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