2 * Copyright (c) 2000, Red Hat, Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * A copy of the GNU General Public License can be found at
12 * Written by DJ Delorie <dj@cygnus.com>
16 /* The purpose of this file is to let the user choose which packages
17 to install, and which versions of the package when more than one
18 version is provided. The "trust" level serves as an indication as
19 to which version should be the default choice. At the moment, all
20 we do is compare with previously installed packages to skip any
21 that are already installed (by setting the action to ACTION_SAME).
22 While the "trust" stuff is supported, it's not really implemented
23 yet. We always prefer the "current" option. In the future, this
24 file might have a user dialog added to let the user choose to not
25 install packages, or to install packages that aren't installed by
49 #define TRUST_KEEP 101
50 #define TRUST_UNINSTALL 102
51 #define TRUST_NONE 103
53 static int initialized = 0;
55 static int full_list = 0;
57 static int scroll_ulc_x, scroll_ulc_y;
59 static HWND lv, nextbutton;
61 static int header_height;
62 static HANDLE sysfont;
63 static int row_height;
64 static HANDLE bm_spin, bm_rtarrow, bm_checkyes, bm_checkno, bm_checkna;
73 { "Current", 7, 0, 0 },
79 { "Package", 7, 0, 0 },
83 #define NUM_COLUMNS (sizeof(headers)/(sizeof(headers[0]))-1)
85 int *package_indexes, nindexes;
87 struct ExtraPackageInfo {
88 char *installed_file; /* filename of previous "install" file */
89 char *installed_ver; /* version part */
90 int installed_size; /* ditto, size. */
95 int which_is_installed; /* == TRUST* or -1 */
99 int trust; /* may be keep or uninstall */
100 char *caption; /* ==0 at EOL */
101 } chooser[NTRUST+3]; /* one extra for NULL above */
104 static ExtraPackageInfo *extra;
113 hdc = BeginPaint (hwnd, &ps);
115 SelectObject (hdc, sysfont);
118 GetClientRect (hwnd, &cr);
122 x = cr.left - scroll_ulc_x;
123 y = cr.top - scroll_ulc_y + header_height;
126 for (i=0; headers[i].text; i++)
128 TextOut (hdc, x+headers[i].x, 3, headers[i].text, headers[i].slen);
129 MoveToEx (hdc, x+headers[i].x, header_height-3, &p);
130 LineTo (hdc, x+headers[i].x+headers[i].width, header_height-3);
133 IntersectClipRect (hdc, cr.left, cr.top+header_height, cr.right, cr.bottom);
135 for (ii=0; ii<nindexes; ii++)
137 i = package_indexes[ii];
138 int r = y + ii * row_height;
139 int by = r + tm.tmHeight - 11;
140 if (extra[i].installed_ver && extra[i].installed_ver[0])
142 TextOut (hdc, x+headers[CURRENT_COL].x, r,
143 extra[i].installed_ver, strlen (extra[i].installed_ver));
144 SelectObject (bitmap_dc, bm_rtarrow);
145 BitBlt (hdc, x+headers[CURRENT_COL].x+headers[0].width+ICON_MARGIN/2+HMARGIN/2, by,
146 11, 11, bitmap_dc, 0, 0, SRCCOPY);
149 char *s = extra[i].chooser[extra[i].pick].caption;
152 TextOut (hdc, x+headers[NEW_COL].x + 11 + ICON_MARGIN, r,
154 if (extra[i].npick > 1)
156 SelectObject (bitmap_dc, bm_spin);
157 BitBlt (hdc, x+headers[NEW_COL].x, by, 11, 11,
158 bitmap_dc, 0, 0, SRCCOPY);
162 HANDLE check_bm = bm_checkna;
163 if (extra[i].chooser[extra[i].pick].src_avail)
165 if (package[i].srcaction == SRCACTION_NO)
166 check_bm = bm_checkno;
167 else if (package[i].srcaction == SRCACTION_YES)
168 check_bm = bm_checkyes;
170 SelectObject (bitmap_dc, check_bm);
171 BitBlt (hdc, x+headers[SRC_COL].x, by, 11, 11,
172 bitmap_dc, 0, 0, SRCCOPY);
175 TextOut (hdc, x+headers[PACKAGE_COL].x, r, package[i].name, strlen(package[i].name));
180 static char *m = "Nothing to Install/Update";
181 TextOut (hdc, HMARGIN, header_height, m, strlen (m));
184 EndPaint (hwnd, &ps);
188 scroll_common (HWND hwnd, int which, int *var, int code)
191 si.cbSize = sizeof (si);
193 GetScrollInfo (hwnd, which, &si);
198 si.nPos = si.nTrackPos;
200 case SB_THUMBPOSITION:
209 si.nPos += row_height;
212 si.nPos -= row_height;
215 si.nPos += si.nPage * 9/10;
218 si.nPos -= si.nPage * 9/10;
222 if ((int)si.nPos < 0)
224 if ((int)(si.nPos + si.nPage) > si.nMax)
225 si.nPos = si.nMax - si.nPage;
228 SetScrollInfo (hwnd, which, &si, TRUE);
230 int ox = scroll_ulc_x;
231 int oy = scroll_ulc_y;
235 GetClientRect (hwnd, &cr);
237 sr.top += header_height;
238 ScrollWindow (hwnd, ox - scroll_ulc_x, oy - scroll_ulc_y, &sr, &sr);
241 ScrollWindow (hwnd, ox - scroll_ulc_x, 0, &sr, &sr);
244 static LRESULT CALLBACK
245 list_vscroll (HWND hwnd, HWND hctl, UINT code, int pos)
247 scroll_common (hwnd, SB_VERT, &scroll_ulc_y, code);
251 static LRESULT CALLBACK
252 list_hscroll (HWND hwnd, HWND hctl, UINT code, int pos)
254 scroll_common (hwnd, SB_HORZ, &scroll_ulc_x, code);
258 static LRESULT CALLBACK
259 list_click (HWND hwnd, BOOL dblclk, int x, int y, UINT hitCode)
266 if (y < header_height)
269 y += scroll_ulc_y - header_height;
271 r = (y + ROW_MARGIN/2) / row_height;
273 if (r < 0 || r >= npackages)
276 int p = package_indexes[r];
278 if (x >= headers[NEW_COL].x - HMARGIN/2 && x <= headers[NEW_COL+1].x - HMARGIN/2)
281 if (extra[p].chooser[extra[p].pick].caption == 0)
285 if (x >= headers[SRC_COL].x - HMARGIN/2 && x <= headers[SRC_COL+1].x - HMARGIN/2)
287 if (extra[p].chooser[extra[p].pick].src_avail)
288 package[p].srcaction ^= (SRCACTION_NO^SRCACTION_YES);
292 rect.left = headers[NEW_COL].x - scroll_ulc_x;
293 rect.right = headers[SRC_COL+1].x - scroll_ulc_x;
294 rect.top = header_height + r * row_height - scroll_ulc_y;
295 rect.bottom = rect.top + row_height;
296 InvalidateRect (hwnd, &rect, TRUE);
300 static LRESULT CALLBACK
301 listview_proc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
305 return HANDLE_WM_HSCROLL (hwnd, wParam, lParam, list_hscroll);
307 return HANDLE_WM_VSCROLL (hwnd, wParam, lParam, list_vscroll);
309 return HANDLE_WM_LBUTTONDOWN (hwnd, wParam, lParam, list_click);
314 return DefWindowProc (hwnd, message, wParam, lParam);
319 register_windows (HINSTANCE hinst)
328 memset (&wcex, 0, sizeof (wcex));
329 wcex.cbSize = sizeof (WNDCLASSEX);
330 wcex.style = CS_HREDRAW | CS_VREDRAW;
331 wcex.lpfnWndProc = listview_proc;
332 wcex.hInstance = hinst;
333 wcex.hIcon = LoadIcon (0, IDI_APPLICATION);
334 wcex.hCursor = LoadCursor (0, IDC_ARROW);
335 wcex.hbrBackground = (HBRUSH) (COLOR_WINDOW+1);
336 wcex.lpszClassName = "listview";
338 RegisterClassEx (&wcex);
342 note_width (HDC dc, char *string, int addend, int column)
347 GetTextExtentPoint32 (dc, string, strlen (string), &s);
348 if (headers[column].width < s.cx + addend)
349 headers[column].width = s.cx + addend;
353 best_trust (int p, int trust)
356 for (t=trust; t>=0; t--)
357 if (package[p].info[t].install)
359 for (t=trust+1; t<=NTRUST; t++)
360 if (package[p].info[t].install)
362 if (extra[p].installed_file)
368 default_trust (HWND h, int trust)
372 for (i=0; i<npackages; i++)
374 t = best_trust (i, trust);
376 for (c=0; c<extra[i].npick; c++)
377 if (t == extra[i].chooser[c].trust)
379 if (install_type == IDC_INSTALL_NATIVE
380 && package[i].type == TY_CYGWIN
382 install_type == IDC_INSTALL_CYGWIN
383 && package[i].type == TY_NATIVE)
384 extra[i].pick = extra[i].npick -1;
387 GetClientRect (h, &r);
388 InvalidateRect (h, &r, TRUE);
390 SetFocus (nextbutton);
394 set_full_list (HWND h, int isfull)
398 if (package_indexes == 0)
399 package_indexes = (int *) malloc (npackages * sizeof (int));
400 for (i=j=0; i<npackages; i++)
402 if (isfull || extra[i].in_partial_list)
403 package_indexes[j++] = i;
408 GetClientRect (h, &r);
410 memset (&si, 0, sizeof (si));
411 si.cbSize = sizeof (si);
414 si.nMax = headers[2].x + headers[2].width + HMARGIN;
416 SetScrollInfo (h, SB_HORZ, &si, TRUE);
418 si.nMax = nindexes * row_height;
419 si.nPage = r.bottom - header_height;
420 SetScrollInfo (h, SB_VERT, &si, TRUE);
422 scroll_ulc_x = scroll_ulc_y = 0;
424 InvalidateRect (h, &r, TRUE);
427 SetFocus (nextbutton);
434 for (i=0; i<npackages; i++)
438 #define C extra[i].chooser[c]
439 if (extra[i].installed_ver)
441 C.caption = "Uninstall";
442 C.trust = TRUST_UNINSTALL;
445 C.trust = TRUST_KEEP;
449 for (t=TRUST_PREV; t<NTRUST; t++)
450 if (package[i].info[t].install)
451 if (t != extra[i].which_is_installed)
453 C.caption = package[i].info[t].version;
454 if (C.caption == 0 || C.caption[0] == 0)
457 if (package[i].info[t].source)
460 /* we intentionally skip TRUST_PREV */
461 if (t != TRUST_PREV || !extra[i].installed_ver)
462 extra[i].in_partial_list = 1;
469 C.trust = TRUST_NONE;
473 if (! extra[i].installed_file)
476 C.trust = TRUST_NONE;
487 create_listview (HWND dlg, RECT *r)
490 lv = CreateWindowEx (WS_EX_CLIENTEDGE,
493 WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE,
495 r->right-r->left+1, r->bottom-r->top+1,
497 NULL, // ??? MAKEINTRESOURCE(IDC_CHOOSE_LIST),
500 ShowWindow (lv, SW_SHOW);
502 for (i=0; headers[i].text; i++)
503 headers[i].width = 0;
506 sysfont = GetStockObject (DEFAULT_GUI_FONT);
507 SelectObject (dc, sysfont);
508 GetTextMetrics (dc, &tm);
509 header_height = tm.tmHeight + 5 + 3;
511 bitmap_dc = CreateCompatibleDC (dc);
513 row_height = (tm.tmHeight + tm.tmExternalLeading + ROW_MARGIN);
514 int irh = tm.tmExternalLeading + tm.tmDescent + 11 + ROW_MARGIN;
515 if (row_height < irh)
518 for (i=0; headers[i].text; i++)
519 note_width (dc, headers[i].text, 0, i);
520 for (i=0; i<npackages; i++)
522 note_width (dc, extra[i].installed_ver, 0, CURRENT_COL);
523 note_width (dc, extra[i].installed_ver, 11+ICON_MARGIN, NEW_COL);
524 for (t=0; t<NTRUST; t++)
525 note_width (dc, package[i].info[t].version, 11+ICON_MARGIN, NEW_COL);
526 note_width (dc, package[i].name, 0, PACKAGE_COL);
527 note_width (dc, package[i].sdesc, 0, PACKAGE_COL);
529 note_width (dc, "keep", 11+ICON_MARGIN, NEW_COL);
530 note_width (dc, "uninstall", 11+ICON_MARGIN, NEW_COL);
532 headers[CURRENT_COL].x = HMARGIN/2;
533 headers[NEW_COL].x = (headers[CURRENT_COL].x + headers[CURRENT_COL].width
534 + HMARGIN + 11 + ICON_MARGIN);
535 headers[SRC_COL].x = headers[NEW_COL].x + headers[NEW_COL].width + HMARGIN;
536 headers[PACKAGE_COL].x = headers[SRC_COL].x + headers[SRC_COL].width + HMARGIN;
538 set_full_list (lv, full_list);
539 default_trust (lv, TRUST_CURR);
545 dialog_cmd (HWND h, int id, HWND hwndctl, UINT code)
550 case IDC_CHOOSE_PREV:
551 default_trust (lv, TRUST_PREV);
553 case IDC_CHOOSE_CURR:
554 default_trust (lv, TRUST_CURR);
557 default_trust (lv, TRUST_TEST);
559 case IDC_CHOOSE_FULLPART:
560 set_full_list (lv, !full_list);
564 if (source == IDC_SOURCE_CWD)
565 NEXT (IDD_S_INSTALL);
567 NEXT (IDD_S_DOWNLOAD);
572 if (source == IDC_SOURCE_CWD)
586 GetParentRect (HWND parent, HWND child, RECT *r)
589 GetWindowRect (child, r);
592 ScreenToClient (parent, &p);
597 ScreenToClient (parent, &p);
603 dialog_proc (HWND h, UINT message, WPARAM wParam, LPARAM lParam)
610 nextbutton = GetDlgItem (h, IDOK);
611 frame = GetDlgItem (h, IDC_LISTVIEW_POS);
612 GetParentRect (h, frame, &r);
615 create_listview (h, &r);
621 return HANDLE_WM_COMMAND (h, wParam, lParam, dialog_cmd);
634 if ((*s == '/' || *s == ':' || *s == '\\') && s[1])
642 scan2 (char *path, unsigned int size)
645 for (i=0; i<npackages; i++)
646 for (t=0; t<NTRUST; t++)
647 if (package[i].info[t].install
648 && strcmp (base (package[i].info[t].install), base (path)) == 0
649 && package[i].info[t].install_size == (int)size)
651 extra[i].installed_file = package[i].info[t].install;
652 extra[i].installed_size = size;
653 extra[i].which_is_installed = t;
654 extra[i].installed_ver = package[i].info[t].version;
655 if (!extra[i].installed_ver)
656 extra[i].installed_ver = "0";
661 scan_downloaded_files ()
673 char line[1000], pkg[1000], inst[1000], src[1000];
676 FILE *db = fopen (concat (root_dir, XEMACS_SETUP_DIR, "installed.db", 0), "rt");
680 while (fgets (line, 1000, db))
684 sscanf (line, "%s %s %d %s %d", pkg, inst, &instsz, src, &srcsz);
686 for (i=0; i<npackages; i++)
687 if (strcmp (package[i].name, pkg) == 0)
690 extra[i].installed_file = inst;
691 extra[i].installed_size = instsz;
693 for (t=0; t<NTRUST; t++)
694 if (package[i].info[t].install
695 && strcmp (base (package[i].info[t].install), base (inst)) == 0)
697 extra[i].which_is_installed = t;
698 extra[i].installed_ver = package[i].info[t].version;
702 if (extra[i].installed_ver == 0) /* still */
705 for (v=base (inst); *v; v++)
706 if (*v == '-' && isdigit(v[1]))
714 if (strncmp (d, ".tar", 4) == 0
715 || strncmp (d, "-pkg", 4) == 0)
721 extra[i].installed_ver = strdup (v);
723 extra[i].installed_ver = "0";
732 package_sort (const void *va, const void *vb)
734 Package *a = (Package *)va;
735 Package *b = (Package *)vb;
736 return strcmp (a->name, b->name);
740 do_choose (HINSTANCE h)
744 qsort (package, npackages, sizeof (package[0]), package_sort);
747 bm_spin = LoadImage (h, MAKEINTRESOURCE (IDB_SPIN), IMAGE_BITMAP, 0, 0, 0);
748 bm_rtarrow = LoadImage (h, MAKEINTRESOURCE (IDB_RTARROW), IMAGE_BITMAP, 0, 0, 0);
750 bm_checkyes = LoadImage (h, MAKEINTRESOURCE (IDB_CHECK_YES), IMAGE_BITMAP, 0, 0, 0);
751 bm_checkno = LoadImage (h, MAKEINTRESOURCE (IDB_CHECK_NO), IMAGE_BITMAP, 0, 0, 0);
752 bm_checkna = LoadImage (h, MAKEINTRESOURCE (IDB_CHECK_NA), IMAGE_BITMAP, 0, 0, 0);
754 extra = (ExtraPackageInfo *) malloc (npackages * sizeof (ExtraPackageInfo));
755 memset (extra, 0, npackages * sizeof (ExtraPackageInfo));
756 for (i=0; i<npackages; i++)
757 extra[i].which_is_installed = -1;
759 register_windows (h);
761 if (source == IDC_SOURCE_DOWNLOAD)
762 scan_downloaded_files ();
764 read_installed_db ();
767 rv = DialogBox (h, MAKEINTRESOURCE (IDD_CHOOSE), 0, dialog_proc);
769 fatal (IDS_DIALOG_FAILED);
771 for (i=0; i<npackages; i++)
773 switch (extra[i].chooser[extra[i].pick].trust)
778 if (extra[i].installed_file)
779 package[i].action = ACTION_UPGRADE;
781 package[i].action = ACTION_NEW;
782 package[i].trust = extra[i].chooser[extra[i].pick].trust;
783 // pick up the actual core package to install
784 if (package[i].type == TY_CYGWIN || package[i].type == TY_NATIVE
785 && xemacs_package == 0)
786 xemacs_package = &package[i];
789 case TRUST_UNINSTALL:
790 package[i].action = ACTION_UNINSTALL;
796 package[i].action = ACTION_SAME;
801 log (LOG_BABBLE, "Chooser results...");
802 for (i=0; i<npackages; i++)
804 static char *infos[] = {"prev", "curr", "test"};
805 const char *trust = ((package[i].trust == TRUST_PREV) ? "prev"
806 : (package[i].trust == TRUST_CURR) ? "curr"
807 : (package[i].trust == TRUST_TEST) ? "test"
809 const char *action = ((package[i].action == ACTION_UNKNOWN) ? "unknown"
810 : (package[i].action == ACTION_SAME) ? "same"
811 : (package[i].action == ACTION_NEW) ? "new"
812 : (package[i].action == ACTION_UPGRADE) ? "upgrade"
813 : (package[i].action == ACTION_UNINSTALL) ? "uninstall"
814 : (package[i].action == ACTION_ERROR) ? "error"
817 log (LOG_BABBLE, "[%s] action=%s trust=%s src? %s", package[i].name, action, trust,
818 package[i].srcaction == SRCACTION_NO ? "no" : "yes");
819 for (int t=0; t<NTRUST; t++)
821 if (package[i].info[t].install)
822 log (LOG_BABBLE, "[%s] ver %s inst %s %d src %s %d",
824 package[i].info[t].version ? package[i].info[t].version : "(none)",
825 package[i].info[t].install ? package[i].info[t].install : "(none)",
826 package[i].info[t].install_size,
827 package[i].info[t].source ? package[i].info[t].source : "(none)",
828 package[i].info[t].source_size);