driveui.c 27.2 KB
Newer Older
Mike Hearn's avatar
Mike Hearn committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * Drive management UI code
 *
 * Copyright 2003 Mark Westcott
 * Copyright 2004 Chris Morgan
 * Copyright 2003-2004 Mike Hearn
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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
Mike Hearn's avatar
Mike Hearn committed
21 22 23
 *
 */

24 25
#include <stdio.h>

26
#define WIN32_LEAN_AND_MEAN
27 28
#define COBJMACROS

29
#include <windows.h>
Mike Hearn's avatar
Mike Hearn committed
30 31 32 33 34 35
#include <shellapi.h>
#include <objbase.h>
#include <shlguid.h>
#include <shlwapi.h>
#include <shlobj.h>

36
#include <wine/unicode.h>
Mike Hearn's avatar
Mike Hearn committed
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
#include <wine/debug.h>

#include "winecfg.h"
#include "resource.h"

WINE_DEFAULT_DEBUG_CHANNEL(winecfg);

#define BOX_MODE_CD_ASSIGN 1
#define BOX_MODE_CD_AUTODETECT 2
#define BOX_MODE_NONE 3
#define BOX_MODE_NORMAL 4

static BOOL advanced = FALSE;
static BOOL updating_ui = FALSE;
static struct drive* current_drive;

static void get_etched_rect(HWND dialog, RECT *rect);
54
static void update_controls(HWND dialog);
Mike Hearn's avatar
Mike Hearn committed
55

56 57 58
static DWORD driveui_msgbox (HWND parent, UINT messageId, DWORD flags)
{
  WCHAR* caption = load_string (IDS_WINECFG_TITLE);
59
  WCHAR* text = load_string (messageId);
60 61 62 63 64 65
  DWORD result = MessageBoxW (parent, text, caption, flags);
  HeapFree (GetProcessHeap(), 0, caption);
  HeapFree (GetProcessHeap(), 0, text);
  return result;
}

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
/**** listview helper functions ****/

/* clears the item at index in the listview */
static void lv_clear_curr_select(HWND dialog, int index)
{
    ListView_SetItemState(GetDlgItem(dialog, IDC_LIST_DRIVES), index, 0, LVIS_SELECTED);
}

/* selects the item at index in the listview */
static void lv_set_curr_select(HWND dialog, int index)
{
    /* no more than one item can be selected in our listview */
    lv_clear_curr_select(dialog, -1);
    ListView_SetItemState(GetDlgItem(dialog, IDC_LIST_DRIVES), index, LVIS_SELECTED, LVIS_SELECTED);
}

/* returns the currently selected item in the listview */
static int lv_get_curr_select(HWND dialog)
{
    return SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LVM_GETNEXTITEM, -1, LVNI_SELECTED);
}

/* sets the item in the listview at item->iIndex */
89
static void lv_set_item(HWND dialog, LVITEMW *item)
90
{
91
    SendDlgItemMessageW(dialog, IDC_LIST_DRIVES, LVM_SETITEMW, 0, (LPARAM) item);
92 93
}

94
/* sets specified item's text */
95
static void lv_set_item_text(HWND dialog, int item, int subItem, WCHAR *text)
96
{
97
    LVITEMW lvItem;
98 99 100 101 102
    if (item < 0 || subItem < 0) return;
    lvItem.mask = LVIF_TEXT;
    lvItem.iItem = item;
    lvItem.iSubItem = subItem;
    lvItem.pszText = text;
103
    lvItem.cchTextMax = lstrlenW(lvItem.pszText);
104 105 106
    lv_set_item(dialog, &lvItem);
}

107
/* inserts an item into the listview */
108
static void lv_insert_item(HWND dialog, LVITEMW *item)
109
{
110
    SendDlgItemMessageW(dialog, IDC_LIST_DRIVES, LVM_INSERTITEMW, 0, (LPARAM) item);
111 112 113
}

/* retrieve the item at index item->iIndex */
114
static void lv_get_item(HWND dialog, LVITEMW *item)
115
{
116
    SendDlgItemMessageW(dialog, IDC_LIST_DRIVES, LVM_GETITEMW, 0, (LPARAM) item);
117 118
}

