]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/tools/common/OpenFileDialog.cpp
hello world
[icculus/iodoom3.git] / neo / tools / common / OpenFileDialog.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "../../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "../../sys/win32/win_local.h"
33 #include "../../sys/win32/rc/common_resource.h"
34 #include "OpenFileDialog.h"
35
36 char rvOpenFileDialog::mLookin[ MAX_OSPATH ];
37
38 /*
39 ================
40 rvOpenFileDialog::rvOpenFileDialog
41
42 constructor
43 ================
44 */
45 rvOpenFileDialog::rvOpenFileDialog( void )
46 {
47         mWnd            = NULL;
48         mInstance       = NULL;
49         mBackBitmap = NULL;
50         mImageList      = NULL;
51         mFlags          = 0;
52 }
53
54 /*
55 ================
56 rvOpenFileDialog::~rvOpenFileDialog
57
58 destructor
59 ================
60 */
61 rvOpenFileDialog::~rvOpenFileDialog ( void )
62 {
63         if ( mImageList )
64         {
65                 ImageList_Destroy ( mImageList );
66         }
67
68         if ( mBackBitmap )
69         {
70                 DeleteObject ( mBackBitmap );
71         }
72 }
73
74 /*
75 ================
76 rvOpenFileDialog::DoModal
77
78 Opens the dialog and returns true if a filename was found
79 ================
80 */
81 bool rvOpenFileDialog::DoModal ( HWND parent )
82 {
83         mInstance = win32.hInstance;
84
85         INITCOMMONCONTROLSEX ex;
86         ex.dwICC = ICC_USEREX_CLASSES | ICC_LISTVIEW_CLASSES;
87         ex.dwSize = sizeof(INITCOMMONCONTROLSEX);
88
89         InitCommonControlsEx ( &ex );
90
91         return DialogBoxParam ( mInstance, MAKEINTRESOURCE(IDD_TOOLS_OPEN), parent, DlgProc, (LPARAM)this ) ? true : false;
92 }
93
94 /*
95 ================
96 rvOpenFileDialog::UpdateLookIn
97
98 Updates the lookin combo box with the current lookin state
99 ================
100 */
101 void rvOpenFileDialog::UpdateLookIn ( void )
102 {
103         COMBOBOXEXITEM  item;
104         idStr                   file;
105         idStr                   path;
106
107         // Reset the combo box
108         SendMessage ( mWndLookin, CB_RESETCONTENT, 0, 0 );
109         
110         // Setup the common item structure components
111         ZeroMemory ( &item, sizeof(item) );
112         item.mask = CBEIF_TEXT | CBEIF_INDENT | CBEIF_IMAGE | CBEIF_SELECTEDIMAGE;
113
114         // Add the top left folder
115         item.pszText = (LPSTR)"base";
116         SendMessage ( mWndLookin, CBEM_INSERTITEM, 0, (LPARAM)&item );
117
118         // Break the lookin path up into its individual components and add them
119         // to the combo box
120         path = mLookin;
121
122         while ( path.Length ( ) )
123         {
124                 int slash = path.Find ( "/" );
125                 
126                 // Parse out the next subfolder
127                 if ( slash != -1 )
128                 {
129                         file = path.Left ( slash );
130                         path = path.Right ( path.Length ( ) - slash - 1 );
131                 }
132                 else
133                 {
134                         file = path;
135                         path.Empty ( );
136                 }
137
138                 // Add the sub folder                           
139                 item.pszText = (LPSTR)file.c_str();
140                 item.iIndent++;
141                 item.iItem = item.iIndent;
142                 SendMessage ( mWndLookin, CBEM_INSERTITEM, 0, (LPARAM)&item );          
143         }
144         
145         // Set the selection to the last one since thats the deepest folder
146         SendMessage ( mWndLookin, CB_SETCURSEL, item.iIndent, 0 );
147 }
148
149 /*
150 ================
151 rvOpenFileDialog::UpdateFileList
152
153 Updates the file list with the files that match the filter in the current
154 look in directory
155 ================
156 */
157 void rvOpenFileDialog::UpdateFileList ( void )
158 {
159         const char *basepath = mLookin;
160         idFileList *files;
161         HWND            list = GetDlgItem ( mWnd, IDC_TOOLS_FILELIST );
162         int                     i;
163         int                     filter;
164                 
165         ListView_DeleteAllItems ( list );
166         
167         // Add all the folders first
168         files = fileSystem->ListFiles ( basepath, "/", true );
169         for ( i = 0; i < files->GetNumFiles(); i ++ )
170         {
171                 if ( files->GetFile( i )[0] == '.' )
172                 {
173                         continue;
174                 }
175         
176                 LVITEM item;
177                 item.mask = LVIF_TEXT;
178                 item.iItem = ListView_GetItemCount ( list );
179                 item.pszText = (LPSTR)files->GetFile( i );
180                 item.iSubItem = 0;
181                 ListView_InsertItem ( list, &item );
182         }
183         fileSystem->FreeFileList( files );
184         
185         // Add all the files in the current lookin directory that match the
186         // current filters.
187         for ( filter = 0; filter < mFilters.Num(); filter ++ )
188         {       
189                 files = fileSystem->ListFiles( basepath, mFilters[filter], true );
190                 for ( i = 0; i < files->GetNumFiles(); i ++ )
191                 {
192                         if ( files->GetFile( i )[0] == '.' )
193                         {
194                                 continue;
195                         }
196         
197                         LVITEM item;
198                         item.mask = LVIF_TEXT|LVIF_IMAGE;
199                         item.iImage = 2;
200                         item.iItem = ListView_GetItemCount( list );
201                         item.pszText = (LPSTR)files->GetFile( i );
202                         item.iSubItem = 0;
203                         ListView_InsertItem ( list, &item );
204                 }
205                 fileSystem->FreeFileList( files );
206         }
207 }
208
209 /*
210 ================
211 rvOpenFileDialog::HandleCommandOK
212
213 Handles the pressing of the OK button but either opening a selected folder
214 or closing the dialog with the resulting filename
215 ================
216 */
217 void rvOpenFileDialog::HandleCommandOK ( void )
218 {
219         char    temp[256];
220         LVITEM  item;
221
222         // If nothing is selected then there is nothing to open
223         int sel = ListView_GetNextItem ( mWndFileList, -1, LVNI_SELECTED );
224         if ( sel == -1 )
225         {
226                 GetWindowText ( GetDlgItem ( mWnd, IDC_TOOLS_FILENAME ), temp, sizeof(temp)-1 );
227                 if ( !temp[0] )
228                 {
229                         return;
230                 }
231                 
232                 item.iImage = 2;
233         }
234         else
235         {
236                 // Get the currently selected item
237                 item.mask = LVIF_IMAGE|LVIF_TEXT;
238                 item.iImage = sel;
239                 item.iSubItem = 0;
240                 item.pszText = temp;
241                 item.cchTextMax = 256;
242                 item.iItem = sel;
243                 ListView_GetItem ( mWndFileList, &item );
244         }
245         
246         // If the item is a folder then just open that folder
247         if ( item.iImage == 0 )
248         {
249                 if ( strlen( mLookin ) )
250                 {
251                         idStr::snPrintf( mLookin, sizeof( mLookin ), "%s/%s", mLookin, temp );
252                 } else {
253                         idStr::Copynz( mLookin, temp, sizeof( mLookin ) );
254                 }
255                 UpdateLookIn ( );
256                 UpdateFileList ( );                                                                     
257         }
258         // If the item is a file then build the filename and end the dialog
259         else if ( item.iImage == 2 )
260         {
261                 mFilename = mLookin;
262                 if ( mFilename.Length ( ) )
263                 {
264                         mFilename.Append ( "/" );
265                 }
266                 mFilename.Append ( temp );
267                 
268                 // Make sure the file exists
269                 if ( mFlags & OFD_MUSTEXIST )
270                 {
271                         idFile* file;                           
272                         file = fileSystem->OpenFileRead ( mFilename );
273                         if ( !file )
274                         {
275                                 MessageBox ( mWnd, va("%s\nFile not found.\nPlease verify the correct file name was given", mFilename.c_str() ), "Open", MB_ICONERROR|MB_OK );
276                                 return;
277                         }
278                         fileSystem->CloseFile ( file );
279                 }
280                                 
281                 EndDialog ( mWnd, 1 );
282         }               
283         
284         return;
285 }
286
287 /*
288 ================
289 rvOpenFileDialog::HandleInitDialog
290
291 Handles the init dialog message
292 ================
293 */
294 void rvOpenFileDialog::HandleInitDialog ( void )
295 {
296         // Cache the more used window handles
297         mWndFileList = GetDlgItem ( mWnd, IDC_TOOLS_FILELIST );
298         mWndLookin   = GetDlgItem ( mWnd, IDC_TOOLS_LOOKIN );
299
300         // Load the custom resources used by the controls
301         mImageList  = ImageList_LoadBitmap ( mInstance, MAKEINTRESOURCE(IDB_TOOLS_OPEN),16,1,RGB(255,255,255) );
302         mBackBitmap = (HBITMAP)LoadImage ( mInstance, MAKEINTRESOURCE(IDB_TOOLS_BACK), IMAGE_BITMAP, 16, 16, LR_DEFAULTCOLOR|LR_LOADMAP3DCOLORS );
303
304         // Attach the image list to the file list and lookin controls           
305         ListView_SetImageList ( mWndFileList, mImageList, LVSIL_SMALL );
306         SendMessage( mWndLookin,CBEM_SETIMAGELIST,0,(LPARAM) mImageList );
307         
308         // Back button is a bitmap button
309         SendMessage( GetDlgItem ( mWnd, IDC_TOOLS_BACK ), BM_SETIMAGE, IMAGE_BITMAP, (LONG) mBackBitmap );
310         
311         // Allow custom titles
312         SetWindowText ( mWnd, mTitle );
313         
314         // Custom ok button title
315         if ( mOKTitle.Length ( ) )
316         {
317                 SetWindowText ( GetDlgItem ( mWnd, IDOK ), mOKTitle );
318         }
319
320         // See if there is a filename in the lookin
321         idStr temp;
322         idStr filename = mLookin;
323         filename.ExtractFileExtension ( temp );
324         if ( temp.Length ( ) )
325         {
326                 filename.ExtractFileName ( temp );
327                 SetWindowText ( GetDlgItem ( mWnd, IDC_TOOLS_FILENAME ), temp );
328                 filename.StripFilename ( );
329                 idStr::snPrintf( mLookin, sizeof( mLookin ), "%s", filename.c_str() );
330         }
331
332         // Update our controls
333         UpdateLookIn ( );
334         UpdateFileList ( );
335 }
336
337 /*
338 ================
339 rvOpenFileDialog::HandleLookInChange
340
341 Handles a selection change within the lookin control
342 ================
343 */
344 void rvOpenFileDialog::HandleLookInChange ( void )
345 {
346         char    temp[256];
347         int             sel;                                            
348         int             i;
349         idStr   lookin;
350         
351         temp[0] = 0;
352         
353         sel = SendMessage ( mWndLookin, CB_GETCURSEL, 0, 0 );
354         
355         // If something other than base is selected then walk up the list
356         // and build the new lookin path
357         if ( sel >= 1 )
358         {
359                 SendMessage ( mWndLookin, CB_GETLBTEXT, 1, (LPARAM)temp );
360                 idStr::snPrintf( mLookin, sizeof( mLookin ), "%s", temp );
361                 for ( i = 2; i <= sel; i ++ )
362                 {
363                         SendMessage ( mWndLookin, CB_GETLBTEXT, i, (LPARAM)temp );
364                         idStr::snPrintf( mLookin, sizeof( mLookin ), "%s/%s", mLookin, temp );
365                 }                       
366         }
367         else
368         {
369                 mLookin[0] = 0;
370         }       
371
372         // Update the controls with the new lookin path
373         UpdateLookIn ( );                                                                       
374         UpdateFileList ( );     
375 }
376
377 /*
378 ================
379 rvOpenFileDialog::SetFilter
380
381 Set the extensions available in the dialog
382 ================
383 */
384 void rvOpenFileDialog::SetFilter ( const char* s )
385 {
386         idStr filters = s;
387         idStr filter;
388         
389         while ( filters.Length ( ) )
390         {
391                 int semi = filters.Find ( ';' );
392                 if ( semi != -1 )
393                 {
394                         filter  = filters.Left ( semi );
395                         filters = filters.Right ( filters.Length ( ) - semi );
396                 }
397                 else
398                 {
399                         filter = filters;
400                         filters.Empty ( );
401                 }
402                 
403                 mFilters.Append ( filter.c_str() + (filter[0] == '*' ? 1 : 0) );
404         }
405 }
406
407 /*
408 ================
409 rvOpenFileDialog::DlgProc
410
411 Dialog Procedure for the open file dialog
412 ================
413 */
414 INT_PTR rvOpenFileDialog::DlgProc ( HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam )
415 {
416         rvOpenFileDialog* dlg = (rvOpenFileDialog*) GetWindowLong ( wnd, GWL_USERDATA );
417         
418         switch ( msg )
419         {
420                 case WM_INITDIALOG:                     
421                         dlg = (rvOpenFileDialog*) lparam;
422                         SetWindowLong ( wnd, GWL_USERDATA, lparam );
423                         dlg->mWnd = wnd;
424                         dlg->HandleInitDialog ( );
425                         return TRUE;
426
427                 case WM_NOTIFY:
428                 {
429                         NMHDR* nm = (NMHDR*) lparam;
430                         switch ( nm->idFrom )
431                         {
432                                 case IDC_TOOLS_FILELIST:
433                                         switch ( nm->code )
434                                         {
435                                                 case LVN_ITEMCHANGED:
436                                                 {
437                                                         NMLISTVIEW* nmlv = (NMLISTVIEW*)nm;
438                                                         if ( nmlv->uNewState & LVIS_SELECTED )
439                                                         {       
440                                                                 // Get the currently selected item
441                                                                 LVITEM item;
442                                                                 char   temp[256];
443                                                                 item.mask = LVIF_IMAGE|LVIF_TEXT;
444                                                                 item.iSubItem = 0;
445                                                                 item.pszText = temp;
446                                                                 item.cchTextMax = sizeof(temp)-1;
447                                                                 item.iItem = nmlv->iItem;
448                                                                 ListView_GetItem ( dlg->mWndFileList, &item );                          
449                                                                 
450                                                                 if ( item.iImage == 2 )
451                                                                 {
452                                                                         SetWindowText ( GetDlgItem ( wnd, IDC_TOOLS_FILENAME ), temp );
453                                                                 }
454                                                         }
455                                                         break;
456                                                 }
457                                                 
458                                                 case NM_DBLCLK:
459                                                         dlg->HandleCommandOK ( );
460                                                         break;
461                                         }
462                                         break;
463                         }
464                         break;
465                 }
466                         
467                 case WM_COMMAND:
468                         switch ( LOWORD ( wparam ) )
469                         {
470                                 case IDOK:
471                                 {
472                                         dlg->HandleCommandOK ( );
473                                         break;
474                                 }
475                                 
476                                 case IDCANCEL:
477                                         EndDialog ( wnd, 0 );
478                                         break;
479                                         
480                                 case IDC_TOOLS_BACK:
481                                 {
482                                         int sel = SendMessage ( GetDlgItem ( wnd, IDC_TOOLS_LOOKIN ), CB_GETCURSEL, 0, 0 );
483                                         if ( sel > 0 )
484                                         {
485                                                 sel--;
486                                                 SendMessage ( GetDlgItem ( wnd, IDC_TOOLS_LOOKIN ), CB_SETCURSEL, sel, 0 );
487                                                 dlg->HandleLookInChange ( );
488                                         }
489                                         
490                                         break;
491                                 }
492                                         
493                                 case IDC_TOOLS_LOOKIN:
494                                         if ( HIWORD ( wparam ) == CBN_SELCHANGE )
495                                         {
496                                                 dlg->HandleLookInChange ( );                                                            
497                                         }
498                                         break;
499                         }
500                         break;
501         }
502         
503         return FALSE;
504 }