Load Show/Hide Advanced strings from resources.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #include <stdarg.h>
25 #include <stdio.h>
26
27 #include <windef.h>
28 #include <winbase.h>
29 #include <winreg.h>
30 #include <shellapi.h>
31 #include <objbase.h>
32 #include <shlguid.h>
33 #include <shlwapi.h>
34 #include <shlobj.h>
35 #include <winuser.h>
36
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_CD_ASSIGN 1
45 #define BOX_MODE_CD_AUTODETECT 2
46 #define BOX_MODE_NONE 3
47 #define BOX_MODE_NORMAL 4
48
49 static BOOL advanced = FALSE;
50 static BOOL updating_ui = FALSE;
51 static struct drive* current_drive;
52
53 static void get_etched_rect(HWND dialog, RECT *rect);
54 static void update_controls(HWND dialog);
55
56 /**** listview helper functions ****/
57
58 /* clears the item at index in the listview */
59 static void lv_clear_curr_select(HWND dialog, int index)
60 {
61     ListView_SetItemState(GetDlgItem(dialog, IDC_LIST_DRIVES), index, 0, LVIS_SELECTED);
62 }
63
64 /* selects the item at index in the listview */
65 static void lv_set_curr_select(HWND dialog, int index)
66 {
67     /* no more than one item can be selected in our listview */
68     lv_clear_curr_select(dialog, -1);
69     ListView_SetItemState(GetDlgItem(dialog, IDC_LIST_DRIVES), index, LVIS_SELECTED, LVIS_SELECTED);
70 }
71
72 /* returns the currently selected item in the listview */
73 static int lv_get_curr_select(HWND dialog)
74 {
75     return SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LVM_GETNEXTITEM, -1, LVNI_SELECTED);
76 }
77
78 /* sets the item in the listview at item->iIndex */
79 static void lv_set_item(HWND dialog, LVITEM *item)
80 {
81     SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LVM_SETITEM, 0, (LPARAM) item);
82 }
83
84 /* inserts an item into the listview */
85 static void lv_insert_item(HWND dialog, LVITEM *item)
86 {
87     SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LVM_INSERTITEM, 0, (LPARAM) item);
88 }
89
90 /* retrieve the item at index item->iIndex */
91 static void lv_get_item(HWND dialog, LVITEM *item)
92 {
93     SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LVM_GETITEM, 0, (LPARAM) item);
94 }
95
96 static void set_advanced(HWND dialog)
97 {
98     int state;
99     char text[256];
100     RECT rect;
101
102     if (advanced)
103     {
104         state = SW_NORMAL;
105         LoadString(GetModuleHandle(NULL), IDS_SHOW_ADVANCED, text, 256);
106     }
107     else
108     {
109         state = SW_HIDE;
110         LoadString(GetModuleHandle(NULL), IDS_HIDE_ADVANCED, text, 256);
111     }
112
113     ShowWindow(GetDlgItem(dialog, IDC_RADIO_AUTODETECT), state);
114     ShowWindow(GetDlgItem(dialog, IDC_RADIO_ASSIGN), state);
115     ShowWindow(GetDlgItem(dialog, IDC_EDIT_LABEL), state);
116     ShowWindow(GetDlgItem(dialog, IDC_EDIT_DEVICE), state);
117     ShowWindow(GetDlgItem(dialog, IDC_STATIC_LABEL), state);
118     ShowWindow(GetDlgItem(dialog, IDC_BUTTON_BROWSE_DEVICE), state);
119     ShowWindow(GetDlgItem(dialog, IDC_EDIT_SERIAL), state);
120     ShowWindow(GetDlgItem(dialog, IDC_STATIC_SERIAL), state);
121     ShowWindow(GetDlgItem(dialog, IDC_LABELSERIAL_STATIC), state);
122
123     /* update the button text based on the state */
124     SetWindowText(GetDlgItem(dialog, IDC_BUTTON_SHOW_HIDE_ADVANCED), text);
125
126     /* redraw for the etched line */
127     get_etched_rect(dialog, &rect);
128     InflateRect(&rect, 5, 5);
129     InvalidateRect(dialog, &rect, TRUE);
130 }
131
132 struct drive_typemap {
133     unsigned int sCode;
134     const char *sDesc;
135 };
136
137 static const struct drive_typemap type_pairs[] = {
138   { DRIVE_FIXED,      "Local hard disk" },
139   { DRIVE_REMOTE,     "Network share"   },
140   { DRIVE_REMOVABLE,  "Floppy disk"     },
141   { DRIVE_CDROM,      "CD-ROM"          }
142 };
143
144 #define DRIVE_TYPE_DEFAULT 1
145
146 void fill_drive_droplist(long mask, char curletter, HWND dialog)
147 {
148     int i;
149     int selection;
150     int count;
151     int next_letter;
152     char sName[4] = "A:";
153
154     for (i = 0, count = 0, selection = -1, next_letter = -1; i <= 'Z'-'A'; ++i)
155     {
156         if (mask & DRIVE_MASK_BIT('A' + i))
157         {
158             int index;
159
160             sName[0] = 'A' + i;
161             index = SendDlgItemMessage(dialog, IDC_COMBO_LETTER, CB_ADDSTRING, 0, (LPARAM) sName);
162
163             if (toupper(curletter) == 'A' + i)
164             {
165                 selection = count;
166             }
167
168             if (i >= 2 && next_letter == -1)
169             {
170                 /* default drive is first one of C-Z */
171                 next_letter = count;
172             }
173
174             count++;
175         }
176     }
177
178     if (selection == -1)
179     {
180         selection = next_letter;
181     }
182
183     SendDlgItemMessage(dialog, IDC_COMBO_LETTER, CB_SETCURSEL, selection, 0);
184 }
185
186
187 void enable_labelserial_box(HWND dialog, int mode)
188 {
189     WINE_TRACE("mode=%d\n", mode);
190
191     switch (mode)
192     {
193         case BOX_MODE_CD_ASSIGN:
194             enable(IDC_RADIO_ASSIGN);
195             disable(IDC_EDIT_DEVICE);
196             disable(IDC_BUTTON_BROWSE_DEVICE);
197             enable(IDC_EDIT_SERIAL);
198             enable(IDC_EDIT_LABEL);
199             enable(IDC_STATIC_SERIAL);
200             enable(IDC_STATIC_LABEL);
201             break;
202
203         case BOX_MODE_CD_AUTODETECT:
204             enable(IDC_RADIO_ASSIGN);
205             enable(IDC_EDIT_DEVICE);
206             enable(IDC_BUTTON_BROWSE_DEVICE);
207             disable(IDC_EDIT_SERIAL);
208             disable(IDC_EDIT_LABEL);
209             disable(IDC_STATIC_SERIAL);
210             disable(IDC_STATIC_LABEL);
211             break;
212
213         case BOX_MODE_NONE:
214             disable(IDC_RADIO_ASSIGN);
215             disable(IDC_EDIT_DEVICE);
216             disable(IDC_BUTTON_BROWSE_DEVICE);
217             disable(IDC_EDIT_SERIAL);
218             disable(IDC_EDIT_LABEL);
219             disable(IDC_STATIC_SERIAL);
220             disable(IDC_STATIC_LABEL);
221             break;
222
223         case BOX_MODE_NORMAL:
224             enable(IDC_RADIO_ASSIGN);
225             disable(IDC_EDIT_DEVICE);
226             disable(IDC_BUTTON_BROWSE_DEVICE);
227             enable(IDC_EDIT_SERIAL);
228             enable(IDC_EDIT_LABEL);
229             enable(IDC_STATIC_SERIAL);
230             enable(IDC_STATIC_LABEL);
231             break;
232     }
233 }
234
235 int fill_drives_list(HWND dialog)
236 {
237     int count = 0;
238     BOOL drivec_present = FALSE;
239     int i;
240     int prevsel = -1;
241
242     WINE_TRACE("\n");
243
244     updating_ui = TRUE;
245
246     prevsel = lv_get_curr_select(dialog); 
247
248     /* Clear the listbox */
249     SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LVM_DELETEALLITEMS, 0, 0);
250
251     for(i = 0; i < 26; i++)
252     {
253         LVITEM item;
254         char *letter = 0;
255         int len;
256
257         /* skip over any unused drives */
258         if (!drives[i].in_use)
259             continue;
260
261         if (drives[i].letter == 'C')
262             drivec_present = TRUE;
263
264         len = snprintf(letter, 0, "%c:", 'A' + i);
265         len++; /* add a byte for the trailing null */
266
267         letter = HeapAlloc(GetProcessHeap(), 0, len);
268         snprintf(letter, len, "%c:", 'A' + i);
269
270         memset(&item, 0, sizeof(item));
271         item.mask = LVIF_TEXT;
272         item.iItem = count;
273         item.iSubItem = 0;
274         item.pszText = letter;
275         item.cchTextMax = lstrlen(item.pszText);
276
277         lv_insert_item(dialog, &item);
278
279         item.iSubItem = 1;
280         item.pszText = drives[i].unixpath;
281         item.cchTextMax = lstrlen(item.pszText);
282
283         lv_set_item(dialog, &item);
284
285         item.mask = LVIF_PARAM;
286         item.iSubItem = 0;
287         item.lParam = (LPARAM) &drives[i];
288         
289         lv_set_item(dialog, &item);
290
291         HeapFree(GetProcessHeap(), 0, letter);
292         count++;
293     }
294
295     WINE_TRACE("loaded %d drives\n", count);
296
297     /* show the warning if there is no Drive C */
298     if (!drivec_present)
299         ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_NORMAL);
300     else
301         ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_HIDE);
302
303     lv_set_curr_select(dialog, prevsel == -1 ? 0 : prevsel);
304
305     updating_ui = FALSE;
306     return count;
307 }
308
309 void on_options_click(HWND dialog)
310 {
311     if (IsDlgButtonChecked(dialog, IDC_SHOW_DIRSYM_LINK) == BST_CHECKED)
312         set("wine", "ShowDirSymLinks", "Y");
313     else
314         set("wine", "ShowDIrSymLinks", "N");
315
316     if (IsDlgButtonChecked(dialog, IDC_SHOW_DOT_FILES) == BST_CHECKED)
317         set("wine", "ShowDotFiles", "Y");
318     else
319         set("wine", "ShowDotFiles", "N");
320 }
321
322 void on_add_click(HWND dialog)
323 {
324     /* we should allocate a drive letter automatically. We also need
325        some way to let the user choose the mapping point, for now we
326        will just force them to enter a path automatically, with / being
327        the default. In future we should be able to temporarily map /
328        then invoke the directory chooser dialog. */
329
330     char new = 'C'; /* we skip A and B, they are historically floppy drives */
331     long mask = ~drive_available_mask(0); /* the mask is now which drives aren't available */
332     int i, c;
333
334     while (mask & (1 << (new - 'A')))
335     {
336         new++;
337         if (new > 'Z')
338         {
339             MessageBox(dialog, "You cannot add any more drives.\n\nEach drive must have a letter, from A to Z, so you cannot have more than 26", "", MB_OK | MB_ICONEXCLAMATION);
340             return;
341         }
342     }
343
344     WINE_TRACE("allocating drive letter %c\n", new);
345
346     if (new == 'C') add_drive(new, "../drive_c", "System Drive", "", DRIVE_FIXED);
347     else add_drive(new, "/", "", "", DRIVE_FIXED);
348
349     fill_drives_list(dialog);
350
351     /* select the newly created drive */
352     mask = ~drive_available_mask(0);
353     c = 0;
354     for (i = 0; i < 26; i++)
355     {
356         if ('A' + i == new) break;
357         if ((1 << i) & mask) c++;
358     }
359     lv_set_curr_select(dialog, c);
360
361     SetFocus(GetDlgItem(dialog, IDC_LIST_DRIVES));
362
363     update_controls(dialog);
364 }
365
366 void on_remove_click(HWND dialog)
367 {
368     int itemIndex;
369     struct drive *drive;
370     LVITEM item;
371
372     itemIndex = lv_get_curr_select(dialog);
373     if (itemIndex == -1) return; /* no selection */
374
375     memset(&item, 0, sizeof(item));
376     item.mask = LVIF_PARAM;
377     item.iItem = itemIndex;
378     item.iSubItem = 0;
379
380     lv_get_item(dialog, &item);
381
382     drive = (struct drive *) item.lParam;
383
384     WINE_ERR("unixpath: %s\n", drive->unixpath);
385
386     if (drive->letter == 'C')
387     {
388         DWORD result = MessageBox(dialog, "Are you sure you want to delete drive C?\n\nMost Windows applications expect drive C to exist, and will die messily if it doesn't. If you proceed remember to recreate it!", "", MB_YESNO | MB_ICONEXCLAMATION);
389         if (result == IDNO) return;
390     }
391
392     delete_drive(drive);
393
394     fill_drives_list(dialog);
395
396     itemIndex = itemIndex - 1;
397     if (itemIndex < 0) itemIndex = 0;
398     lv_set_curr_select(dialog, itemIndex);   /* previous item */
399
400     SetFocus(GetDlgItem(dialog, IDC_LIST_DRIVES));
401
402     update_controls(dialog);
403 }
404
405 static void update_controls(HWND dialog)
406 {
407     char *path;
408     unsigned int type;
409     char *label;
410     char *serial;
411     char *device;
412     int i, selection = -1;
413     LVITEM item;
414
415     updating_ui = TRUE;
416
417     i = lv_get_curr_select(dialog);
418     if (i == -1)
419     {
420         /* no selection? let's select something for the user. this will re-enter */
421         lv_set_curr_select(dialog, i);
422         return;
423     }
424
425     memset(&item, 0, sizeof(item));
426     item.mask = LVIF_PARAM;
427     item.iItem = i;
428     item.iSubItem = 0;
429
430     lv_get_item(dialog, &item);
431     current_drive = (struct drive *) item.lParam;
432
433     WINE_TRACE("Updating sheet for drive %c\n", current_drive->letter);
434
435     /* Drive letters */
436     fill_drive_droplist(drive_available_mask(current_drive->letter), current_drive->letter, dialog);
437
438     /* path */
439     path = current_drive->unixpath;
440     WINE_TRACE("set path control text to '%s'\n", path);
441     set_text(dialog, IDC_EDIT_PATH, path);
442
443     /* drive type */
444     type = current_drive->type;
445     if (type)
446     {
447         SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_RESETCONTENT, 0, 0);
448         
449         for (i = 0; i < sizeof(type_pairs) / sizeof(struct drive_typemap); i++)
450         {
451             SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_ADDSTRING, 0, (LPARAM) type_pairs[i].sDesc);
452
453             if (type_pairs[i].sCode ==  type)
454             {
455                 selection = i;
456             }
457         }
458
459         if (selection == -1) selection = DRIVE_TYPE_DEFAULT;
460         SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_SETCURSEL, selection, 0);
461     } else WINE_WARN("no Type field?\n");
462
463
464     /* removeable media properties */
465     label = current_drive->label;
466     set_text(dialog, IDC_EDIT_LABEL, label);
467
468     /* set serial edit text */
469     serial = current_drive->serial;
470     set_text(dialog, IDC_EDIT_SERIAL, serial);
471
472     /* TODO: get the device here to put into the edit box */
473     device = "Not implemented yet";
474     set_text(dialog, IDC_EDIT_DEVICE, device);
475     device = NULL;
476
477     selection = IDC_RADIO_ASSIGN;
478     if ((type == DRIVE_CDROM) || (type == DRIVE_REMOVABLE))
479     {
480         if (device)
481         {
482             selection = IDC_RADIO_AUTODETECT;
483             enable_labelserial_box(dialog, BOX_MODE_CD_AUTODETECT);
484         }
485         else
486         {
487             selection = IDC_RADIO_ASSIGN;
488             enable_labelserial_box(dialog, BOX_MODE_CD_ASSIGN);
489         }
490     }
491     else
492     {
493         enable_labelserial_box(dialog, BOX_MODE_NORMAL);
494         selection = IDC_RADIO_ASSIGN;
495     }
496
497     CheckRadioButton(dialog, IDC_RADIO_AUTODETECT, IDC_RADIO_ASSIGN, selection);
498
499     updating_ui = FALSE;
500
501     return;
502 }
503
504 void on_edit_changed(HWND dialog, WORD id)
505 {
506     if (updating_ui) return;
507
508     WINE_TRACE("edit id %d changed\n", id);
509
510     /* using fill_drives_list here is pretty lazy, but i'm tired
511
512        fortunately there are only 26 letters in the alphabet, so
513        we don't have to worry about efficiency too much here :)  */
514
515     switch (id)
516     {
517         case IDC_EDIT_LABEL:
518         {
519             char *label;
520
521             label = get_text(dialog, id);
522             HeapFree(GetProcessHeap(), 0, current_drive->label);
523             current_drive->label = label ? label :  strdupA("");
524
525             WINE_TRACE("set label to %s\n", current_drive->label);
526
527             fill_drives_list(dialog);
528             break;
529         }
530
531         case IDC_EDIT_PATH:
532         {
533             char *path;
534
535             path = get_text(dialog, id);
536             HeapFree(GetProcessHeap(), 0, current_drive->unixpath);
537             current_drive->unixpath = path ? path : strdupA("drive_c");
538
539             WINE_TRACE("set path to %s\n", current_drive->unixpath);
540
541             fill_drives_list(dialog);
542             break;
543         }
544
545         case IDC_EDIT_SERIAL:
546         {
547             char *serial;
548
549             serial = get_text(dialog, id);
550             HeapFree(GetProcessHeap(), 0, current_drive->serial);
551             current_drive->serial = serial ? serial : strdupA("");
552
553             WINE_TRACE("set serial to %s", current_drive->serial);
554
555             break;
556         }
557
558         case IDC_EDIT_DEVICE:
559         {
560             char *device = get_text(dialog, id);
561             /* TODO: handle device if/when it makes sense to do so.... */
562             HeapFree(GetProcessHeap(), 0, device);
563             fill_drives_list(dialog);
564             break;
565         }
566     }
567 }
568
569 static void get_etched_rect(HWND dialog, RECT *rect)
570 {
571     GetClientRect(dialog, rect);
572
573     /* these dimensions from the labelserial static in En.rc  */
574     rect->top = 265;
575     rect->bottom = 265;
576     rect->left += 25;
577     rect->right -= 25;
578 }
579
580 /* this just draws a nice line to separate the advanced gui from the n00b gui :) */
581 static void paint(HWND dialog)
582 {
583     PAINTSTRUCT ps;
584
585     BeginPaint(dialog, &ps);
586
587     if (advanced)
588     {
589         RECT rect;
590
591         get_etched_rect(dialog, &rect);
592
593         DrawEdge(ps.hdc, &rect, EDGE_ETCHED, BF_TOP);
594     }
595
596     EndPaint(dialog, &ps);
597 }
598
599 static void browse_for_folder(HWND dialog)
600 {
601     static WCHAR wszUnixRootDisplayName[] = 
602         { ':',':','{','C','C','7','0','2','E','B','2','-','7','D','C','5','-','1','1','D','9','-',
603           'C','6','8','7','-','0','0','0','4','2','3','8','A','0','1','C','D','}', 0 };
604     char pszChoosePath[256];
605     BROWSEINFOA bi = {
606         dialog,
607         NULL,
608         NULL,
609         pszChoosePath,
610         0,
611         NULL,
612         0,
613         0
614     };
615     IShellFolder *pDesktop;
616     LPITEMIDLIST pidlUnixRoot, pidlSelectedPath;
617     HRESULT hr;
618    
619     LoadString(GetModuleHandle(NULL), IDS_CHOOSE_PATH, pszChoosePath, 256);
620     
621     hr = SHGetDesktopFolder(&pDesktop);
622     if (!SUCCEEDED(hr)) return;
623
624     hr = pDesktop->lpVtbl->ParseDisplayName(pDesktop, NULL, NULL, wszUnixRootDisplayName, NULL, 
625                                             &pidlUnixRoot, NULL);
626     if (!SUCCEEDED(hr)) {
627         pDesktop->lpVtbl->Release(pDesktop);
628         return;
629     }
630
631     bi.pidlRoot = pidlUnixRoot;
632     pidlSelectedPath = SHBrowseForFolderA(&bi);
633     SHFree(pidlUnixRoot);
634     
635     if (pidlSelectedPath) {
636         STRRET strSelectedPath;
637         char *pszSelectedPath;
638         HRESULT hr;
639         
640         hr = pDesktop->lpVtbl->GetDisplayNameOf(pDesktop, pidlSelectedPath, SHGDN_FORPARSING, 
641                                                 &strSelectedPath);
642         pDesktop->lpVtbl->Release(pDesktop);
643         if (!SUCCEEDED(hr)) {
644             SHFree(pidlSelectedPath);
645             return;
646         }
647
648         hr = StrRetToStr(&strSelectedPath, pidlSelectedPath, &pszSelectedPath);
649         SHFree(pidlSelectedPath);
650         if (!SUCCEEDED(hr)) return;
651     
652         HeapFree(GetProcessHeap(), 0, current_drive->unixpath);
653         current_drive->unixpath = strdupA(pszSelectedPath);
654         fill_drives_list(dialog);
655         update_controls(dialog);   
656         
657         CoTaskMemFree(pszSelectedPath);
658     }
659 }
660
661 static void init_listview_columns(HWND dialog)
662 {
663     LVCOLUMN listColumn;
664     RECT viewRect;
665     int width;
666
667     GetClientRect(GetDlgItem(dialog, IDC_LIST_DRIVES), &viewRect);
668     width = (viewRect.right - viewRect.left) / 6 - 5;
669
670     listColumn.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
671     listColumn.pszText = "Letter";
672     listColumn.cchTextMax = lstrlen(listColumn.pszText);
673     listColumn.cx = width;
674
675     SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LVM_INSERTCOLUMN, 0, (LPARAM) &listColumn);
676
677     listColumn.cx = viewRect.right - viewRect.left - width;
678     listColumn.pszText = "Drive Mapping";
679     listColumn.cchTextMax = lstrlen(listColumn.pszText);
680
681     SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LVM_INSERTCOLUMN, 1, (LPARAM) &listColumn);
682 }
683
684 static void load_drive_options(HWND dialog)
685 {
686     if (!strcmp(get("wine", "ShowDirSymLinks", "N"), "Y"))
687         CheckDlgButton(dialog, IDC_SHOW_DIRSYM_LINK, BST_CHECKED);
688
689     if (!strcmp(get("wine", "ShowDotFiles", "N"), "Y"))
690         CheckDlgButton(dialog, IDC_SHOW_DOT_FILES, BST_CHECKED);
691 }
692
693 INT_PTR CALLBACK
694 DriveDlgProc (HWND dialog, UINT msg, WPARAM wParam, LPARAM lParam)
695 {
696     int item;
697     struct drive *drive;
698
699     switch (msg)
700     {
701         case WM_INITDIALOG:
702             init_listview_columns(dialog);
703             load_drives();
704             load_drive_options(dialog);
705
706             if (!drives[2].in_use)
707                 MessageBox(dialog, "You don't have a drive C. This is not so great.\n\nRemember to click 'Add' in the Drives tab to create one!\n", "", MB_OK | MB_ICONEXCLAMATION);
708
709             fill_drives_list(dialog);
710             update_controls(dialog);
711             /* put in non-advanced mode by default  */
712             set_advanced(dialog);
713             break;
714
715         case WM_SHOWWINDOW:
716             set_window_title(dialog);
717             break;
718
719         case WM_PAINT:
720             paint(dialog);
721             break;
722
723         case WM_COMMAND:
724             switch (HIWORD(wParam))
725             {
726                 case EN_CHANGE:
727                     on_edit_changed(dialog, LOWORD(wParam));
728                     break;
729
730                 case BN_CLICKED:
731                     SendMessage(GetParent(dialog), PSM_CHANGED, 0, 0);
732
733                     switch (LOWORD(wParam))
734                     {
735                         case IDC_SHOW_DIRSYM_LINK:
736                         case IDC_SHOW_DOT_FILES:
737                             on_options_click(dialog);
738                         break;
739                     }
740                     break;
741             }
742
743             switch (LOWORD(wParam))
744             {
745                 case IDC_BUTTON_ADD:
746                     if (HIWORD(wParam) != BN_CLICKED) break;
747                     on_add_click(dialog);
748                     break;
749
750                 case IDC_BUTTON_REMOVE:
751                     if (HIWORD(wParam) != BN_CLICKED) break;
752                     on_remove_click(dialog);
753                     break;
754
755                 case IDC_BUTTON_EDIT:
756                     if (HIWORD(wParam) != BN_CLICKED) break;
757                     item = SendMessage(GetDlgItem(dialog, IDC_LIST_DRIVES),  LB_GETCURSEL, 0, 0);
758                     drive = (struct drive *) SendMessage(GetDlgItem(dialog, IDC_LIST_DRIVES), LB_GETITEMDATA, item, 0);
759                     /*DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_DRIVE_EDIT), NULL, (DLGPROC) DriveEditDlgProc, (LPARAM) drive); */
760                     break;
761
762                 case IDC_BUTTON_AUTODETECT:
763                     autodetect_drives();
764                     fill_drives_list(dialog);
765                     break;
766
767                 case IDC_BUTTON_SHOW_HIDE_ADVANCED:
768                     advanced = !advanced;
769                     set_advanced(dialog);
770                     break;
771
772                 case IDC_BUTTON_BROWSE_PATH:
773                     browse_for_folder(dialog);
774                     break;
775
776                 case IDC_RADIO_ASSIGN:
777                 {
778                     char *str;
779
780                     str = get_text(dialog, IDC_EDIT_LABEL);
781                     HeapFree(GetProcessHeap(), 0, current_drive->label);
782                     current_drive->label = str ? str : strdupA("");
783
784                     str = get_text(dialog, IDC_EDIT_SERIAL);
785                     HeapFree(GetProcessHeap(), 0, current_drive->serial);
786                     current_drive->serial = str ? str : strdupA("");
787
788                     /* TODO: we don't have a device at this point */
789
790                     enable_labelserial_box(dialog, BOX_MODE_CD_ASSIGN);
791
792                     break;
793                 }
794
795
796                 case IDC_COMBO_TYPE:
797                 {
798                     int mode = BOX_MODE_NORMAL;
799                     int selection;
800
801                     if (HIWORD(wParam) != CBN_SELCHANGE) break;
802
803                     selection = SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_GETCURSEL, 0, 0);
804
805                     if (selection == 2 || selection == 3) /* cdrom or floppy */
806                     {
807                         if (IsDlgButtonChecked(dialog, IDC_RADIO_AUTODETECT))
808                             mode = BOX_MODE_CD_AUTODETECT;
809                         else
810                             mode = BOX_MODE_CD_ASSIGN;
811                     }
812
813                     enable_labelserial_box(dialog, mode);
814
815                     current_drive->type = type_pairs[selection].sCode;
816                     break;
817                 }
818
819             }
820             break;
821
822         case WM_NOTIFY:
823             switch (((LPNMHDR)lParam)->code)
824             {
825                 case PSN_KILLACTIVE:
826                     WINE_TRACE("PSN_KILLACTIVE\n");
827                     SetWindowLongPtr(dialog, DWLP_MSGRESULT, FALSE);
828                     break;
829                 case PSN_APPLY:
830                     apply_drive_changes();
831                     SetWindowLongPtr(dialog, DWLP_MSGRESULT, PSNRET_NOERROR);
832                     break;
833                 case PSN_SETACTIVE:
834                     break;
835             }
836
837             switch (((LPNMITEMACTIVATE)lParam)->hdr.code)
838             {
839                 case NM_CLICK:
840                     update_controls(dialog);
841                     break;
842             }
843             break;
844     }
845
846     return FALSE;
847 }