Mike Hearn's avatar
Mike Hearn committed
119 120 121
static void set_advanced(HWND dialog)
{
    int state;
122
    WCHAR text[256];
Mike Hearn's avatar
Mike Hearn committed
123 124 125 126 127
    RECT rect;

    if (advanced)
    {
        state = SW_NORMAL;
128
        LoadStringW(GetModuleHandle(NULL), IDS_HIDE_ADVANCED, text, 256);
Mike Hearn's avatar
Mike Hearn committed
129 130 131 132
    }
    else
    {
        state = SW_HIDE;
133
        LoadStringW(GetModuleHandle(NULL), IDS_SHOW_ADVANCED, text, 256);
Mike Hearn's avatar
Mike Hearn committed
134 135 136 137 138 139 140 141 142 143 144
    }

    ShowWindow(GetDlgItem(dialog, IDC_RADIO_AUTODETECT), state);
    ShowWindow(GetDlgItem(dialog, IDC_RADIO_ASSIGN), state);
    ShowWindow(GetDlgItem(dialog, IDC_EDIT_LABEL), state);
    ShowWindow(GetDlgItem(dialog, IDC_EDIT_DEVICE), state);
    ShowWindow(GetDlgItem(dialog, IDC_STATIC_LABEL), state);
    ShowWindow(GetDlgItem(dialog, IDC_BUTTON_BROWSE_DEVICE), state);
    ShowWindow(GetDlgItem(dialog, IDC_EDIT_SERIAL), state);
    ShowWindow(GetDlgItem(dialog, IDC_STATIC_SERIAL), state);
    ShowWindow(GetDlgItem(dialog, IDC_LABELSERIAL_STATIC), state);
145 146
    ShowWindow(GetDlgItem(dialog, IDC_COMBO_TYPE), state);
    ShowWindow(GetDlgItem(dialog, IDC_STATIC_TYPE), state);
Mike Hearn's avatar
Mike Hearn committed
147 148

    /* update the button text based on the state */
149
    SetWindowTextW(GetDlgItem(dialog, IDC_BUTTON_SHOW_HIDE_ADVANCED), text);
Mike Hearn's avatar
Mike Hearn committed
150 151 152 153 154 155 156 157

    /* redraw for the etched line */
    get_etched_rect(dialog, &rect);
    InflateRect(&rect, 5, 5);
    InvalidateRect(dialog, &rect, TRUE);
}

struct drive_typemap {
Steven Edwards's avatar
Steven Edwards committed
158
    unsigned int sCode;
159
    UINT idDesc;
Mike Hearn's avatar
Mike Hearn committed
160 161
};

Steven Edwards's avatar
Steven Edwards committed
162
static const struct drive_typemap type_pairs[] = {
163 164 165 166 167
  { DRIVE_UNKNOWN,    IDS_DRIVE_UNKNOWN   },
  { DRIVE_FIXED,      IDS_DRIVE_FIXED     },
  { DRIVE_REMOTE,     IDS_DRIVE_REMOTE    },
  { DRIVE_REMOVABLE,  IDS_DRIVE_REMOVABLE },
  { DRIVE_CDROM,      IDS_DRIVE_CDROM     }
Mike Hearn's avatar
Mike Hearn committed
168 169
};

170
#define DRIVE_TYPE_DEFAULT 0
Mike Hearn's avatar
Mike Hearn committed
171

172
static void enable_labelserial_box(HWND dialog, int mode)
Mike Hearn's avatar
Mike Hearn committed
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
{
    WINE_TRACE("mode=%d\n", mode);

    switch (mode)
    {
        case BOX_MODE_CD_ASSIGN:
            enable(IDC_RADIO_ASSIGN);
            disable(IDC_EDIT_DEVICE);
            disable(IDC_BUTTON_BROWSE_DEVICE);
            enable(IDC_EDIT_SERIAL);
            enable(IDC_EDIT_LABEL);
            enable(IDC_STATIC_SERIAL);
            enable(IDC_STATIC_LABEL);
            break;

        case BOX_MODE_CD_AUTODETECT:
            enable(IDC_RADIO_ASSIGN);
            enable(IDC_EDIT_DEVICE);
            enable(IDC_BUTTON_BROWSE_DEVICE);
            disable(IDC_EDIT_SERIAL);
            disable(IDC_EDIT_LABEL);
            disable(IDC_STATIC_SERIAL);
            disable(IDC_STATIC_LABEL);
            break;

        case BOX_MODE_NONE:
            disable(IDC_RADIO_ASSIGN);
            disable(IDC_EDIT_DEVICE);
            disable(IDC_BUTTON_BROWSE_DEVICE);
            disable(IDC_EDIT_SERIAL);
            disable(IDC_EDIT_LABEL);
            disable(IDC_STATIC_SERIAL);
            disable(IDC_STATIC_LABEL);
            break;

        case BOX_MODE_NORMAL:
            enable(IDC_RADIO_ASSIGN);
            disable(IDC_EDIT_DEVICE);
            disable(IDC_BUTTON_BROWSE_DEVICE);
            enable(IDC_EDIT_SERIAL);
            enable(IDC_EDIT_LABEL);
            enable(IDC_STATIC_SERIAL);
            enable(IDC_STATIC_LABEL);
            break;
    }
}

220
static int fill_drives_list(HWND dialog)
Mike Hearn's avatar
Mike Hearn committed
221 222 223 224 225 226 227 228 229 230
{
    int count = 0;
    BOOL drivec_present = FALSE;
    int i;
    int prevsel = -1;

    WINE_TRACE("\n");

    updating_ui = TRUE;

231
    prevsel = lv_get_curr_select(dialog); 
Mike Hearn's avatar
Mike Hearn committed
232 233

    /* Clear the listbox */
234
    SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LVM_DELETEALLITEMS, 0, 0);
