winecfg: Fix an error in the Chinese (Traditional) translation.
[wine] / programs / winecfg / driveui.c
1 /*
2  * Drive management UI code
3  *
4  * Copyright 2003 Mark Westcott
5  * Copyright 2004 Chris Morgan
6  * Copyright 2003-2004 Mike Hearn
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  *
22  */
23
24 #include <stdio.h>
25
26 #define WIN32_LEAN_AND_MEAN
27 #define COBJMACROS
28
29 #include <windows.h>
30 #include <shellapi.h>
31 #include <objbase.h>
32 #include <shlguid.h>
33 #include <shlwapi.h>
34 #include <shlobj.h>
35
36 #include <wine/unicode.h>
37 #include <wine/debug.h>
38
39 #include "winecfg.h"
40 #include "resource.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(winecfg);
43
44 #define BOX_MODE_DEVICE 1
45 #define BOX_MODE_NORMAL 2
46
47 static BOOL advanced = FALSE;
48 static BOOL updating_ui = FALSE;
49 static struct drive* current_drive;
50
51 static void update_controls(HWND dialog);
52
53 static DWORD driveui_msgbox (HWND parent, UINT messageId, DWORD flags)
54 {
55   WCHAR* caption = load_string (IDS_WINECFG_TITLE);
56   WCHAR* text = load_string (messageId);
57   DWORD result = MessageBoxW (parent, text, caption, flags);
58   HeapFree (GetProcessHeap(), 0, caption);
59   HeapFree (GetProcessHeap(), 0, text);
60   return result;
61 }
62
63 /**** listview helper functions ****/
64
65 /* clears the item at index in the listview */
66 static void lv_clear_curr_select(HWND dialog, int index)
67 {
68     ListView_SetItemState(GetDlgItem(dialog, IDC_LIST_DRIVES), index, 0, LVIS_SELECTED);
69 }
70
71 /* selects the item at index in the listview */
72 static void lv_set_curr_select(HWND dialog, int index)
73 {
74     /* no more than one item can be selected in our listview */
75     lv_clear_curr_select(dialog, -1);
76     ListView_SetItemState(GetDlgItem(dialog, IDC_LIST_DRIVES), index, LVIS_SELECTED, LVIS_SELECTED);
77 }
78
79 /* returns the currently selected item in the listview */
80 static int lv_get_curr_select(HWND dialog)
81 {
82     return SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LVM_GETNEXTITEM, -1, LVNI_SELECTED);
83 }
84
85 /* sets the item in the listview at item->iIndex */
86 static void lv_set_item(HWND dialog, LVITEMW *item)
87 {
88     SendDlgItemMessageW(dialog, IDC_LIST_DRIVES, LVM_SETITEMW, 0, (LPARAM) item);
89 }
90
91 /* sets specified item's text */
92 static void lv_set_item_text(HWND dialog, int item, int subItem, WCHAR *text)
93 {
94     LVITEMW lvItem;
95     if (item < 0 || subItem < 0) return;
96     lvItem.mask = LVIF_TEXT;
97     lvItem.iItem = item;
98     lvItem.iSubItem = subItem;
99     lvItem.pszText = text;
100     lvItem.cchTextMax = lstrlenW(lvItem.pszText);
101     lv_set_item(dialog, &lvItem);
102 }
103
104 /* inserts an item into the listview */
105 static void lv_insert_item(HWND dialog, LVITEMW *item)
106 {
107     SendDlgItemMessageW(dialog, IDC_LIST_DRIVES, LVM_INSERTITEMW, 0, (LPARAM) item);
108 }
109
110 /* retrieve the item at index item->iIndex */
111 static void lv_get_item(HWND dialog, LVITEMW *item)
112 {
113     SendDlgItemMessageW(dialog, IDC_LIST_DRIVES, LVM_GETITEMW, 0, (LPARAM) item);
114 }
115
116 static void set_advanced(HWND dialog)
117 {
118     int state;
119     WCHAR text[256];
120
121     if (advanced)
122     {
123         state = SW_NORMAL;
124         LoadStringW(GetModuleHandle(NULL), IDS_HIDE_ADVANCED, text, 256);
125     }
126     else
127     {
128         state = SW_HIDE;
129         LoadStringW(GetModuleHandle(NULL), IDS_SHOW_ADVANCED, text, 256);
130     }
131
132     ShowWindow(GetDlgItem(dialog, IDC_EDIT_DEVICE), state);
133     ShowWindow(GetDlgItem(dialog, IDC_STATIC_DEVICE), state);
134     ShowWindow(GetDlgItem(dialog, IDC_EDIT_LABEL), state);
135     ShowWindow(GetDlgItem(dialog, IDC_STATIC_LABEL), state);
136     ShowWindow(GetDlgItem(dialog, IDC_BUTTON_BROWSE_DEVICE), state);
137     ShowWindow(GetDlgItem(dialog, IDC_EDIT_SERIAL), state);
138     ShowWindow(GetDlgItem(dialog, IDC_STATIC_SERIAL), state);
139     ShowWindow(GetDlgItem(dialog, IDC_COMBO_TYPE), state);
140     ShowWindow(GetDlgItem(dialog, IDC_STATIC_TYPE), state);
141
142     /* update the button text based on the state */
143     SetWindowTextW(GetDlgItem(dialog, IDC_BUTTON_SHOW_HIDE_ADVANCED), text);
144 }
145
146 struct drive_typemap {
147     unsigned int sCode;
148     UINT idDesc;
149 };
150
151 static const struct drive_typemap type_pairs[] = {
152   { DRIVE_UNKNOWN,    IDS_DRIVE_UNKNOWN   },
153   { DRIVE_FIXED,      IDS_DRIVE_FIXED     },
154   { DRIVE_REMOTE,     IDS_DRIVE_REMOTE    },
155   { DRIVE_REMOVABLE,  IDS_DRIVE_REMOVABLE },
156   { DRIVE_CDROM,      IDS_DRIVE_CDROM     }
157 };
158
159 #define DRIVE_TYPE_DEFAULT 0
160
161 static void enable_labelserial_box(HWND dialog, int mode)
162 {
163     WINE_TRACE("mode=%d\n", mode);
164
165     switch (mode)
166     {
167         case BOX_MODE_DEVICE:
168             /* FIXME: enable device editing */
169             disable(IDC_EDIT_DEVICE);
170             disable(IDC_BUTTON_BROWSE_DEVICE);
171             disable(IDC_EDIT_SERIAL);
172             disable(IDC_EDIT_LABEL);
173             break;
174
175         case BOX_MODE_NORMAL:
176             disable(IDC_EDIT_DEVICE);
177             disable(IDC_BUTTON_BROWSE_DEVICE);
178             enable(IDC_EDIT_SERIAL);
179             enable(IDC_EDIT_LABEL);
180             break;
181     }
182 }
183
184 static int fill_drives_list(HWND dialog)
185 {
186     int count = 0;
187     BOOL drivec_present = FALSE;
188     int i;
189     int prevsel = -1;
190
191     WINE_TRACE("\n");
192
193     updating_ui = TRUE;
194
195     prevsel = lv_get_curr_select(dialog); 
196
197     /* Clear the listbox */
198     SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LVM_DELETEALLITEMS, 0, 0);
199
200     for(i = 0; i < 26; i++)
201     {
202         LVITEMW item;
203         WCHAR *path;
204         char letter[4];
205
206         /* skip over any unused drives */
207         if (!drives[i].in_use)
208             continue;
209
210         if (drives[i].letter == 'C')
211             drivec_present = TRUE;
212
213         letter[0] = 'A' + i;
214         letter[1] = ':';
215         letter[2] = 0;
216
217         item.mask = LVIF_TEXT | LVIF_PARAM;
218         item.iItem = count;
219         item.iSubItem = 0;
220         item.pszText = strdupU2W(letter);
221         item.cchTextMax = lstrlenW(item.pszText);
222         item.lParam = (LPARAM) &drives[i];
223
224         lv_insert_item(dialog, &item);
225         HeapFree(GetProcessHeap(), 0, item.pszText);
226
227         path = strdupU2W(drives[i].unixpath);
228         lv_set_item_text(dialog, count, 1, path);
229         HeapFree(GetProcessHeap(), 0, path);
230
231         count++;
232     }
233
234     WINE_TRACE("loaded %d drives\n", count);
235
236     /* show the warning if there is no Drive C */
237     if (!drivec_present)
238         ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_NORMAL);
239     else
240         ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_HIDE);
241
242     lv_set_curr_select(dialog, prevsel == -1 ? 0 : prevsel);
243
244     updating_ui = FALSE;
245     return count;
246 }
247
248 static void on_options_click(HWND dialog)
249 {
250     if (IsDlgButtonChecked(dialog, IDC_SHOW_DOT_FILES) == BST_CHECKED)
251         set_reg_key(config_key, "", "ShowDotFiles", "Y");
252     else
253         set_reg_key(config_key, "", "ShowDotFiles", "N");
254
255     SendMessage(GetParent(dialog), PSM_CHANGED, 0, 0);
256 }
257
258 static INT_PTR CALLBACK drivechoose_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
259 {
260     static int i, sel;
261     char c;
262     char drive[] = "X:";
263
264     switch(uMsg)
265     {
266     case WM_INITDIALOG:
267         {
268         ULONG mask = ~drive_available_mask(0); /* the mask is now which drives aren't available */
269         for( c = 'A'; c<= 'Z'; c++){
270             drive[0] = c;
271             if(!( mask & (1 << (c - 'A'))))
272                 SendDlgItemMessageA( hwndDlg, IDC_DRIVESA2Z, CB_ADDSTRING, 0, (LPARAM) drive);
273         }
274         drive[0] = lParam;
275         SendDlgItemMessageA( hwndDlg, IDC_DRIVESA2Z, CB_SELECTSTRING, 0, (LPARAM) drive);
276         return TRUE;
277         }
278     case WM_COMMAND:
279         if(HIWORD(wParam) != BN_CLICKED) break;
280         switch (LOWORD(wParam))
281         {
282         case IDOK:
283             i = SendDlgItemMessageA( hwndDlg, IDC_DRIVESA2Z, CB_GETCURSEL, 0, 0);
284             if( i != CB_ERR){
285                 SendDlgItemMessageA( hwndDlg, IDC_DRIVESA2Z, CB_GETLBTEXT, i, (LPARAM) drive);
286                 sel = drive[0];
287             } else
288                 sel = -1;
289             EndDialog(hwndDlg, sel);
290             return TRUE;
291         case IDCANCEL:
292             EndDialog(hwndDlg, -1);
293             return TRUE;
294         }
295     }
296     return FALSE;
297 }
298
299 static void on_add_click(HWND dialog)
300 {
301     /* we should allocate a drive letter automatically. We also need
302        some way to let the user choose the mapping point, for now we
303        will just force them to enter a path automatically, with / being
304        the default. In future we should be able to temporarily map /
305        then invoke the directory chooser dialog. */
306
307     char new = 'C'; /* we skip A and B, they are historically floppy drives */
308     ULONG mask = ~drive_available_mask(0); /* the mask is now which drives aren't available */
309     int i, c;
310
311     while (mask & (1 << (new - 'A')))
312     {
313         new++;
314         if (new > 'Z')
315         {
316             driveui_msgbox (dialog, IDS_DRIVE_LETTERS_EXCEEDED, MB_OK | MB_ICONEXCLAMATION);
317             return;
318         }
319     }
320
321
322     new = DialogBoxParam(0, MAKEINTRESOURCE(IDD_DRIVECHOOSE), dialog, drivechoose_dlgproc, new);
323
324     if( new == -1) return;
325
326     WINE_TRACE("selected drive letter %c\n", new);
327
328     if (new == 'C')
329     {
330         WCHAR label[64];
331         LoadStringW (GetModuleHandle (NULL), IDS_SYSTEM_DRIVE_LABEL, label,
332                      sizeof(label)/sizeof(label[0]));
333         add_drive(new, "../drive_c", NULL, label, 0, DRIVE_FIXED);
334     }
335     else add_drive(new, "/", NULL, NULL, 0, DRIVE_UNKNOWN);
336
337     fill_drives_list(dialog);
338
339     /* select the newly created drive */
340     mask = ~drive_available_mask(0);
341     c = 0;
342     for (i = 0; i < 26; i++)
343     {
344         if ('A' + i == new) break;
345         if ((1 << i) & mask) c++;
346     }
347     lv_set_curr_select(dialog, c);
348
349     SetFocus(GetDlgItem(dialog, IDC_LIST_DRIVES));
350
351     update_controls(dialog);
352     SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
353 }
354
355 static void on_remove_click(HWND dialog)
356 {
357     int itemIndex;
358     struct drive *drive;
359     LVITEMW item;
360
361     itemIndex = lv_get_curr_select(dialog);
362     if (itemIndex == -1) return; /* no selection */
363
364     item.mask = LVIF_PARAM;
365     item.iItem = itemIndex;
366     item.iSubItem = 0;
367
368     lv_get_item(dialog, &item);
369
370     drive = (struct drive *) item.lParam;
371
372     WINE_TRACE("unixpath: %s\n", drive->unixpath);
373
374     if (drive->letter == 'C')
375     {
376         DWORD result = driveui_msgbox (dialog, IDS_CONFIRM_DELETE_C, MB_YESNO | MB_ICONEXCLAMATION);
377         if (result == IDNO) return;
378     }
379
380     delete_drive(drive);
381
382     fill_drives_list(dialog);
383
384     itemIndex = itemIndex - 1;
385     if (itemIndex < 0) itemIndex = 0;
386     lv_set_curr_select(dialog, itemIndex);   /* previous item */
387
388     SetFocus(GetDlgItem(dialog, IDC_LIST_DRIVES));
389
390     update_controls(dialog);
391     SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
392 }
393
394 static void update_controls(HWND dialog)
395 {
396     static const WCHAR emptyW[1];
397     WCHAR *path;
398     unsigned int type;
399     char serial[16];
400     int i, selection = -1;
401     LVITEMW item;
402
403     updating_ui = TRUE;
404
405     i = lv_get_curr_select(dialog);
406     if (i == -1)
407     {
408         /* no selection? let's select something for the user. this will re-enter */
409         lv_set_curr_select(dialog, i);
410         return;
411     }
412
413     item.mask = LVIF_PARAM;
414     item.iItem = i;
415     item.iSubItem = 0;
416
417     lv_get_item(dialog, &item);
418     current_drive = (struct drive *) item.lParam;
419
420     WINE_TRACE("Updating sheet for drive %c\n", current_drive->letter);
421
422     /* path */
423     WINE_TRACE("set path control text to '%s'\n", current_drive->unixpath);
424     path = strdupU2W(current_drive->unixpath);
425     set_textW(dialog, IDC_EDIT_PATH, path);
426     HeapFree(GetProcessHeap(), 0, path);
427
428     /* drive type */
429     type = current_drive->type;
430     SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_RESETCONTENT, 0, 0);
431
432     for (i = 0; i < sizeof(type_pairs) / sizeof(struct drive_typemap); i++)
433     {
434         WCHAR driveDesc[64];
435         LoadStringW (GetModuleHandle (NULL), type_pairs[i].idDesc, driveDesc,
436             sizeof(driveDesc)/sizeof(driveDesc[0]));
437         SendDlgItemMessageW (dialog, IDC_COMBO_TYPE, CB_ADDSTRING, 0, (LPARAM)driveDesc);
438
439         if (type_pairs[i].sCode ==  type)
440         {
441             selection = i;
442         }
443     }
444
445     if (selection == -1) selection = DRIVE_TYPE_DEFAULT;
446     SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_SETCURSEL, selection, 0);
447
448     EnableWindow( GetDlgItem( dialog, IDC_BUTTON_REMOVE ), (current_drive->letter != 'C') );
449     EnableWindow( GetDlgItem( dialog, IDC_EDIT_PATH ), (current_drive->letter != 'C') );
450     EnableWindow( GetDlgItem( dialog, IDC_BUTTON_BROWSE_PATH ), (current_drive->letter != 'C') );
451     EnableWindow( GetDlgItem( dialog, IDC_COMBO_TYPE ), (current_drive->letter != 'C') );
452
453     /* removeable media properties */
454     set_textW(dialog, IDC_EDIT_LABEL, current_drive->label ? current_drive->label : emptyW);
455
456     /* set serial edit text */
457     sprintf( serial, "%X", current_drive->serial );
458     set_text(dialog, IDC_EDIT_SERIAL, serial);
459
460     set_text(dialog, IDC_EDIT_DEVICE, current_drive->device);
461
462     if ((type == DRIVE_CDROM) || (type == DRIVE_REMOVABLE))
463         enable_labelserial_box(dialog, BOX_MODE_DEVICE);
464     else
465         enable_labelserial_box(dialog, BOX_MODE_NORMAL);
466
467     updating_ui = FALSE;
468
469     return;
470 }
471
472 static void on_edit_changed(HWND dialog, WORD id)
473 {
474     if (updating_ui) return;
475
476     WINE_TRACE("edit id %d changed\n", id);
477
478     switch (id)
479     {
480         case IDC_EDIT_LABEL:
481         {
482             WCHAR *label = get_textW(dialog, id);
483             HeapFree(GetProcessHeap(), 0, current_drive->label);
484             current_drive->label = label;
485             current_drive->modified = TRUE;
486
487             WINE_TRACE("set label to %s\n", wine_dbgstr_w(current_drive->label));
488
489             /* enable the apply button  */
490             SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
491             break;
492         }
493
494         case IDC_EDIT_PATH:
495         {
496             WCHAR *wpath;
497             char *path;
498             int lenW;
499
500             wpath = get_textW(dialog, id);
501             if( (lenW = WideCharToMultiByte(CP_UNIXCP, 0, wpath, -1, NULL, 0, NULL, NULL)) )
502             {
503                 path = HeapAlloc(GetProcessHeap(), 0, lenW);
504                 WideCharToMultiByte(CP_UNIXCP, 0, wpath, -1, path, lenW, NULL, NULL);
505             }
506             else
507             {
508                 path = NULL;
509                 wpath = strdupU2W("drive_c");
510             }
511
512             HeapFree(GetProcessHeap(), 0, current_drive->unixpath);
513             current_drive->unixpath = path ? path : strdupA("drive_c");
514             current_drive->modified = TRUE;
515
516             WINE_TRACE("set path to %s\n", current_drive->unixpath);
517
518             lv_set_item_text(dialog, lv_get_curr_select(dialog), 1,
519                              wpath);
520             HeapFree(GetProcessHeap(), 0, wpath);
521
522             /* enable the apply button  */
523             SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
524             break;
525         }
526
527         case IDC_EDIT_SERIAL:
528         {
529             char *serial;
530
531             serial = get_text(dialog, id);
532             current_drive->serial = serial ? strtoul( serial, NULL, 16 ) : 0;
533             HeapFree(GetProcessHeap(), 0, serial);
534             current_drive->modified = TRUE;
535
536             WINE_TRACE("set serial to %08X\n", current_drive->serial);
537
538             /* enable the apply button  */
539             SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
540             break;
541         }
542
543         case IDC_EDIT_DEVICE:
544         {
545             char *device = get_text(dialog, id);
546             /* TODO: handle device if/when it makes sense to do so.... */
547             HeapFree(GetProcessHeap(), 0, device);
548             break;
549         }
550     }
551 }
552
553 BOOL browse_for_unix_folder(HWND dialog, WCHAR *pszPath)
554 {
555     static WCHAR wszUnixRootDisplayName[] = 
556         { ':',':','{','C','C','7','0','2','E','B','2','-','7','D','C','5','-','1','1','D','9','-',
557           'C','6','8','7','-','0','0','0','4','2','3','8','A','0','1','C','D','}', 0 };
558     WCHAR pszChoosePath[FILENAME_MAX];
559     BROWSEINFOW bi = {
560         dialog,
561         NULL,
562         NULL,
563         pszChoosePath,
564         0,
565         NULL,
566         0,
567         0
568     };
569     IShellFolder *pDesktop;
570     LPITEMIDLIST pidlUnixRoot, pidlSelectedPath;
571     HRESULT hr;
572    
573     LoadStringW(GetModuleHandle(NULL), IDS_CHOOSE_PATH, pszChoosePath, FILENAME_MAX);
574     
575     hr = SHGetDesktopFolder(&pDesktop);
576     if (FAILED(hr)) return FALSE;
577
578     hr = IShellFolder_ParseDisplayName(pDesktop, NULL, NULL, wszUnixRootDisplayName, NULL, 
579                                        &pidlUnixRoot, NULL);
580     if (FAILED(hr)) {
581         IShellFolder_Release(pDesktop);
582         return FALSE;
583     }
584
585     bi.pidlRoot = pidlUnixRoot;
586     pidlSelectedPath = SHBrowseForFolderW(&bi);
587     SHFree(pidlUnixRoot);
588     
589     if (pidlSelectedPath) {
590         STRRET strSelectedPath;
591         WCHAR *pszSelectedPath;
592         HRESULT hr;
593         
594         hr = IShellFolder_GetDisplayNameOf(pDesktop, pidlSelectedPath, SHGDN_FORPARSING, 
595                                            &strSelectedPath);
596         IShellFolder_Release(pDesktop);
597         if (FAILED(hr)) {
598             SHFree(pidlSelectedPath);
599             return FALSE;
600         }
601
602         hr = StrRetToStrW(&strSelectedPath, pidlSelectedPath, &pszSelectedPath);
603         SHFree(pidlSelectedPath);
604         if (FAILED(hr)) return FALSE;
605
606         lstrcpyW(pszPath, pszSelectedPath);
607         
608         CoTaskMemFree(pszSelectedPath);
609         return TRUE;
610     }
611     return FALSE;
612 }
613
614 static void init_listview_columns(HWND dialog)
615 {
616     LVCOLUMNW listColumn;
617     RECT viewRect;
618     int width;
619     WCHAR column[64];
620
621     GetClientRect(GetDlgItem(dialog, IDC_LIST_DRIVES), &viewRect);
622     width = (viewRect.right - viewRect.left) / 6 - 5;
623
624     LoadStringW (GetModuleHandle (NULL), IDS_COL_DRIVELETTER, column,
625         sizeof(column)/sizeof(column[0]));
626     listColumn.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
627     listColumn.pszText = column;
628     listColumn.cchTextMax = lstrlenW (listColumn.pszText);
629     listColumn.cx = width;
630
631     SendDlgItemMessageW (dialog, IDC_LIST_DRIVES, LVM_INSERTCOLUMNW, 0, (LPARAM) &listColumn);
632
633     LoadStringW (GetModuleHandle (NULL), IDS_COL_DRIVEMAPPING, column,
634         sizeof(column)/sizeof(column[0]));
635     listColumn.cx = viewRect.right - viewRect.left - width;
636     listColumn.pszText = column;
637     listColumn.cchTextMax = lstrlenW (listColumn.pszText);
638
639     SendDlgItemMessageW (dialog, IDC_LIST_DRIVES, LVM_INSERTCOLUMNW, 1, (LPARAM) &listColumn);
640 }
641
642 static void load_drive_options(HWND dialog)
643 {
644     if (!strcmp(get_reg_key(config_key, "", "ShowDotFiles", "N"), "Y"))
645         CheckDlgButton(dialog, IDC_SHOW_DOT_FILES, BST_CHECKED);
646 }
647
648 INT_PTR CALLBACK
649 DriveDlgProc (HWND dialog, UINT msg, WPARAM wParam, LPARAM lParam)
650 {
651     int item;
652
653     switch (msg)
654     {
655         case WM_INITDIALOG:
656             init_listview_columns(dialog);
657             if (!load_drives())
658             {
659                 ShowWindow( GetDlgItem( dialog, IDC_STATIC_MOUNTMGR_ERROR ), SW_SHOW );
660                 ShowWindow( GetDlgItem( dialog, IDC_LIST_DRIVES ), SW_HIDE );
661                 ShowWindow( GetDlgItem( dialog, IDC_BUTTON_ADD ), SW_HIDE );
662                 ShowWindow( GetDlgItem( dialog, IDC_BUTTON_REMOVE ), SW_HIDE );
663                 ShowWindow( GetDlgItem( dialog, IDC_BUTTON_AUTODETECT ), SW_HIDE );
664                 ShowWindow( GetDlgItem( dialog, IDC_STATIC_PATH ), SW_HIDE );
665                 ShowWindow( GetDlgItem( dialog, IDC_EDIT_PATH ), SW_HIDE );
666                 ShowWindow( GetDlgItem( dialog, IDC_BUTTON_BROWSE_PATH ), SW_HIDE );
667                 ShowWindow( GetDlgItem( dialog, IDC_COMBO_TYPE ), SW_HIDE );
668                 ShowWindow( GetDlgItem( dialog, IDC_BUTTON_SHOW_HIDE_ADVANCED ), SW_HIDE );
669                 set_advanced(dialog);
670                 break;
671             }
672             ShowWindow( GetDlgItem( dialog, IDC_STATIC_MOUNTMGR_ERROR ), SW_HIDE );
673             load_drive_options(dialog);
674
675             if (!drives[2].in_use)
676                 driveui_msgbox (dialog, IDS_NO_DRIVE_C, MB_OK | MB_ICONEXCLAMATION);
677
678             fill_drives_list(dialog);
679             update_controls(dialog);
680             /* put in non-advanced mode by default  */
681             set_advanced(dialog);
682             break;
683
684         case WM_SHOWWINDOW:
685             set_window_title(dialog);
686             break;
687
688         case WM_COMMAND:
689             switch (HIWORD(wParam))
690             {
691                 case EN_CHANGE:
692                     on_edit_changed(dialog, LOWORD(wParam));
693                     break;
694
695                 case BN_CLICKED:
696                     switch (LOWORD(wParam))
697                     {
698                         case IDC_SHOW_DOT_FILES:
699                             on_options_click(dialog);
700                         break;
701                     }
702                     break;
703
704                 case CBN_SELCHANGE:
705                     SendMessage(GetParent(dialog), PSM_CHANGED, 0, 0);
706                     break;
707             }
708
709             switch (LOWORD(wParam))
710             {
711                 case IDC_BUTTON_ADD:
712                     if (HIWORD(wParam) != BN_CLICKED) break;
713                     on_add_click(dialog);
714                     break;
715
716                 case IDC_BUTTON_REMOVE:
717                     if (HIWORD(wParam) != BN_CLICKED) break;
718                     on_remove_click(dialog);
719                     break;
720
721                 case IDC_BUTTON_EDIT:
722                     if (HIWORD(wParam) != BN_CLICKED) break;
723                     item = SendMessage(GetDlgItem(dialog, IDC_LIST_DRIVES),  LB_GETCURSEL, 0, 0);
724                     SendMessage(GetDlgItem(dialog, IDC_LIST_DRIVES), LB_GETITEMDATA, item, 0);
725                     break;
726
727                 case IDC_BUTTON_AUTODETECT:
728                     autodetect_drives();
729                     fill_drives_list(dialog);
730                     SendMessage(GetParent(dialog), PSM_CHANGED, 0, 0);
731                     break;
732
733                 case IDC_BUTTON_SHOW_HIDE_ADVANCED:
734                     advanced = !advanced;
735                     set_advanced(dialog);
736                     break;
737
738                 case IDC_BUTTON_BROWSE_PATH:
739                 {
740                     WCHAR szTargetPath[FILENAME_MAX];
741                     if (browse_for_unix_folder(dialog, szTargetPath)) 
742                         set_textW(dialog, IDC_EDIT_PATH, szTargetPath);
743                     break;
744                 }
745
746                 case IDC_COMBO_TYPE:
747                 {
748                     int mode = BOX_MODE_NORMAL;
749                     int selection;
750
751                     if (HIWORD(wParam) != CBN_SELCHANGE) break;
752
753                     selection = SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_GETCURSEL, 0, 0);
754
755                     if (selection >= 0 &&
756                         (type_pairs[selection].sCode == DRIVE_CDROM ||
757                          type_pairs[selection].sCode == DRIVE_REMOVABLE))
758                         mode = BOX_MODE_DEVICE;
759                     else
760                         mode = BOX_MODE_NORMAL;
761
762                     enable_labelserial_box(dialog, mode);
763
764                     current_drive->type = type_pairs[selection].sCode;
765                     current_drive->modified = TRUE;
766                     break;
767                 }
768
769             }
770             break;
771
772         case WM_NOTIFY:
773             switch (((LPNMHDR)lParam)->code)
774             {
775                 case PSN_KILLACTIVE:
776                     WINE_TRACE("PSN_KILLACTIVE\n");
777                     SetWindowLongPtr(dialog, DWLP_MSGRESULT, FALSE);
778                     break;
779                 case PSN_APPLY:
780                     apply_drive_changes();
781                     SetWindowLongPtr(dialog, DWLP_MSGRESULT, PSNRET_NOERROR);
782                     break;
783                 case PSN_SETACTIVE:
784                     break;
785                 case LVN_ITEMCHANGED:
786                 {
787                     LPNMLISTVIEW lpnm = (LPNMLISTVIEW)lParam;
788                     if (!(lpnm->uOldState & LVIS_SELECTED) &&
789                          (lpnm->uNewState & LVIS_SELECTED))
790                     update_controls(dialog);
791                     break;
792                 }
793             }
794             break;
795     }
796
797     return FALSE;
798 }