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