Mike Hearn's avatar
Mike Hearn committed
235 236 237

    for(i = 0; i < 26; i++)
    {
238 239
        LVITEMW item;
        WCHAR *path;
240
        char letter[4];
Mike Hearn's avatar
Mike Hearn committed
241 242 243 244 245 246 247 248

        /* skip over any unused drives */
        if (!drives[i].in_use)
            continue;

        if (drives[i].letter == 'C')
            drivec_present = TRUE;

249 250 251
        letter[0] = 'A' + i;
        letter[1] = ':';
        letter[2] = 0;
252

253
        item.mask = LVIF_TEXT | LVIF_PARAM;
254 255
        item.iItem = count;
        item.iSubItem = 0;
256 257
        item.pszText = strdupU2W(letter);
        item.cchTextMax = lstrlenW(item.pszText);
258
        item.lParam = (LPARAM) &drives[i];
Mike Hearn's avatar
Mike Hearn committed
259

260
        lv_insert_item(dialog, &item);
261 262 263 264 265
        HeapFree(GetProcessHeap(), 0, item.pszText);

        path = strdupU2W(drives[i].unixpath);
        lv_set_item_text(dialog, count, 1, path);
        HeapFree(GetProcessHeap(), 0, path);
Mike Hearn's avatar
Mike Hearn committed
266 267 268 269 270 271 272 273 274 275 276 277

        count++;
    }

    WINE_TRACE("loaded %d drives\n", count);

    /* show the warning if there is no Drive C */
    if (!drivec_present)
        ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_NORMAL);
    else
        ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_HIDE);

278
    lv_set_curr_select(dialog, prevsel == -1 ? 0 : prevsel);
Mike Hearn's avatar
Mike Hearn committed
279 280 281 282 283

    updating_ui = FALSE;
    return count;
}

284
static void on_options_click(HWND dialog)
285 286
{
    if (IsDlgButtonChecked(dialog, IDC_SHOW_DOT_FILES) == BST_CHECKED)
287
        set_reg_key(config_key, "", "ShowDotFiles", "Y");
288
    else
289
        set_reg_key(config_key, "", "ShowDotFiles", "N");
290 291

    SendMessage(GetParent(dialog), PSM_CHANGED, 0, 0);
292
}
Mike Hearn's avatar
Mike Hearn committed
293

294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
static INT_PTR CALLBACK drivechoose_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static int i, sel;
    char c;
    char drive[] = "X:";

    switch(uMsg)
    {
    case WM_INITDIALOG:
        {
        ULONG mask = ~drive_available_mask(0); /* the mask is now which drives aren't available */
        for( c = 'A'; c<= 'Z'; c++){
            drive[0] = c;
            if(!( mask & (1 << (c - 'A'))))
                SendDlgItemMessageA( hwndDlg, IDC_DRIVESA2Z, CB_ADDSTRING, 0, (LPARAM) drive);
        }
        drive[0] = lParam;
        SendDlgItemMessageA( hwndDlg, IDC_DRIVESA2Z, CB_SELECTSTRING, 0, (LPARAM) drive);
        return TRUE;
        }
    case WM_COMMAND:
        if(HIWORD(wParam) != BN_CLICKED) break;
        switch (LOWORD(wParam))
        {
        case IDOK:
            i = SendDlgItemMessageA( hwndDlg, IDC_DRIVESA2Z, CB_GETCURSEL, 0, 0);
            if( i != CB_ERR){
                SendDlgItemMessageA( hwndDlg, IDC_DRIVESA2Z, CB_GETLBTEXT, i, (LPARAM) drive);
                sel = drive[0];
            } else
                sel = -1;
            EndDialog(hwndDlg, sel);
            return TRUE;
        case IDCANCEL:
            EndDialog(hwndDlg, -1);
            return TRUE;
        }
    }
    return FALSE;
}

