2 * Copyright (c) 2000, 2001 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
29 static const char *cvsid
=
49 #include "filemanip.h"
50 #include "io_stream.h"
51 #include "propsheet.h"
55 #include "package_db.h"
56 #include "package_meta.h"
57 #include "package_version.h"
61 extern ThreeBarProgressPage Progress
;
63 #define alloca __builtin_alloca
68 #define RTARROW_WIDTH 11
70 #define NEW_COL_SIZE_SLOP (ICON_MARGIN + SPIN_WIDTH + RTARROW_WIDTH)
74 static int initialized
= 0;
76 static int scroll_ulc_x
, scroll_ulc_y
;
78 static HWND lv
, nextbutton
, choose_inst_text
;
80 static int header_height
;
81 static HANDLE sysfont
;
82 static int row_height
;
83 static HANDLE bm_spin
, bm_rtarrow
, bm_checkyes
, bm_checkno
, bm_checkna
;
85 static view
*chooser
= NULL
;
86 static trusts deftrust
= TRUST_UNKNOWN
;
88 static struct _header pkg_headers
[] = {
92 {"Category", 8, 0, 0},
97 static struct _header cat_headers
[] = {
98 {"Category", 8, 0, 0},
102 {"Package", 7, 0, 0},
106 static void set_view_mode (HWND h
, views mode
);
109 pkgtrustp (packagemeta
const &pkg
, trusts
const t
)
111 return t
== TRUST_PREV
? (pkg
.prev
? pkg
.prev
: (pkg
.curr
? pkg
.curr
: pkg
.installed
))
112 : t
== TRUST_CURR
? (pkg
.curr
? pkg
.curr
: pkg
.installed
)
117 add_required (packagemeta
& pkg
, size_t depth
= 0)
120 packagemeta
*required
;
123 || (pkg
.desired
!= pkg
.installed
&& !pkg
.desired
->binpicked
))
124 /* uninstall || source only */
127 dp
= pkg
.desired
->required
;
129 /* cheap test for too much recursion */
134 if ((required
= db
.packages
.getbykey (dp
->package
)) == NULL
)
140 if (!required
->desired
)
142 /* it's set to uninstall */
143 required
->set_action (pkgtrustp (*required
, deftrust
));
145 else if (required
->desired
!= required
->installed
146 && !required
->desired
->binpicked
)
148 /* it's set to change to a different version source only */
149 required
->desired
->binpicked
= 1;
151 /* does this requirement have requirements? */
152 changed
+= add_required (*required
, depth
+ 1);
159 topbucket::paint (HDC hdc
, int x
, int y
, int row
, int show_cat
)
162 for (size_t n
= 1; n
<= bucket
.number (); n
++)
164 bucket
[n
]->paint (hdc
, x
, y
, accum_row
, show_cat
);
165 accum_row
+= bucket
[n
]->itemcount ();
170 topbucket::empty (void)
172 while (bucket
.number ())
174 pick_line
*line
= bucket
.removebyindex (1);
179 topbucket::~topbucket (void)
185 topbucket::click (int const myrow
, int const ClickedRow
, int const x
)
187 int accum_row
= myrow
;
188 for (size_t n
= 1; n
<= bucket
.number (); n
++)
190 accum_row
+= bucket
[n
]->itemcount ();
191 if (accum_row
> ClickedRow
)
192 return bucket
[n
]->click (accum_row
- bucket
[n
]->itemcount (),
205 hdc
= BeginPaint (hwnd
, &ps
);
207 SelectObject (hdc
, sysfont
);
208 SetBkColor (hdc
, GetSysColor (COLOR_WINDOW
));
209 SetTextColor (hdc
, GetSysColor (COLOR_WINDOWTEXT
));
212 GetClientRect (hwnd
, &cr
);
214 x
= cr
.left
- scroll_ulc_x
;
215 y
= cr
.top
- scroll_ulc_y
+ header_height
;
217 IntersectClipRect (hdc
, cr
.left
, cr
.top
+ header_height
, cr
.right
,
220 chooser
->contents
.paint (hdc
, x
, y
, 0, (chooser
->get_view_mode () ==
221 VIEW_CATEGORY
) ? 0 : 1);
223 if (chooser
->contents
.itemcount () == 0)
225 static const char *msg
= "Nothing to Install/Update";
226 if (source
== IDC_SOURCE_DOWNLOAD
)
227 msg
= "Nothing to Download";
228 TextOut (hdc
, HMARGIN
, header_height
, msg
, strlen (msg
));
231 EndPaint (hwnd
, &ps
);
235 view::scroll (HWND hwnd
, int which
, int *var
, int code
)
238 si
.cbSize
= sizeof (si
);
240 GetScrollInfo (hwnd
, which
, &si
);
245 si
.nPos
= si
.nTrackPos
;
247 case SB_THUMBPOSITION
:
256 si
.nPos
+= row_height
;
259 si
.nPos
-= row_height
;
262 si
.nPos
+= si
.nPage
* 9 / 10;
265 si
.nPos
-= si
.nPage
* 9 / 10;
269 if ((int) si
.nPos
< 0)
271 if (si
.nPos
+ si
.nPage
> (unsigned int) si
.nMax
)
272 si
.nPos
= si
.nMax
- si
.nPage
;
275 SetScrollInfo (hwnd
, which
, &si
, TRUE
);
277 int ox
= scroll_ulc_x
;
278 int oy
= scroll_ulc_y
;
282 GetClientRect (hwnd
, &cr
);
284 sr
.top
+= header_height
;
286 ScrollWindow (hwnd
, ox
- scroll_ulc_x
, oy
- scroll_ulc_y
, &sr
, &sr
);
290 ScrollWindow (hwnd, ox - scroll_ulc_x, 0, &sr, &sr);
292 if (ox
- scroll_ulc_x
)
294 GetClientRect (listheader
, &cr
);
296 // UpdateWindow (htmp);
297 MoveWindow (listheader
, -scroll_ulc_x
, 0,
298 chooser
->headers
[last_col
].x
+
299 chooser
->headers
[last_col
].width
, header_height
, TRUE
);
304 static LRESULT CALLBACK
305 list_vscroll (HWND hwnd
, HWND hctl
, UINT code
, int pos
)
307 chooser
->scroll (hwnd
, SB_VERT
, &scroll_ulc_y
, code
);
311 static LRESULT CALLBACK
312 list_hscroll (HWND hwnd
, HWND hctl
, UINT code
, int pos
)
314 chooser
->scroll (hwnd
, SB_HORZ
, &scroll_ulc_x
, code
);
318 static LRESULT CALLBACK
319 list_click (HWND hwnd
, BOOL dblclk
, int x
, int y
, UINT hitCode
)
323 if (chooser
->contents
.itemcount () == 0)
326 if (y
< header_height
)
329 y
+= scroll_ulc_y
- header_height
;
331 row
= (y
+ ROW_MARGIN
/ 2) / row_height
;
333 if (row
< 0 || row
>= chooser
->contents
.itemcount ())
336 refresh
= chooser
->click (row
, x
);
341 GetClientRect (lv
, &r
);
343 memset (&si
, 0, sizeof (si
));
344 si
.cbSize
= sizeof (si
);
345 si
.fMask
= SIF_ALL
; /* SIF_RANGE was giving strange behaviour */
348 si
.nMax
= chooser
->contents
.itemcount () * row_height
;
349 si
.nPage
= r
.bottom
- header_height
;
351 /* if we are under the minimum display count ,
352 * set the offset to 0
354 if ((unsigned int) si
.nMax
<= si
.nPage
)
356 si
.nPos
= scroll_ulc_y
;
358 SetScrollInfo (lv
, SB_VERT
, &si
, TRUE
);
360 InvalidateRect (lv
, &r
, TRUE
);
366 rect
.left
= chooser
->headers
[chooser
->new_col
].x
- scroll_ulc_x
;
367 rect
.right
= chooser
->headers
[chooser
->src_col
+ 1].x
- scroll_ulc_x
;
368 rect
.top
= header_height
+ row
* row_height
- scroll_ulc_y
;
369 rect
.bottom
= rect
.top
+ row_height
;
370 InvalidateRect (hwnd
, &rect
, TRUE
);
375 static LRESULT CALLBACK
376 listview_proc (HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
381 return HANDLE_WM_HSCROLL (hwnd
, wParam
, lParam
, list_hscroll
);
383 return HANDLE_WM_VSCROLL (hwnd
, wParam
, lParam
, list_vscroll
);
385 return HANDLE_WM_LBUTTONDOWN (hwnd
, wParam
, lParam
, list_click
);
391 // pnmh = (LPNMHDR) lParam
392 LPNMHEADER phdr
= (LPNMHEADER
) lParam
;
393 switch (phdr
->hdr
.code
)
395 case HDN_ITEMCHANGED
:
396 if (phdr
->hdr
.hwndFrom
== chooser
->ListHeader ())
398 if (phdr
->pitem
&& phdr
->pitem
->mask
& HDI_WIDTH
)
399 chooser
->headers
[phdr
->iItem
].width
= phdr
->pitem
->cxy
;
400 for (int i
= 1; i
<= chooser
->last_col
; i
++)
401 chooser
->headers
[i
].x
=
402 chooser
->headers
[i
- 1].x
+ chooser
->headers
[i
- 1].width
;
404 GetClientRect (hwnd
, &r
);
406 si
.cbSize
= sizeof (si
);
408 GetScrollInfo (hwnd
, SB_HORZ
, &si
);
409 int oldMax
= si
.nMax
;
411 chooser
->headers
[chooser
->last_col
].x
+
412 chooser
->headers
[chooser
->last_col
].width
;
413 if (si
.nTrackPos
&& oldMax
> si
.nMax
)
414 si
.nTrackPos
+= si
.nMax
- oldMax
;
416 SetScrollInfo (hwnd
, SB_HORZ
, &si
, TRUE
);
417 InvalidateRect (hwnd
, &r
, TRUE
);
418 if (si
.nTrackPos
&& oldMax
> si
.nMax
)
419 chooser
->scroll (hwnd
, SB_HORZ
, &scroll_ulc_x
,
428 return DefWindowProc (hwnd
, message
, wParam
, lParam
);
433 register_windows (HINSTANCE hinst
)
442 memset (&wcex
, 0, sizeof (wcex
));
443 wcex
.cbSize
= sizeof (WNDCLASSEX
);
444 wcex
.style
= CS_HREDRAW
| CS_VREDRAW
;
445 wcex
.lpfnWndProc
= listview_proc
;
446 wcex
.hInstance
= hinst
;
447 wcex
.hIcon
= LoadIcon (0, IDI_APPLICATION
);
448 wcex
.hCursor
= LoadCursor (0, IDC_ARROW
);
449 wcex
.hbrBackground
= (HBRUSH
) (COLOR_WINDOW
+ 1);
450 wcex
.lpszClassName
= "listview";
452 RegisterClassEx (&wcex
);
456 note_width (struct _header
*hdrs
, HDC dc
, const char *string
, int addend
,
461 if (hdrs
[column
].width
< addend
)
462 hdrs
[column
].width
= addend
;
466 GetTextExtentPoint32 (dc
, string
, strlen (string
), &s
);
467 if (hdrs
[column
].width
< s
.cx
+ addend
)
468 hdrs
[column
].width
= s
.cx
+ addend
;
475 /* Remove packages that are in the db, not installed, and have no
478 while (n
<= db
.packages
.number ())
480 packagemeta
& pkg
= *db
.packages
[n
];
481 bool mirrors
= false;
483 while (o
<= pkg
.versions
.number () && !mirrors
)
485 packageversion
& ver
= *pkg
.versions
[o
];
486 if (ver
.bin
.sites
.number () || ver
.bin
.Cached () ||
487 ver
.src
.sites
.number () || ver
.src
.Cached ())
491 if (!pkg
.installed
&& !mirrors
)
493 packagemeta
* pkgm
= db
.packages
.removebyindex (n
);
502 fill_missing_category ()
505 for (size_t n
= 1; n
<= db
.packages
.number (); n
++)
507 packagemeta
& pkg
= *db
.packages
[n
];
508 if (!pkg
.Categories
.number ())
509 pkg
.add_category (db
.categories
.registerbykey ("Misc"));
510 pkg
.add_category (db
.categories
.registerbykey ("All"));
515 default_trust (HWND h
, trusts trust
)
519 for (size_t n
= 1; n
<= db
.packages
.number (); n
++)
521 packagemeta
& pkg
= *db
.packages
[n
];
523 || pkg
.Categories
.getbykey (db
.categories
.registerbykey ("Base"))
524 || pkg
.Categories
.getbykey (db
.categories
.registerbykey ("Misc")))
526 pkg
.desired
= pkgtrustp (pkg
, trust
);
529 pkg
.desired
->binpicked
= pkg
.desired
== pkg
.installed
? 0 : 1;
530 pkg
.desired
->srcpicked
= 0;
537 GetClientRect (h
, &r
);
538 InvalidateRect (h
, &r
, TRUE
);
540 SetFocus (nextbutton
);
541 // and then do the same for categories with no packages.
543 while (n
<= db
.categories
.number ())
545 if (!db
.categories
[n
]->packages
)
547 Category
* cat
= db
.categories
.removebyindex (n
);
556 pick_pkg_line::paint (HDC hdc
, int x
, int y
, int row
, int show_cat
)
558 int r
= y
+ row
* row_height
;
559 int by
= r
+ tm
.tmHeight
- 11;
560 int oldDC
= SaveDC (hdc
);
563 HRGN oldClip
= CreateRectRgn (0, 0, 0, 0);
564 if (GetRandomRgn (hdc
, oldClip
, SYSRGN
) == -1)
566 RestoreDC (hdc
, oldDC
);
569 unsigned int regionsize
= GetRegionData (oldClip
, 0, 0);
570 LPRGNDATA oldClipData
= (LPRGNDATA
) malloc (regionsize
);
571 if (GetRegionData (oldClip
, regionsize
, oldClipData
) != regionsize
)
573 RestoreDC (hdc
, oldDC
);
574 DeleteObject (oldClip
);
577 for (unsigned int n
= 0; n
< oldClipData
->rdh
.nCount
; n
++)
578 for (unsigned int t
= 0; t
< 2; t
++)
579 ScreenToClient (WindowFromDC (hdc
),
580 &((POINT
*) oldClipData
->Buffer
)[t
+ n
* 2]);
582 HRGN oldClip2
= ExtCreateRegion (NULL
, regionsize
, oldClipData
);
583 SelectClipRgn (hdc
, oldClip2
);
586 IntersectClipRect (hdc
, x
+ chooser
->headers
[chooser
->current_col
].x
,
588 x
+ chooser
->headers
[chooser
->current_col
].x
+
589 chooser
->headers
[chooser
->current_col
].width
,
592 x
+ chooser
->headers
[chooser
->current_col
].x
+ HMARGIN
/ 2, r
,
593 pkg
.installed
->Canonical_version (),
594 strlen (pkg
.installed
->Canonical_version ()));
595 SelectObject (bitmap_dc
, bm_rtarrow
);
596 BitBlt (hdc
, x
+ chooser
->headers
[chooser
->new_col
].x
+ HMARGIN
/ 2,
597 by
, 11, 11, bitmap_dc
, 0, 0, SRCCOPY
);
598 SelectClipRgn (hdc
, oldClip2
);
601 const char *s
= pkg
.action_caption ();
602 IntersectClipRect (hdc
, x
+ chooser
->headers
[chooser
->new_col
].x
,
604 x
+ chooser
->headers
[chooser
->new_col
].x
+
605 chooser
->headers
[chooser
->new_col
].width
, by
+ 11);
607 x
+ chooser
->headers
[chooser
->new_col
].x
+ HMARGIN
/ 2 +
608 NEW_COL_SIZE_SLOP
, r
, s
, strlen (s
));
609 SelectObject (bitmap_dc
, bm_spin
);
611 x
+ chooser
->headers
[chooser
->new_col
].x
+ ICON_MARGIN
/ 2 +
612 RTARROW_WIDTH
+ HMARGIN
/ 2, by
, 11, 11, bitmap_dc
, 0, 0, SRCCOPY
);
613 SelectClipRgn (hdc
, oldClip2
);
616 if ( /* uninstall */ !pkg
.desired
||
617 /* source only */ (!pkg
.desired
->binpicked
618 && pkg
.desired
->srcpicked
) ||
619 /* when no source mirror available */
620 !pkg
.desired
->src
.sites
.number ())
621 check_bm
= bm_checkna
;
622 else if (pkg
.desired
->srcpicked
)
623 check_bm
= bm_checkyes
;
625 check_bm
= bm_checkno
;
627 SelectObject (bitmap_dc
, check_bm
);
628 IntersectClipRect (hdc
, x
+ chooser
->headers
[chooser
->src_col
].x
, by
,
629 x
+ chooser
->headers
[chooser
->src_col
].x
+
630 chooser
->headers
[chooser
->src_col
].width
, by
+ 11);
631 BitBlt (hdc
, x
+ chooser
->headers
[chooser
->src_col
].x
+ HMARGIN
/ 2, by
, 11,
632 11, bitmap_dc
, 0, 0, SRCCOPY
);
633 SelectClipRgn (hdc
, oldClip2
);
635 /* shows "first" category - do we want to show any? */
636 if (pkg
.Categories
.number () && show_cat
)
638 IntersectClipRect (hdc
, x
+ chooser
->headers
[chooser
->cat_col
].x
, by
,
639 x
+ chooser
->headers
[chooser
->cat_col
].x
+
640 chooser
->headers
[chooser
->cat_col
].x
, by
+ 11);
641 TextOut (hdc
, x
+ chooser
->headers
[chooser
->cat_col
].x
+ HMARGIN
/ 2, r
,
642 pkg
.Categories
[1]->key
.name
,
643 strlen (pkg
.Categories
[1]->key
.name
));
644 SelectClipRgn (hdc
, oldClip2
);
651 static char buf
[512];
652 strcpy (buf
, pkg
.name
);
654 strcat (buf
, pkg
.SDesc ());
657 IntersectClipRect (hdc
, x
+ chooser
->headers
[chooser
->pkg_col
].x
, by
,
658 x
+ chooser
->headers
[chooser
->pkg_col
].x
+
659 chooser
->headers
[chooser
->pkg_col
].width
, by
+ 11);
660 TextOut (hdc
, x
+ chooser
->headers
[chooser
->pkg_col
].x
+ HMARGIN
/ 2, r
, s
,
662 DeleteObject (oldClip
);
663 DeleteObject (oldClip2
);
664 RestoreDC (hdc
, oldDC
);
668 pick_category_line::paint (HDC hdc
, int x
, int y
, int row
, int show_cat
)
670 int r
= y
+ row
* row_height
;
673 int by
= r
+ tm
.tmHeight
- 11;
674 TextOut (hdc
, x
+ chooser
->headers
[chooser
->cat_col
].x
+ HMARGIN
/ 2 + depth
* 8,
675 r
, cat
.name
, strlen (cat
.name
));
677 GetTextExtentPoint32 (hdc
, cat
.name
, strlen (cat
.name
), &s
);
678 SelectObject (bitmap_dc
, bm_spin
);
680 x
+ chooser
->headers
[chooser
->cat_col
].x
+
683 HMARGIN
/ 2, by
, 11, 11, bitmap_dc
, 0, 0, SRCCOPY
);
687 int accum_row
= row
+ (show_label
? 1 : 0);
688 for (size_t n
= 1; n
<= bucket
.number (); n
++)
690 bucket
[n
]->paint (hdc
, x
, y
, accum_row
, show_cat
);
691 accum_row
+= bucket
[n
]->itemcount ();
696 pick_pkg_line::click (int const myrow
, int const ClickedRow
, int const x
)
698 // assert (myrow == ClickedRow);
699 if (pkg
.desired
&& pkg
.desired
->src
.sites
.number ()
700 && x
>= chooser
->headers
[chooser
->src_col
].x
- HMARGIN
/ 2
701 && x
<= chooser
->headers
[chooser
->src_col
+ 1].x
- HMARGIN
/ 2)
702 pkg
.desired
->srcpicked
^= 1;
704 if (x
>= chooser
->headers
[chooser
->new_col
].x
- HMARGIN
/ 2
705 && x
<= chooser
->headers
[chooser
->new_col
+ 1].x
- HMARGIN
/ 2)
707 pkg
.set_action (pkgtrustp (pkg
, deftrust
));
708 /* Add any packages that are needed by this package */
709 return add_required (pkg
);
715 pick_category_line::click (int const myrow
, int const ClickedRow
, int const x
)
717 if (myrow
== ClickedRow
&& show_label
)
719 collapsed
= !collapsed
;
721 for (size_t n
= 1; n
<= bucket
.number (); n
++)
722 accum_row
+= bucket
[n
]->itemcount ();
723 return collapsed
? accum_row
: -accum_row
;
727 int accum_row
= myrow
+ (show_label
? 1 : 0);
728 for (size_t n
= 1; n
<= bucket
.number (); n
++)
730 if (accum_row
+ bucket
[n
]->itemcount () > ClickedRow
)
731 return bucket
[n
]->click (accum_row
, ClickedRow
, x
);
732 accum_row
+= bucket
[n
]->itemcount ();
738 HWND
DoCreateHeader (HWND hwndParent
);
740 view::view (views _mode
, HWND lv
, Category
&cat
) :
741 contents (cat
, 0, false, true), listview (lv
)
744 HDC dc
= GetDC (listview
);
745 sysfont
= GetStockObject (DEFAULT_GUI_FONT
);
746 SelectObject (dc
, sysfont
);
747 GetTextMetrics (dc
, &tm
);
749 bitmap_dc
= CreateCompatibleDC (dc
);
751 row_height
= (tm
.tmHeight
+ tm
.tmExternalLeading
+ ROW_MARGIN
);
760 if (row_height
< irh
)
767 // Ensure that the common control DLL is loaded, and then create
768 // the header control.
769 INITCOMMONCONTROLSEX controlinfo
=
771 sizeof (INITCOMMONCONTROLSEX
), ICC_LISTVIEW_CLASSES
};
772 InitCommonControlsEx (&controlinfo
);
774 if ((listheader
= CreateWindowEx (0, WC_HEADER
, (LPCTSTR
) NULL
,
775 WS_CHILD
| WS_BORDER
| CCS_NORESIZE
|
777 HDS_HORZ
, 0, 0, 0, 0, listview
,
778 (HMENU
) IDC_CHOOSE_LISTHEADER
, hinstance
,
779 (LPVOID
) NULL
)) == NULL
)
780 // FIXME: throw an exception
783 // Retrieve the bounding rectangle of the parent window's
784 // client area, and then request size and position values
785 // from the header control.
786 GetClientRect (listview
, &rcParent
);
790 if (!SendMessage (listheader
, HDM_LAYOUT
, 0, (LPARAM
) & hdl
))
791 // FIXME: throw an exception
795 // Set the size, position, and visibility of the header control.
796 SetWindowPos (listheader
, wp
.hwndInsertAfter
, wp
.x
, wp
.y
,
797 wp
.cx
, wp
.cy
, wp
.flags
| SWP_SHOWWINDOW
);
799 header_height
= wp
.cy
;
801 view_mode
= VIEW_PACKAGE
;
804 view_mode
= VIEW_CATEGORY
;
815 view::set_view_mode (views _mode
)
818 view_mode
= VIEW_PACKAGE_FULL
;
825 view::mode_caption ()
831 case VIEW_PACKAGE_FULL
:
842 int DoInsertItem (HWND hwndHeader
, int iInsertAfter
, int nWidth
, LPSTR lpsz
);
851 case VIEW_PACKAGE_FULL
:
853 headers
= pkg_headers
;
862 headers
= cat_headers
;
873 while (int n
= SendMessage (listheader
, HDM_GETITEMCOUNT
, 0, 0))
875 SendMessage (listheader
, HDM_DELETEITEM
, n
- 1, 0);
878 for (i
= 0; i
<= last_col
; i
++)
879 DoInsertItem (listheader
, i
, headers
[i
].width
, (char *) headers
[i
].text
);
884 view::init_headers (HDC dc
)
888 for (i
= 0; headers
[i
].text
; i
++)
890 headers
[i
].width
= 0;
894 for (i
= 0; headers
[i
].text
; i
++)
895 note_width (headers
, dc
, headers
[i
].text
, HMARGIN
, i
);
897 note_width (headers
, dc
, 0, HMARGIN
+ 11, src_col
);
899 for (size_t n
= 1; n
<= db
.packages
.number (); n
++)
901 packagemeta
& pkg
= *db
.packages
[n
];
903 note_width (headers
, dc
, pkg
.installed
->Canonical_version (),
904 HMARGIN
, current_col
);
905 for (size_t n
= 1; n
<= pkg
.versions
.number (); n
++)
906 if (pkg
.versions
[n
] != pkg
.installed
)
907 note_width (headers
, dc
,
908 pkg
.versions
[n
]->Canonical_version (),
909 NEW_COL_SIZE_SLOP
+ HMARGIN
, new_col
);
910 for (size_t n
= 1; n
<= db
.categories
.number (); n
++)
911 note_width (headers
, dc
, db
.categories
[n
]->name
, HMARGIN
, cat_col
);
913 note_width (headers
, dc
, pkg
.name
, HMARGIN
, pkg_col
);
916 static char buf
[512];
917 strcpy (buf
, pkg
.name
);
919 strcat (buf
, pkg
.SDesc ());
920 note_width (headers
, dc
, buf
, HMARGIN
, pkg_col
);
923 note_width (headers
, dc
, "keep", NEW_COL_SIZE_SLOP
+ HMARGIN
, new_col
);
924 note_width (headers
, dc
, "uninstall", NEW_COL_SIZE_SLOP
+ HMARGIN
, new_col
);
927 for (i
= 1; i
<= last_col
; i
++)
928 headers
[i
].x
= headers
[i
- 1].x
+ headers
[i
- 1].width
;
932 view::insert_pkg (packagemeta
& pkg
)
934 if (view_mode
!= VIEW_CATEGORY
)
936 pick_pkg_line
& line
= *new pick_pkg_line (pkg
);
937 contents
.insert (line
);
941 for (size_t x
= 1; x
<= pkg
.Categories
.number (); x
++)
943 Category
& cat
= pkg
.Categories
[x
]->key
;
944 // Special case - yuck
945 if (cat
== Category ("All"))
947 pick_category_line
& catline
= *new pick_category_line (cat
, 1);
948 pick_pkg_line
& line
= *new pick_pkg_line (pkg
);
949 catline
.insert (line
);
950 contents
.insert (catline
);
956 view::insert_category (Category
* cat
, bool collapsed
)
958 if (*cat
== Category ("All"))
960 pick_category_line
& catline
= *new pick_category_line (*cat
, 1, collapsed
);
961 for (CategoryPackage
* catpkg
= cat
->packages
; catpkg
;
962 catpkg
= catpkg
->next
)
965 pick_pkg_line
& line
= *new pick_pkg_line (*catpkg
->pkg
);
966 catline
.insert (line
);
968 contents
.insert (catline
);
972 view::clear_view (void)
979 case VIEW_PACKAGE_FULL
:
981 contents
.ShowLabel (false);
984 contents
.ShowLabel ();
992 viewsplusplus (views theview
)
997 return VIEW_PACKAGE_FULL
;
998 case VIEW_PACKAGE_FULL
:
1001 return VIEW_CATEGORY
;
1005 return VIEW_UNKNOWN
;
1010 view::click (int row
, int x
)
1012 return contents
.click (0, row
, x
);
1016 set_view_mode (HWND h
, views mode
)
1018 chooser
->set_view_mode (mode
);
1020 chooser
->clear_view ();
1022 switch (chooser
->get_view_mode ())
1025 for (size_t n
= 1; n
<= db
.packages
.number (); n
++)
1027 packagemeta
& pkg
= *db
.packages
[n
];
1028 if ((!pkg
.desired
&& pkg
.installed
)
1030 && (pkg
.desired
->srcpicked
|| pkg
.desired
->binpicked
)))
1031 chooser
->insert_pkg (pkg
);
1034 case VIEW_PACKAGE_FULL
:
1035 for (size_t n
= 1; n
<= db
.packages
.number (); n
++)
1037 packagemeta
& pkg
= *db
.packages
[n
];
1038 chooser
->insert_pkg (pkg
);
1042 /* start collapsed. TODO: make this a chooser flag */
1043 for (size_t n
= 1; n
<= db
.categories
.number (); n
++)
1044 chooser
->insert_category (db
.categories
[n
], CATEGORY_COLLAPSED
);
1051 GetClientRect (h
, &r
);
1053 memset (&si
, 0, sizeof (si
));
1054 si
.cbSize
= sizeof (si
);
1057 si
.nMax
= chooser
->headers
[chooser
->last_col
].x
+ chooser
->headers
[chooser
->last_col
].width
; // + HMARGIN;
1059 SetScrollInfo (h
, SB_HORZ
, &si
, TRUE
);
1061 si
.nMax
= chooser
->contents
.itemcount () * row_height
;
1062 si
.nPage
= r
.bottom
- header_height
;
1063 SetScrollInfo (h
, SB_VERT
, &si
, TRUE
);
1065 scroll_ulc_x
= scroll_ulc_y
= 0;
1067 InvalidateRect (h
, &r
, TRUE
);
1070 SetFocus (nextbutton
);
1073 // DoInsertItem - inserts an item into a header control.
1074 // Returns the index of the new item.
1075 // hwndHeader - handle to the header control.
1076 // iInsertAfter - index of the previous item.
1077 // nWidth - width of the new item.
1078 // lpsz - address of the item string.
1080 DoInsertItem (HWND hwndHeader
, int iInsertAfter
, int nWidth
, LPSTR lpsz
)
1085 hdi
.mask
= HDI_TEXT
| HDI_FORMAT
| HDI_WIDTH
;
1088 hdi
.cchTextMax
= lstrlen (hdi
.pszText
);
1089 hdi
.fmt
= HDF_LEFT
| HDF_STRING
;
1091 index
= SendMessage (hwndHeader
, HDM_INSERTITEM
,
1092 (WPARAM
) iInsertAfter
, (LPARAM
) & hdi
);
1100 create_listview (HWND dlg
, RECT
* r
)
1102 lv
= CreateWindowEx (WS_EX_CLIENTEDGE
,
1105 WS_CHILD
| WS_HSCROLL
| WS_VSCROLL
| WS_VISIBLE
,
1107 r
->right
- r
->left
+ 1, r
->bottom
- r
->top
+ 1,
1109 (HMENU
) MAKEINTRESOURCE (IDC_CHOOSE_LIST
),
1111 ShowWindow (lv
, SW_SHOW
);
1113 chooser
= new view (VIEW_CATEGORY
, lv
, db
.categories
.registerbykey("All"));
1115 default_trust (lv
, TRUST_CURR
);
1116 set_view_mode (lv
, VIEW_CATEGORY
);
1117 if (!SetDlgItemText (dlg
, IDC_CHOOSE_VIEWCAPTION
, chooser
->mode_caption ()))
1118 log (LOG_BABBLE
, "Failed to set View button caption %ld",
1120 for (size_t n
= 1; n
<= db
.packages
.number (); n
++)
1122 packagemeta
& pkg
= *db
.packages
[n
];
1125 /* FIXME: do we need to init the desired fields ? */
1126 static int ta
[] = { IDC_CHOOSE_CURR
, 0 };
1127 rbset (dlg
, ta
, IDC_CHOOSE_CURR
);
1132 dialog_cmd (HWND h
, int id
, HWND hwndctl
, UINT code
)
1137 case IDC_CHOOSE_PREV
:
1138 default_trust (lv
, TRUST_PREV
);
1139 for (size_t n
= 1; n
<= db
.packages
.number (); n
++)
1141 packagemeta
& pkg
= *db
.packages
[n
];
1144 set_view_mode (lv
, chooser
->get_view_mode ());
1146 case IDC_CHOOSE_CURR
:
1147 default_trust (lv
, TRUST_CURR
);
1148 for (size_t n
= 1; n
<= db
.packages
.number (); n
++)
1150 packagemeta
& pkg
= *db
.packages
[n
];
1153 set_view_mode (lv
, chooser
->get_view_mode ());
1155 case IDC_CHOOSE_EXP
:
1156 default_trust (lv
, TRUST_TEST
);
1157 for (size_t n
= 1; n
<= db
.packages
.number (); n
++)
1159 packagemeta
& pkg
= *db
.packages
[n
];
1162 set_view_mode (lv
, chooser
->get_view_mode ());
1164 case IDC_CHOOSE_VIEW
:
1165 set_view_mode (lv
, viewsplusplus (chooser
->get_view_mode ()));
1167 (h
, IDC_CHOOSE_VIEWCAPTION
, chooser
->mode_caption ()))
1168 log (LOG_BABBLE
, "Failed to set View button caption %ld",
1173 if (source
== IDC_SOURCE_CWD
)
1174 NEXT (IDD_S_INSTALL
);
1176 NEXT (IDD_S_DOWNLOAD
);
1181 if (source
== IDC_SOURCE_CWD
)
1182 NEXT (IDD_LOCAL_DIR
);
1195 GetParentRect (HWND parent
, HWND child
, RECT
* r
)
1198 GetWindowRect (child
, r
);
1201 ScreenToClient (parent
, &p
);
1206 ScreenToClient (parent
, &p
);
1211 static BOOL CALLBACK
1212 dialog_proc (HWND h
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1219 nextbutton
= GetDlgItem (h
, IDOK
);
1220 frame
= GetDlgItem (h
, IDC_LISTVIEW_POS
);
1221 choose_inst_text
= GetDlgItem (h
, IDC_CHOOSE_INST_TEXT
);
1222 if (source
== IDC_SOURCE_DOWNLOAD
)
1223 SetWindowText (choose_inst_text
, "Select packages to download ");
1225 SetWindowText (choose_inst_text
, "Select packages to install ");
1226 GetParentRect (h
, frame
, &r
);
1229 create_listview (h
, &r
);
1236 return HANDLE_WM_COMMAND (h
, wParam
, lParam
, dialog_cmd
);
1241 /* Find out where to put existing tar file in local directory in
1242 known package array. */
1244 scan2 (char *path
, unsigned int size
)
1249 if (!parse_filename (path
, f
))
1252 if (f
.what
[0] != '\0' && f
.what
[0] != 's')
1256 pkg
= db
.packages
.getbykey (f
.pkg
);
1260 /* Scan existing package list looking for a match between a known
1261 package and a tar archive on disk.
1262 While scanning, keep track of appropriate "holes" in the trust
1263 table where a tar file could be put if no known entry
1266 We have 4 specific insertion points and one generic point.
1267 The generic point is in versioned order in the package version array.
1268 The specific points are
1274 if the version number matches a version in the db,
1275 we simply add this as a mirror source to that version.
1276 If it matches no version, we add a new version to the db.
1278 Lastly if the version number does not matche one of installed/prev/current/exp
1279 AND we had to create a new version entry
1280 we apply the following heuristic:
1281 if there is no exp, we link this in exp.
1282 If there is an exp and this is higher, we link this in exp, and
1283 if there is no curr, bump what was in exp to curr. If there was a curr, we leave it be.
1284 if this is lower than exp, and there is no curr, link as curr. If there is a curr, leave it be.
1285 If this is lower than curr, and there is no prev, link as prev, if there is a prev, leave it be.
1287 Whilst this logic is potentially wrong from time to time, it guarantees that
1288 setup.ini defined stability won't be altered unintentially. An alternative is to
1289 mark setup.ini defined prev/curr/exp packages as such, when this algorithm, can
1292 So, if setup.ini knows that ash-20010425-1.tar.gz is the current
1293 version and there is an ash-20010426-1.tar.gz in the current directory,
1294 the 20010426 version will be placed in the "test" slot, assuming that
1295 there is no test version listed in setup.ini. */
1298 for (size_t n
= 1; n
<= pkg
->versions
.number (); n
++)
1300 if (!strcasecmp (f
.ver
, pkg
->versions
[n
]->Canonical_version ()))
1302 /* FIXME: Add a mirror entry */
1308 /* FIXME: Add a new version */
1310 /* And now the hole finder */
1313 pkg
->exp
= thenewver
;
1314 else if (strcasecmp (f
.ver
, pkg
->versions
[n
]->Canonicalversion ()) < 0)
1317 pkg
->curr
= thenewver
;
1318 else if (strcasecmp (f
.ver
, pkg
->versions
[n
]->Canonicalversion ()) <
1322 pkg
->prev
= thenewver
;
1329 scan_downloaded_files ()
1335 do_choose (HINSTANCE h
, HWND owner
)
1340 bm_spin
= LoadImage (h
, MAKEINTRESOURCE (IDB_SPIN
), IMAGE_BITMAP
, 0, 0, 0);
1341 bm_rtarrow
= LoadImage (h
, MAKEINTRESOURCE (IDB_RTARROW
), IMAGE_BITMAP
,
1344 bm_checkyes
= LoadImage (h
, MAKEINTRESOURCE (IDB_CHECK_YES
), IMAGE_BITMAP
,
1346 bm_checkno
= LoadImage (h
, MAKEINTRESOURCE (IDB_CHECK_NO
), IMAGE_BITMAP
,
1348 bm_checkna
= LoadImage (h
, MAKEINTRESOURCE (IDB_CHECK_NA
), IMAGE_BITMAP
,
1351 register_windows (h
);
1353 if (source
== IDC_SOURCE_DOWNLOAD
|| source
== IDC_SOURCE_CWD
)
1354 scan_downloaded_files ();
1357 fill_missing_category ();
1359 rv
= DialogBox (h
, MAKEINTRESOURCE (IDD_CHOOSE
), owner
, dialog_proc
);
1361 fatal (owner
, IDS_DIALOG_FAILED
);
1363 log (LOG_BABBLE
, "Chooser results...");
1365 for (size_t n
= 1; n
<= db
.packages
.number (); n
++)
1367 packagemeta
& pkg
= *db
.packages
[n
];
1368 // static const char *infos[] = { "nada", "prev", "curr", "test" };
1369 const char *trust
= ((pkg
.desired
== pkg
.prev
) ? "prev"
1370 : (pkg
.desired
== pkg
.curr
) ? "curr"
1371 : (pkg
.desired
== pkg
.exp
) ? "test" : "unknown");
1372 const char *action
= pkg
.action_caption ();
1373 const char *installed
=
1374 pkg
.installed
? pkg
.installed
->Canonical_version () : "none";
1376 log (LOG_BABBLE
, "[%s] action=%s trust=%s installed=%s"
1378 pkg
.name
, action
, trust
, installed
,
1379 pkg
.desired
&& pkg
.desired
->srcpicked
? "yes" : "no");
1380 if (pkg
.Categories
.number ())
1382 /* List categories the package belongs to */
1383 int categories_len
= 0;
1384 for (size_t n
= 1; n
<= pkg
.Categories
.number (); n
++)
1385 categories_len
+= strlen (pkg
.Categories
[n
]->key
.name
) + 2;
1387 if (categories_len
> 0)
1389 char *categories
= (char *) malloc (categories_len
);
1390 strcpy (categories
, pkg
.Categories
[1]->key
.name
);
1391 for (size_t n
= 2; n
<= pkg
.Categories
.number (); n
++)
1393 strcat (categories
, ", ");
1394 strcat (categories
, pkg
.Categories
[n
]->key
.name
);
1396 log (LOG_BABBLE
, " categories=%s", categories
);
1400 if (pkg
.desired
&& pkg
.desired
->required
)
1402 /* List other packages this package depends on */
1403 int requires_len
= 0;
1405 for (dp
= pkg
.desired
->required
; dp
; dp
= dp
->next
)
1407 requires_len
+= strlen (dp
->package
) + 2;
1409 if (requires_len
> 0)
1411 char *requires
= (char *) malloc (requires_len
);
1412 strcpy (requires
, pkg
.desired
->required
->package
);
1413 for (dp
= pkg
.desired
->required
->next
; dp
; dp
= dp
->next
)
1416 strcat (requires
, ", ");
1417 strcat (requires
, dp
->package
);
1419 log (LOG_BABBLE
, " requires=%s", requires
);
1425 /* FIXME: Reinstate this code, but spit out all mirror sites */
1427 for (int t
= 1; t
< NTRUST
; t
++)
1429 if (pkg
->info
[t
].install
)
1430 log (LOG_BABBLE
, " [%s] ver=%s\n"
1431 " inst=%s %d exists=%s\n"
1432 " src=%s %d exists=%s",
1434 pkg
->info
[t
].version
? : "(none)",
1435 pkg
->info
[t
].install
? : "(none)",
1436 pkg
->info
[t
].install_size
,
1437 (pkg
->info
[t
].install_exists
) ? "yes" : "no",
1438 pkg
->info
[t
].source
? : "(none)",
1439 pkg
->info
[t
].source_size
,
1440 (pkg
->info
[t
].source_exists
) ? "yes" : "no");
1446 #define WM_APP_START_CHOOSE WM_APP+0
1447 #define WM_APP_CHOOSE_IS_FINISHED WM_APP+1
1449 extern void do_choose (HINSTANCE h
, HWND owner
);
1452 do_choose_thread (void *p
)
1456 cp
= static_cast < ChooserPage
* >(p
);
1458 do_choose (cp
->GetInstance (), cp
->GetHWND ());
1460 cp
->PostMessage (WM_APP_CHOOSE_IS_FINISHED
);
1466 ChooserPage::Create ()
1468 return PropertyPage::Create (IDD_CHOOSER
);
1472 ChooserPage::OnActivate ()
1474 GetOwner ()->SetButtons (0);
1475 PostMessage (WM_APP_START_CHOOSE
);
1479 ChooserPage::OnMessageApp (UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1483 case WM_APP_START_CHOOSE
:
1485 // Start the chooser thread.
1486 _beginthread (do_choose_thread
, 0, this);
1489 case WM_APP_CHOOSE_IS_FINISHED
:
1491 switch (next_dialog
)
1496 GetOwner ()->PressButton (PSBTN_CANCEL
);
1503 GetOwner ()->SetActivePageByID (next_dialog
);
1506 case IDD_S_DOWNLOAD
:
1508 // Next, start download from internet
1509 Progress
.SetActivateTask (WM_APP_START_DOWNLOAD
);
1510 GetOwner ()->SetActivePageByID (IDD_INSTATUS
);
1516 Progress
.SetActivateTask (WM_APP_START_INSTALL
);
1517 GetOwner ()->SetActivePageByID (IDD_INSTATUS
);