335
static void on_add_click(HWND dialog)
Mike Hearn's avatar
Mike Hearn committed
336 337 338 339 340 341 342 343
{
    /* we should allocate a drive letter automatically. We also need
       some way to let the user choose the mapping point, for now we
       will just force them to enter a path automatically, with / being
       the default. In future we should be able to temporarily map /
       then invoke the directory chooser dialog. */

    char new = 'C'; /* we skip A and B, they are historically floppy drives */
344
    ULONG mask = ~drive_available_mask(0); /* the mask is now which drives aren't available */
Mike Hearn's avatar
Mike Hearn committed
345 346 347 348 349 350 351
    int i, c;

    while (mask & (1 << (new - 'A')))
    {
        new++;
        if (new > 'Z')
        {
352
            driveui_msgbox (dialog, IDS_DRIVE_LETTERS_EXCEEDED, MB_OK | MB_ICONEXCLAMATION);
Mike Hearn's avatar
Mike Hearn committed
353 354 355 356
            return;
        }
    }

357 358 359 360 361 362

    new = DialogBoxParam(0, MAKEINTRESOURCE(IDD_DRIVECHOOSE), dialog, drivechoose_dlgproc, new);

    if( new == -1) return;

    WINE_TRACE("selected drive letter %c\n", new);
Mike Hearn's avatar
Mike Hearn committed
363

364 365
    if (new == 'C')
    {
366 367 368
        WCHAR label[64];
        LoadStringW (GetModuleHandle (NULL), IDS_SYSTEM_DRIVE_LABEL, label,
                     sizeof(label)/sizeof(label[0]));
369
        add_drive(new, "../drive_c", NULL, label, 0, DRIVE_FIXED);
370
    }
371
    else add_drive(new, "/", NULL, NULL, 0, DRIVE_UNKNOWN);
Mike Hearn's avatar
Mike Hearn committed
372 373 374 375 376 377 378 379 380 381 382

    fill_drives_list(dialog);

    /* select the newly created drive */
    mask = ~drive_available_mask(0);
    c = 0;
    for (i = 0; i < 26; i++)
    {
        if ('A' + i == new) break;
        if ((1 << i) & mask) c++;
    }
383
    lv_set_curr_select(dialog, c);
Mike Hearn's avatar
Mike Hearn committed
384 385

    SetFocus(GetDlgItem(dialog, IDC_LIST_DRIVES));
386 387

    update_controls(dialog);
388
    SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
Mike Hearn's avatar
Mike Hearn committed
389 390
}

391
static void on_remove_click(HWND dialog)
Mike Hearn's avatar
Mike Hearn committed
392
{
393
    int itemIndex;
Mike Hearn's avatar
Mike Hearn committed
394
    struct drive *drive;
395
    LVITEMW item;
396 397 398 399 400 401 402 403 404 405 406

    itemIndex = lv_get_curr_select(dialog);
    if (itemIndex == -1) return; /* no selection */

    item.mask = LVIF_PARAM;
    item.iItem = itemIndex;
    item.iSubItem = 0;

    lv_get_item(dialog, &item);

    drive = (struct drive *) item.lParam;
Mike Hearn's avatar
Mike Hearn committed
407

408
    WINE_TRACE("unixpath: %s\n", drive->unixpath);
Mike Hearn's avatar
Mike Hearn committed
409 410 411

    if (drive->letter == 'C')
    {
412
        DWORD result = driveui_msgbox (dialog, IDS_CONFIRM_DELETE_C, MB_YESNO | MB_ICONEXCLAMATION);
Mike Hearn's avatar
Mike Hearn committed
413 414 415 416 417 418 419
        if (result == IDNO) return;
    }

    delete_drive(drive);

    fill_drives_list(dialog);

420 421 422
    itemIndex = itemIndex - 1;
    if (itemIndex < 0) itemIndex = 0;
    lv_set_curr_select(dialog, itemIndex);   /* previous item */
Mike Hearn's avatar
Mike Hearn committed
423 424

    SetFocus(GetDlgItem(dialog, IDC_LIST_DRIVES));
425 426

    update_controls(dialog);
427
    SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
Mike Hearn's avatar
Mike Hearn committed
428 429
}

430 431
static void update_controls(HWND dialog)
{
432
    static const WCHAR emptyW[1];
433
    WCHAR *path;
Steven Edwards's avatar
Steven Edwards committed
434
    unsigned int type;
435
    char serial[16];
436
    const char *device;
Mike Hearn's avatar
Mike Hearn committed
437
    int i, selection = -1;
438
    LVITEMW item;
Mike Hearn's avatar
Mike Hearn committed
439 440 441

    updating_ui = TRUE;

442
    i = lv_get_curr_select(dialog);
Mike Hearn's avatar
Mike Hearn committed
443 444 445
    if (i == -1)
    {
        /* no selection? let's select something for the user. this will re-enter */
446
        lv_set_curr_select(dialog, i);
Mike Hearn's avatar
Mike Hearn committed
447 448
        return;
    }
449 450 451 452 453 454 455

    item.mask = LVIF_PARAM;
    item.iItem = i;
    item.iSubItem = 0;

    lv_get_item(dialog, &item);
    current_drive = (struct drive *) item.lParam;
Mike Hearn's avatar
Mike Hearn committed
456 457 458 459

    WINE_TRACE("Updating sheet for drive %c\n", current_drive->letter);

    /* path */
460 461 462 463
    WINE_TRACE("set path control text to '%s'\n", current_drive->unixpath);
    path = strdupU2W(current_drive->unixpath);
    set_textW(dialog, IDC_EDIT_PATH, path);
    HeapFree(GetProcessHeap(), 0, path);
Mike Hearn's avatar
Mike Hearn committed
464 465 466

    /* drive type */
    type = current_drive->type;
467 468 469
    SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_RESETCONTENT, 0, 0);

    for (i = 0; i < sizeof(type_pairs) / sizeof(struct drive_typemap); i++)
Mike Hearn's avatar
Mike Hearn committed
470
    {
471 472 473 474
        WCHAR driveDesc[64];
        LoadStringW (GetModuleHandle (NULL), type_pairs[i].idDesc, driveDesc,
            sizeof(driveDesc)/sizeof(driveDesc[0]));
        SendDlgItemMessageW (dialog, IDC_COMBO_TYPE, CB_ADDSTRING, 0, (LPARAM)driveDesc);
Mike Hearn's avatar
Mike Hearn committed
475

476 477 478
        if (type_pairs[i].sCode ==  type)
        {
            selection = i;
Mike Hearn's avatar
Mike Hearn committed
479
        }
480
    }
Mike Hearn's avatar
Mike Hearn committed
481

482 483
    if (selection == -1) selection = DRIVE_TYPE_DEFAULT;
    SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_SETCURSEL, selection, 0);
Mike Hearn's avatar
Mike Hearn committed
484

485 486 487 488 489
    EnableWindow( GetDlgItem( dialog, IDC_BUTTON_REMOVE ), (current_drive->letter != 'C') );
    EnableWindow( GetDlgItem( dialog, IDC_EDIT_PATH ), (current_drive->letter != 'C') );
    EnableWindow( GetDlgItem( dialog, IDC_BUTTON_BROWSE_PATH ), (current_drive->letter != 'C') );
    EnableWindow( GetDlgItem( dialog, IDC_COMBO_TYPE ), (current_drive->letter != 'C') );

Mike Hearn's avatar
Mike Hearn committed
490
    /* removeable media properties */
491
    set_textW(dialog, IDC_EDIT_LABEL, current_drive->label ? current_drive->label : emptyW);
Mike Hearn's avatar
Mike Hearn committed
492 493

    /* set serial edit text */
494
    sprintf( serial, "%X", current_drive->serial );
Mike Hearn's avatar
Mike Hearn committed
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
    set_text(dialog, IDC_EDIT_SERIAL, serial);

    /* TODO: get the device here to put into the edit box */
    device = "Not implemented yet";
    set_text(dialog, IDC_EDIT_DEVICE, device);
    device = NULL;

    selection = IDC_RADIO_ASSIGN;
    if ((type == DRIVE_CDROM) || (type == DRIVE_REMOVABLE))
    {
        if (device)
        {
            selection = IDC_RADIO_AUTODETECT;
            enable_labelserial_box(dialog, BOX_MODE_CD_AUTODETECT);
        }
        else
        {
            selection = IDC_RADIO_ASSIGN;
            enable_labelserial_box(dialog, BOX_MODE_CD_ASSIGN);
        }
    }
    else
    {
        enable_labelserial_box(dialog, BOX_MODE_NORMAL);
        selection = IDC_RADIO_ASSIGN;
    }

    CheckRadioButton(dialog, IDC_RADIO_AUTODETECT, IDC_RADIO_ASSIGN, selection);

    updating_ui = FALSE;

    return;
}

529
static void on_edit_changed(HWND dialog, WORD id)
Mike Hearn's avatar
Mike Hearn committed
530 531 532 533 534 535 536 537 538
{
    if (updating_ui) return;

    WINE_TRACE("edit id %d changed\n", id);

    switch (id)
    {
        case IDC_EDIT_LABEL:
        {
539
            WCHAR *label = get_textW(dialog, id);
540
            HeapFree(GetProcessHeap(), 0, current_drive->label);
541
            current_drive->label = label;
542
            current_drive->modified = TRUE;
Mike Hearn's avatar
Mike Hearn committed
543

544
            WINE_TRACE("set label to %s\n", wine_dbgstr_w(current_drive->label));
Mike Hearn's avatar
Mike Hearn committed
545

546 547
            /* enable the apply button  */
            SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
Mike Hearn's avatar
Mike Hearn committed
548 549 550 551 552
            break;
        }

        case IDC_EDIT_PATH:
        {
553
            WCHAR *wpath;
Mike Hearn's avatar
Mike Hearn committed
554
            char *path;
555 556 557 558 559 560 561 562 563 564 565 566 567
            int lenW;

            wpath = get_textW(dialog, id);
            if( (lenW = WideCharToMultiByte(CP_UNIXCP, 0, wpath, -1, NULL, 0, NULL, NULL)) )
            {
                path = HeapAlloc(GetProcessHeap(), 0, lenW);
                WideCharToMultiByte(CP_UNIXCP, 0, wpath, -1, path, lenW, NULL, NULL);
            }
            else
            {
                path = NULL;
                wpath = strdupU2W("drive_c");
            }
Mike Hearn's avatar
Mike Hearn committed
568

569
            HeapFree(GetProcessHeap(), 0, current_drive->unixpath);
Mike Hearn's avatar
Mike Hearn committed
570
            current_drive->unixpath = path ? path : strdupA("drive_c");
571
            current_drive->modified = TRUE;
Mike Hearn's avatar
Mike Hearn committed
572 573 574

            WINE_TRACE("set path to %s\n", current_drive->unixpath);

575
            lv_set_item_text(dialog, lv_get_curr_select(dialog), 1,
576 577
                             wpath);
            HeapFree(GetProcessHeap(), 0, wpath);
578 579 580

            /* enable the apply button  */
            SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
Mike Hearn's avatar
Mike Hearn committed
581 582 583 584 585 586 587 588
            break;
        }

        case IDC_EDIT_SERIAL:
        {
            char *serial;

            serial = get_text(dialog, id);
589 590
            current_drive->serial = serial ? strtoul( serial, NULL, 16 ) : 0;
            HeapFree(GetProcessHeap(), 0, serial);
591
            current_drive->modified = TRUE;
Mike Hearn's avatar
Mike Hearn committed
592

593
            WINE_TRACE("set serial to %08X\n", current_drive->serial);
Mike Hearn's avatar
Mike Hearn committed
594

595 596
            /* enable the apply button  */
            SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
Mike Hearn's avatar
Mike Hearn committed
597 598 599 600 601 602 603
            break;
        }

        case IDC_EDIT_DEVICE:
        {
            char *device = get_text(dialog, id);
            /* TODO: handle device if/when it makes sense to do so.... */
604
            HeapFree(GetProcessHeap(), 0, device);
Mike Hearn's avatar
Mike Hearn committed
605 606 607 608 609 610 611 612 613 614
            break;
        }
    }
}

static void get_etched_rect(HWND dialog, RECT *rect)
{
    GetClientRect(dialog, rect);

    /* these dimensions from the labelserial static in En.rc  */
615 616 617
    rect->top = 265;
    rect->bottom = 265;
    rect->left += 25;
Mike Hearn's avatar
Mike Hearn committed
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639
    rect->right -= 25;
}

/* this just draws a nice line to separate the advanced gui from the n00b gui :) */
static void paint(HWND dialog)
{
    PAINTSTRUCT ps;

    BeginPaint(dialog, &ps);

    if (advanced)
    {
        RECT rect;

        get_etched_rect(dialog, &rect);

        DrawEdge(ps.hdc, &rect, EDGE_ETCHED, BF_TOP);
    }

    EndPaint(dialog, &ps);
}

640
BOOL browse_for_unix_folder(HWND dialog, WCHAR *pszPath)
641 642 643
{
    static WCHAR wszUnixRootDisplayName[] = 
        { ':',':','{','C','C','7','0','2','E','B','2','-','7','D','C','5','-','1','1','D','9','-',
644
          'C','6','8','7','-','0','0','0','4','2','3','8','A','0','1','C','D','}', 0 };
645 646
    WCHAR pszChoosePath[FILENAME_MAX];
    BROWSEINFOW bi = {
647 648 649
        dialog,
        NULL,
        NULL,
650
        pszChoosePath,
651 652 653 654 655 656 657 658
        0,
        NULL,
        0,
        0
    };
    IShellFolder *pDesktop;
    LPITEMIDLIST pidlUnixRoot, pidlSelectedPath;
    HRESULT hr;
659
   
660
    LoadStringW(GetModuleHandle(NULL), IDS_CHOOSE_PATH, pszChoosePath, FILENAME_MAX);
661 662
    
    hr = SHGetDesktopFolder(&pDesktop);
663
    if (FAILED(hr)) return FALSE;
664

665 666
    hr = IShellFolder_ParseDisplayName(pDesktop, NULL, NULL, wszUnixRootDisplayName, NULL, 
                                       &pidlUnixRoot, NULL);
667
    if (FAILED(hr)) {
668
        IShellFolder_Release(pDesktop);
669
        return FALSE;
670 671 672
    }

    bi.pidlRoot = pidlUnixRoot;
673
    pidlSelectedPath = SHBrowseForFolderW(&bi);
674 675 676 677
    SHFree(pidlUnixRoot);
    
    if (pidlSelectedPath) {
        STRRET strSelectedPath;
678
        WCHAR *pszSelectedPath;
679 680
        HRESULT hr;
        
681 682 683
        hr = IShellFolder_GetDisplayNameOf(pDesktop, pidlSelectedPath, SHGDN_FORPARSING, 
                                           &strSelectedPath);
        IShellFolder_Release(pDesktop);
684
        if (FAILED(hr)) {
685
            SHFree(pidlSelectedPath);
686
            return FALSE;
687 688
        }

689
        hr = StrRetToStrW(&strSelectedPath, pidlSelectedPath, &pszSelectedPath);
690
        SHFree(pidlSelectedPath);
691
        if (FAILED(hr)) return FALSE;
692

693
        lstrcpyW(pszPath, pszSelectedPath);
694 695
        
        CoTaskMemFree(pszSelectedPath);
696
        return TRUE;
697
    }
698
    return FALSE;
699 700
}

701 702
static void init_listview_columns(HWND dialog)
{
703
    LVCOLUMNW listColumn;
704 705
    RECT viewRect;
    int width;
706
    WCHAR column[64];
707 708 709 710

    GetClientRect(GetDlgItem(dialog, IDC_LIST_DRIVES), &viewRect);
    width = (viewRect.right - viewRect.left) / 6 - 5;

711 712
    LoadStringW (GetModuleHandle (NULL), IDS_COL_DRIVELETTER, column,
        sizeof(column)/sizeof(column[0]));
713
    listColumn.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
714 715
    listColumn.pszText = column;
    listColumn.cchTextMax = lstrlenW (listColumn.pszText);
716 717
    listColumn.cx = width;

718
    SendDlgItemMessageW (dialog, IDC_LIST_DRIVES, LVM_INSERTCOLUMNW, 0, (LPARAM) &listColumn);
719

720 721
    LoadStringW (GetModuleHandle (NULL), IDS_COL_DRIVEMAPPING, column,
        sizeof(column)/sizeof(column[0]));
722
    listColumn.cx = viewRect.right - viewRect.left - width;
723 724
    listColumn.pszText = column;
    listColumn.cchTextMax = lstrlenW (listColumn.pszText);
725

726
    SendDlgItemMessageW (dialog, IDC_LIST_DRIVES, LVM_INSERTCOLUMNW, 1, (LPARAM) &listColumn);
727 728
}

729 730
static void load_drive_options(HWND dialog)
{
731
    if (!strcmp(get_reg_key(config_key, "", "ShowDotFiles", "N"), "Y"))
732 733
        CheckDlgButton(dialog, IDC_SHOW_DOT_FILES, BST_CHECKED);
}
734

Mike Hearn's avatar
Mike Hearn committed
735 736 737 738 739 740 741 742 743
INT_PTR CALLBACK
DriveDlgProc (HWND dialog, UINT msg, WPARAM wParam, LPARAM lParam)
{
    int item;
    struct drive *drive;

    switch (msg)
    {
        case WM_INITDIALOG:
744
            init_listview_columns(dialog);
745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
            if (!load_drives())
            {
                ShowWindow( GetDlgItem( dialog, IDC_STATIC_MOUNTMGR_ERROR ), SW_SHOW );
                ShowWindow( GetDlgItem( dialog, IDC_LIST_DRIVES ), SW_HIDE );
                ShowWindow( GetDlgItem( dialog, IDC_BUTTON_ADD ), SW_HIDE );
                ShowWindow( GetDlgItem( dialog, IDC_BUTTON_REMOVE ), SW_HIDE );
                ShowWindow( GetDlgItem( dialog, IDC_BUTTON_AUTODETECT ), SW_HIDE );
                ShowWindow( GetDlgItem( dialog, IDC_STATIC_PATH ), SW_HIDE );
                ShowWindow( GetDlgItem( dialog, IDC_EDIT_PATH ), SW_HIDE );
                ShowWindow( GetDlgItem( dialog, IDC_BUTTON_BROWSE_PATH ), SW_HIDE );
                ShowWindow( GetDlgItem( dialog, IDC_COMBO_TYPE ), SW_HIDE );
                ShowWindow( GetDlgItem( dialog, IDC_BUTTON_SHOW_HIDE_ADVANCED ), SW_HIDE );
                set_advanced(dialog);
                break;
            }
            ShowWindow( GetDlgItem( dialog, IDC_STATIC_MOUNTMGR_ERROR ), SW_HIDE );
761
            load_drive_options(dialog);
Mike Hearn's avatar
Mike Hearn committed
762 763

            if (!drives[2].in_use)
764
                driveui_msgbox (dialog, IDS_NO_DRIVE_C, MB_OK | MB_ICONEXCLAMATION);
Mike Hearn's avatar
Mike Hearn committed
765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780

            fill_drives_list(dialog);
            update_controls(dialog);
            /* put in non-advanced mode by default  */
            set_advanced(dialog);
            break;

        case WM_SHOWWINDOW:
            set_window_title(dialog);
            break;

        case WM_PAINT:
            paint(dialog);
            break;

        case WM_COMMAND:
781
            switch (HIWORD(wParam))
Mike Hearn's avatar
Mike Hearn committed
782
            {
783 784 785 786 787 788 789 790 791 792 793 794
                case EN_CHANGE:
                    on_edit_changed(dialog, LOWORD(wParam));
                    break;

                case BN_CLICKED:
                    switch (LOWORD(wParam))
                    {
                        case IDC_SHOW_DOT_FILES:
                            on_options_click(dialog);
                        break;
                    }
                    break;
795 796 797 798

                case CBN_SELCHANGE:
                    SendMessage(GetParent(dialog), PSM_CHANGED, 0, 0);
                    break;
Mike Hearn's avatar
Mike Hearn committed
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821
            }

            switch (LOWORD(wParam))
            {
                case IDC_BUTTON_ADD:
                    if (HIWORD(wParam) != BN_CLICKED) break;
                    on_add_click(dialog);
                    break;

                case IDC_BUTTON_REMOVE:
                    if (HIWORD(wParam) != BN_CLICKED) break;
                    on_remove_click(dialog);
                    break;

                case IDC_BUTTON_EDIT:
                    if (HIWORD(wParam) != BN_CLICKED) break;
                    item = SendMessage(GetDlgItem(dialog, IDC_LIST_DRIVES),  LB_GETCURSEL, 0, 0);
                    drive = (struct drive *) SendMessage(GetDlgItem(dialog, IDC_LIST_DRIVES), LB_GETITEMDATA, item, 0);
                    break;

                case IDC_BUTTON_AUTODETECT:
                    autodetect_drives();
                    fill_drives_list(dialog);
822
                    SendMessage(GetParent(dialog), PSM_CHANGED, 0, 0);
Mike Hearn's avatar
Mike Hearn committed
823 824 825 826 827 828 829 830
                    break;

                case IDC_BUTTON_SHOW_HIDE_ADVANCED:
                    advanced = !advanced;
                    set_advanced(dialog);
                    break;

                case IDC_BUTTON_BROWSE_PATH:
831
                {
832
                    WCHAR szTargetPath[FILENAME_MAX];
833
                    if (browse_for_unix_folder(dialog, szTargetPath)) 
834
                        set_textW(dialog, IDC_EDIT_PATH, szTargetPath);
Mike Hearn's avatar
Mike Hearn committed
835
                    break;
836
                }
Mike Hearn's avatar
Mike Hearn committed
837 838 839

                case IDC_RADIO_ASSIGN:
                {
840
                    WCHAR *str = get_textW(dialog, IDC_EDIT_LABEL);
841
                    HeapFree(GetProcessHeap(), 0, current_drive->label);
842
                    current_drive->label = str;
Mike Hearn's avatar
Mike Hearn committed
843

844
                    str = get_textW(dialog, IDC_EDIT_SERIAL);
845 846
                    current_drive->serial = str ? strtoulW( str, NULL, 16 ) : 0;
                    HeapFree(GetProcessHeap(), 0, str);
847
                    current_drive->modified = TRUE;
Mike Hearn's avatar
Mike Hearn committed
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865

                    /* TODO: we don't have a device at this point */

                    enable_labelserial_box(dialog, BOX_MODE_CD_ASSIGN);

                    break;
                }


                case IDC_COMBO_TYPE:
                {
                    int mode = BOX_MODE_NORMAL;
                    int selection;

                    if (HIWORD(wParam) != CBN_SELCHANGE) break;

                    selection = SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_GETCURSEL, 0, 0);

866 867 868
                    if (selection >= 0 &&
                        (type_pairs[selection].sCode == DRIVE_CDROM ||
                         type_pairs[selection].sCode == DRIVE_REMOVABLE))
Mike Hearn's avatar
Mike Hearn committed
869 870 871 872 873 874 875 876 877 878
                    {
                        if (IsDlgButtonChecked(dialog, IDC_RADIO_AUTODETECT))
                            mode = BOX_MODE_CD_AUTODETECT;
                        else
                            mode = BOX_MODE_CD_ASSIGN;
                    }

                    enable_labelserial_box(dialog, mode);

                    current_drive->type = type_pairs[selection].sCode;
879
                    current_drive->modified = TRUE;
Mike Hearn's avatar
Mike Hearn committed
880 881 882 883 884 885 886 887 888 889 890
                    break;
                }

            }
            break;

        case WM_NOTIFY:
            switch (((LPNMHDR)lParam)->code)
            {
                case PSN_KILLACTIVE:
                    WINE_TRACE("PSN_KILLACTIVE\n");
891
                    SetWindowLongPtr(dialog, DWLP_MSGRESULT, FALSE);
Mike Hearn's avatar
Mike Hearn committed
892 893 894
                    break;
                case PSN_APPLY:
                    apply_drive_changes();
895
                    SetWindowLongPtr(dialog, DWLP_MSGRESULT, PSNRET_NOERROR);
Mike Hearn's avatar
Mike Hearn committed
896 897 898
                    break;
                case PSN_SETACTIVE:
                    break;
899 900 901 902 903
                case LVN_ITEMCHANGED:
                {
                    LPNMLISTVIEW lpnm = (LPNMLISTVIEW)lParam;
                    if (!(lpnm->uOldState & LVIS_SELECTED) &&
                         (lpnm->uNewState & LVIS_SELECTED))
904 905
                    update_controls(dialog);
                    break;
906
                }
907
            }
Mike Hearn's avatar
Mike Hearn committed
908 909 910 911 912
            break;
    }

    return FALSE;
}