2 * Copyright (c) 2002 Robert Collins.
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 Robert Collins <robertc@hotmail.com>
21 #include "PickPackageLine.h"
22 #include "PickCategoryLine.h"
23 #include "package_db.h"
24 #include "package_version.h"
29 #include "LogSingleton.h"
33 static PickView::Header pkg_headers
[] = {
34 {"Current", 0, 0, true},
36 {"Bin?", 0, 0, false},
37 {"Src?", 0, 0, false},
38 {"Categories", 0, 0, true},
40 {"Package", 0, 0, true},
44 static PickView::Header cat_headers
[] = {
45 {"Category", 0, 0, true},
46 {"Current", 0, 0, true},
48 {"Bin?", 0, 0, false},
49 {"Src?", 0, 0, false},
51 {"Package", 0, 0, true},
56 const PickView::views
PickView::views::Unknown (0);
57 const PickView::views
PickView::views::PackageFull (1);
58 const PickView::views
PickView::views::Package (2);
59 const PickView::views
PickView::views::PackageKeeps (3);
60 const PickView::views
PickView::views::PackageSkips
= PickView::views (4);
61 const PickView::views
PickView::views::Category (5);
63 ATOM
PickView::WindowClassAtom
= 0;
65 // DoInsertItem - inserts an item into a header control.
66 // Returns the index of the new item.
67 // hwndHeader - handle to the header control.
68 // iInsertAfter - index of the previous item.
69 // nWidth - width of the new item.
70 // lpsz - address of the item string.
72 DoInsertItem (HWND hwndHeader
, int iInsertAfter
, int nWidth
, LPSTR lpsz
)
77 hdi
.mask
= HDI_TEXT
| HDI_FORMAT
| HDI_WIDTH
;
80 hdi
.cchTextMax
= lstrlen (hdi
.pszText
);
81 hdi
.fmt
= HDF_LEFT
| HDF_STRING
;
83 index
= SendMessage (hwndHeader
, HDM_INSERTITEM
,
84 (WPARAM
) iInsertAfter
, (LPARAM
) & hdi
);
90 PickView::set_header_column_order (views vm
)
92 if (vm
== views::Unknown
)
94 else if (vm
== views::PackageFull
|| vm
== views::Package
95 || vm
== views::PackageKeeps
|| vm
== views::PackageSkips
)
97 headers
= pkg_headers
;
100 bintick_col
= new_col
+ 1;
101 srctick_col
= bintick_col
+ 1;
102 cat_col
= srctick_col
+ 1;
103 size_col
= cat_col
+ 1;
104 pkg_col
= size_col
+ 1;
107 else if (vm
== views::Category
)
109 headers
= cat_headers
;
112 new_col
= current_col
+ 1;
113 bintick_col
= new_col
+ 1;
114 srctick_col
= bintick_col
+ 1;
115 size_col
= srctick_col
+ 1;
116 pkg_col
= size_col
+ 1;
125 PickView::set_headers ()
127 if (set_header_column_order (view_mode
) == -1)
129 while (int n
= SendMessage (listheader
, HDM_GETITEMCOUNT
, 0, 0))
131 SendMessage (listheader
, HDM_DELETEITEM
, n
- 1, 0);
134 for (i
= 0; i
<= last_col
; i
++)
135 DoInsertItem (listheader
, i
, headers
[i
].width
, (char *) headers
[i
].text
);
139 PickView::note_width (PickView::Header
*hdrs
, HDC dc
,
140 const std::string
& string
, int addend
, int column
)
145 GetTextExtentPoint32 (dc
, string
.c_str(), string
.size(), &s
);
146 if (hdrs
[column
].width
< s
.cx
+ addend
)
147 hdrs
[column
].width
= s
.cx
+ addend
;
151 PickView::cycleViewMode ()
153 setViewMode (++view_mode
);
157 PickView::setViewMode (views mode
)
164 if (view_mode
== PickView::views::Category
)
166 contents
.ShowLabel (true);
167 /* start collapsed. TODO: make this a chooser flag */
168 for (packagedb::categoriesType::iterator n
=
169 packagedb::categories
.begin(); n
!= packagedb::categories
.end();
171 insert_category (&*n
, (*n
).first
.c_str()[0] == '.'
172 ? CATEGORY_EXPANDED
: CATEGORY_COLLAPSED
);
176 contents
.ShowLabel (false);
177 // iterate through every package
178 for (packagedb::packagecollection::iterator i
= db
.packages
.begin ();
179 i
!= db
.packages
.end (); ++i
)
181 packagemeta
& pkg
= *(i
->second
);
183 if ( // "Full" : everything
184 (view_mode
== PickView::views::PackageFull
)
186 // "Pending" : packages that are being added/removed/upgraded
187 || (view_mode
== PickView::views::Package
&&
188 ((!pkg
.desired
&& pkg
.installed
) || // uninstall
190 (pkg
.desired
.picked () || // install bin
191 pkg
.desired
.sourcePackage ().picked ())))) // src
193 // "Up to date" : installed packages that will not be changed
194 || (view_mode
== PickView::views::PackageKeeps
&&
195 (pkg
.installed
&& pkg
.desired
&& !pkg
.desired
.picked ()
196 && !pkg
.desired
.sourcePackage ().picked ()))
199 || (view_mode
== PickView::views::PackageSkips
&&
200 (!pkg
.desired
&& !pkg
.installed
)))
202 // Filter by package name
203 if (packageFilterString
.empty ()
204 || StrStrI (pkg
.name
.c_str (), packageFilterString
.c_str ()))
210 RECT r
= GetClientRect ();
212 memset (&si
, 0, sizeof (si
));
213 si
.cbSize
= sizeof (si
);
214 si
.fMask
= SIF_ALL
| SIF_DISABLENOSCROLL
;
216 si
.nMax
= headers
[last_col
].x
+ headers
[last_col
].width
; // + HMARGIN;
218 SetScrollInfo (GetHWND(), SB_HORZ
, &si
, TRUE
);
220 si
.nMax
= contents
.itemcount () * row_height
;
221 si
.nPage
= r
.bottom
- header_height
;
222 SetScrollInfo (GetHWND(), SB_VERT
, &si
, TRUE
);
224 scroll_ulc_x
= scroll_ulc_y
= 0;
226 InvalidateRect (GetHWND(), &r
, TRUE
);
230 PickView::mode_caption ()
232 return view_mode
.caption ();
236 PickView::views::caption ()
247 return "Not Installed";
255 /* meant to be called on packagemeta::categories */
257 isObsolete (set
<std::string
, casecompare_lt_op
> &categories
)
259 set
<std::string
, casecompare_lt_op
>::const_iterator i
;
261 for (i
= categories
.begin (); i
!= categories
.end (); ++i
)
268 isObsolete (const std::string
& catname
)
270 if (casecompare(catname
, "ZZZRemovedPackages") == 0
271 || casecompare(catname
, "_", 1) == 0)
276 /* Sets the mode for showing/hiding obsolete junk packages. */
278 PickView::setObsolete (bool doit
)
286 PickView::insert_pkg (packagemeta
& pkg
)
288 if (!showObsolete
&& isObsolete (pkg
.categories
))
291 if (view_mode
!= views::Category
)
293 PickLine
& line
= *new PickPackageLine (*this, pkg
);
294 contents
.insert (line
);
298 for (set
<std::string
, casecompare_lt_op
>::const_iterator x
299 = pkg
.categories
.begin (); x
!= pkg
.categories
.end (); ++x
)
301 // Special case - yuck
302 if (casecompare(*x
, "All") == 0)
306 PickCategoryLine
& catline
=
307 *new PickCategoryLine (*this, *db
.categories
.find (*x
), 1);
308 PickLine
& line
= *new PickPackageLine(*this, pkg
);
309 catline
.insert (line
);
310 contents
.insert (catline
);
316 PickView::insert_category (Category
*cat
, bool collapsed
)
319 if (casecompare(cat
->first
, "All") == 0 ||
320 (!showObsolete
&& isObsolete (cat
->first
)))
322 PickCategoryLine
& catline
= *new PickCategoryLine (*this, *cat
, 1, collapsed
);
323 int packageCount
= 0;
324 for (vector
<packagemeta
*>::iterator i
= cat
->second
.begin ();
325 i
!= cat
->second
.end () ; ++i
)
327 if (packageFilterString
.empty () \
329 && StrStrI ((*i
)->name
.c_str (), packageFilterString
.c_str ())))
331 PickLine
& line
= *new PickPackageLine (*this, **i
);
332 catline
.insert (line
);
337 if (packageFilterString
.empty () || packageCount
)
338 contents
.insert (catline
);
344 PickView::views::operator++ ()
347 if (_value
> Category
._value
)
353 PickView::click (int row
, int x
)
355 return contents
.click (0, row
, x
);
360 PickView::scroll (HWND hwnd
, int which
, int *var
, int code
, int howmany
= 1)
363 si
.cbSize
= sizeof (si
);
364 si
.fMask
= SIF_ALL
| SIF_DISABLENOSCROLL
;
365 GetScrollInfo (hwnd
, which
, &si
);
370 si
.nPos
= si
.nTrackPos
;
372 case SB_THUMBPOSITION
:
381 si
.nPos
+= (row_height
* howmany
);
384 si
.nPos
-= (row_height
* howmany
);
387 si
.nPos
+= si
.nPage
* 9 / 10;
390 si
.nPos
-= si
.nPage
* 9 / 10;
394 if ((int) si
.nPos
< 0)
396 if (si
.nPos
+ si
.nPage
> (unsigned int) si
.nMax
)
397 si
.nPos
= si
.nMax
- si
.nPage
;
400 SetScrollInfo (hwnd
, which
, &si
, TRUE
);
402 int ox
= scroll_ulc_x
;
403 int oy
= scroll_ulc_y
;
407 ::GetClientRect (hwnd
, &cr
);
409 sr
.top
+= header_height
;
411 ScrollWindow (hwnd
, ox
- scroll_ulc_x
, oy
- scroll_ulc_y
, &sr
, &sr
);
415 ScrollWindow (hwnd, ox - scroll_ulc_x, 0, &sr, &sr);
417 if (ox
- scroll_ulc_x
)
419 ::GetClientRect (listheader
, &cr
);
421 // UpdateWindow (htmp);
422 ::MoveWindow (listheader
, -scroll_ulc_x
, 0,
423 headers
[last_col
].x
+
424 headers
[last_col
].width
, header_height
, TRUE
);
429 /* this means to make the 'category' column wide enough to fit the first 'n'
430 categories for each package. */
431 #define NUM_CATEGORY_COL_WIDTH 2
434 PickView::init_headers (HDC dc
)
438 for (i
= 0; headers
[i
].text
; i
++)
440 headers
[i
].width
= 0;
444 // accomodate widths of the 'bin' and 'src' checkbox columns
445 // FIXME: What's up with the "0"? It's probably a mistake, and should be
446 // "". It used to be written as 0, and was subject to a bizarre implicit
447 // conversion by the unwise String(int) constructor.
448 note_width (headers
, dc
, "0", HMARGIN
+ 11, bintick_col
);
449 note_width (headers
, dc
, "0", HMARGIN
+ 11, srctick_col
);
451 // accomodate the width of each category name
453 for (packagedb::categoriesType::iterator n
= packagedb::categories
.begin();
454 n
!= packagedb::categories
.end(); ++n
)
456 if (!showObsolete
&& isObsolete (n
->first
))
458 note_width (headers
, dc
, n
->first
, HMARGIN
, cat_col
);
461 /* For each package, accomodate the width of the installed version in the
462 current_col, the widths of all other versions in the new_col, and the
463 width of the sdesc for the pkg_col. Also, if this is not a Category
464 view, adjust the 'category' column so that the first NUM_CATEGORY_COL_WIDTH
465 categories from each package fits. */
466 for (packagedb::packagecollection::iterator n
= db
.packages
.begin ();
467 n
!= db
.packages
.end (); ++n
)
469 packagemeta
& pkg
= *(n
->second
);
470 if (!showObsolete
&& isObsolete (pkg
.categories
))
473 note_width (headers
, dc
, pkg
.installed
.Canonical_version (),
474 HMARGIN
, current_col
);
475 for (set
<packageversion
>::iterator i
= pkg
.versions
.begin ();
476 i
!= pkg
.versions
.end (); ++i
)
478 if (*i
!= pkg
.installed
)
479 note_width (headers
, dc
, i
->Canonical_version (),
480 HMARGIN
+ SPIN_WIDTH
, new_col
);
481 std::string z
= format_1000s(packageversion(*i
).source ()->size
);
482 note_width (headers
, dc
, z
, HMARGIN
, size_col
);
483 z
= format_1000s(packageversion(i
->sourcePackage ()).source ()->size
);
484 note_width (headers
, dc
, z
, HMARGIN
, size_col
);
486 std::string s
= pkg
.name
;
487 if (pkg
.SDesc ().size())
488 s
+= std::string (": ") + std::string(pkg
.SDesc ());
489 note_width (headers
, dc
, s
, HMARGIN
, pkg_col
);
491 if (view_mode
!= PickView::views::Category
&& pkg
.categories
.size () > 2)
493 std::string
compound_cat("");
494 std::set
<std::string
, casecompare_lt_op
>::const_iterator cat
;
497 for (cnt
= 0, cat
= pkg
.categories
.begin ();
498 cnt
< NUM_CATEGORY_COL_WIDTH
&& cat
!= pkg
.categories
.end ();
501 if (casecompare(*cat
, "All") == 0)
503 if (compound_cat
.size ())
504 compound_cat
+= ", ";
505 compound_cat
+= *cat
;
508 note_width (headers
, dc
, compound_cat
, HMARGIN
, cat_col
);
512 // ensure that the new_col is wide enough for all the labels
513 const char *captions
[] = { "Uninstall", "Skip", "Reinstall", "Retrieve",
514 "Source", "Keep", NULL
};
515 for (int i
= 0; captions
[i
]; i
++)
516 note_width (headers
, dc
, captions
[i
], HMARGIN
+ SPIN_WIDTH
, new_col
);
518 // finally, compute the actual x values based on widths
520 for (i
= 1; i
<= last_col
; i
++)
521 headers
[i
].x
= headers
[i
- 1].x
+ headers
[i
- 1].width
;
522 // and allow for resizing to ensure the last column reaches
523 // all the way to the end of the chooser box.
524 headers
[last_col
].width
+= total_delta_x
;
528 PickView::PickView (Category
&cat
) : deftrust (TRUST_UNKNOWN
),
529 contents (*this, cat
, 0, false, true), showObsolete (false),
530 packageFilterString (), hasWindowRect (false), total_delta_x (0)
535 PickView::init(views _mode
)
537 HDC dc
= GetDC (GetHWND());
538 sysfont
= GetStockObject (DEFAULT_GUI_FONT
);
539 SelectObject (dc
, sysfont
);
540 GetTextMetrics (dc
, &tm
);
542 bitmap_dc
= CreateCompatibleDC (dc
);
543 #define LI(x) LoadImage (hinstance, MAKEINTRESOURCE (x), IMAGE_BITMAP, 0, 0, 0);
544 bm_spin
= LI (IDB_SPIN
);
545 bm_checkyes
= LI (IDB_CHECK_YES
);
546 bm_checkno
= LI (IDB_CHECK_NO
);
547 bm_checkna
= LI (IDB_CHECK_NA
);
548 bm_treeplus
= LI (IDB_TREE_PLUS
);
549 bm_treeminus
= LI (IDB_TREE_MINUS
);
551 icon_dc
= CreateCompatibleDC (dc
);
552 bm_icon
= CreateCompatibleBitmap (dc
, 11, 11);
553 SelectObject (icon_dc
, bm_icon
);
554 rect_icon
= CreateRectRgn (0, 0, 11, 11);
556 row_height
= (tm
.tmHeight
+ tm
.tmExternalLeading
+ ROW_MARGIN
);
557 int irh
= tm
.tmExternalLeading
+ tm
.tmDescent
+ 11 + ROW_MARGIN
;
558 if (row_height
< irh
)
564 // Ensure that the common control DLL is loaded, and then create
565 // the header control.
566 INITCOMMONCONTROLSEX controlinfo
= { sizeof (INITCOMMONCONTROLSEX
),
567 ICC_LISTVIEW_CLASSES
};
568 InitCommonControlsEx (&controlinfo
);
570 if ((listheader
= CreateWindowEx (0, WC_HEADER
, (LPCTSTR
) NULL
,
571 WS_CHILD
| WS_BORDER
| CCS_NORESIZE
|
573 HDS_HORZ
, 0, 0, 0, 0, GetHWND(),
574 (HMENU
) IDC_CHOOSE_LISTHEADER
, hinstance
,
575 (LPVOID
) NULL
)) == NULL
)
576 // FIXME: throw an exception
579 // Retrieve the bounding rectangle of the parent window's
580 // client area, and then request size and position values
581 // from the header control.
582 RECT rcParent
= GetClientRect ();
586 if (!SendMessage (listheader
, HDM_LAYOUT
, 0, (LPARAM
) & hdl
))
587 // FIXME: throw an exception
590 // Set the font of the listheader, but don't redraw, because its not shown
591 // yet.This message does not return a value, so we are not checking it as we
593 SendMessage (listheader
, WM_SETFONT
, (WPARAM
) sysfont
, FALSE
);
595 // Set the size, position, and visibility of the header control.
596 SetWindowPos (listheader
, wp
.hwndInsertAfter
, wp
.x
, wp
.y
,
597 wp
.cx
, wp
.cy
, wp
.flags
| SWP_SHOWWINDOW
);
599 header_height
= wp
.cy
;
600 ReleaseDC (GetHWND (), dc
);
606 PickView::~PickView()
608 DeleteDC (bitmap_dc
);
609 DeleteObject (bm_spin
);
610 DeleteObject (bm_checkyes
);
611 DeleteObject (bm_checkno
);
612 DeleteObject (bm_checkna
);
613 DeleteObject (bm_treeplus
);
614 DeleteObject (bm_treeminus
);
615 DeleteObject (rect_icon
);
616 DeleteObject (bm_icon
);
620 bool PickView::registerWindowClass ()
622 if (WindowClassAtom
!= 0)
625 // We're not registered yet
628 wc
.cbSize
= sizeof (wc
);
629 // Some sensible style defaults
630 wc
.style
= CS_HREDRAW
| CS_VREDRAW
;
631 // Our default window procedure. This replaces itself
632 // on the first call with the simpler Window::WindowProcReflector().
633 wc
.lpfnWndProc
= Window::FirstWindowProcReflector
;
636 // One pointer to REFLECTION_INFO in the extra window instance bytes
639 wc
.hInstance
= hinstance
; //GetInstance ();
640 // Use a bunch of system defaults for the GUI elements
641 wc
.hIcon
= LoadIcon (0, IDI_APPLICATION
);
643 wc
.hCursor
= LoadCursor (0, IDC_ARROW
);
644 wc
.hbrBackground
= NULL
;
646 wc
.lpszMenuName
= NULL
;
647 // We'll get a little crazy here with the class name
648 wc
.lpszClassName
= "listview";
650 // All set, try to register
651 WindowClassAtom
= RegisterClassEx (&wc
);
652 if (WindowClassAtom
== 0)
653 log (LOG_BABBLE
) << "Failed to register listview " << GetLastError () << endLog
;
654 return WindowClassAtom
!= 0;
658 PickView::list_vscroll (HWND hwnd
, HWND hctl
, UINT code
, int pos
)
660 scroll (hwnd
, SB_VERT
, &scroll_ulc_y
, code
);
665 PickView::list_hscroll (HWND hwnd
, HWND hctl
, UINT code
, int pos
)
667 scroll (hwnd
, SB_HORZ
, &scroll_ulc_x
, code
);
672 PickView::set_vscroll_info (const RECT
&r
)
675 memset (&si
, 0, sizeof (si
));
676 si
.cbSize
= sizeof (si
);
677 si
.fMask
= SIF_ALL
| SIF_DISABLENOSCROLL
; /* SIF_RANGE was giving strange behaviour */
680 si
.nMax
= contents
.itemcount () * row_height
;
681 si
.nPage
= r
.bottom
- header_height
;
683 /* if we are under the minimum display count ,
684 * set the offset to 0
686 if ((unsigned int) si
.nMax
<= si
.nPage
)
688 si
.nPos
= scroll_ulc_y
;
690 SetScrollInfo (GetHWND(), SB_VERT
, &si
, TRUE
);
694 PickView::list_click (HWND hwnd
, BOOL dblclk
, int x
, int y
, UINT hitCode
)
696 int row
, refresh
__attribute__ ((unused
));
698 if (contents
.itemcount () == 0)
701 if (y
< header_height
)
704 y
+= scroll_ulc_y
- header_height
;
706 row
= (y
+ ROW_MARGIN
/ 2) / row_height
;
708 if (row
< 0 || row
>= contents
.itemcount ())
711 refresh
= click (row
, x
);
713 // XXX we need a method to query the database to see if more
714 // than just one package has changed! Until then...
719 RECT r
= GetClientRect ();
720 set_vscroll_info (r
);
721 InvalidateRect (GetHWND(), &r
, TRUE
);
728 headers
[new_col
].x
- scroll_ulc_x
;
730 headers
[src_col
+ 1].x
- scroll_ulc_x
;
732 header_height
+ row
* row_height
-
734 rect
.bottom
= rect
.top
+ row_height
;
735 InvalidateRect (hwnd
, &rect
, TRUE
);
743 * PickView::listview_proc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
746 PickView::WindowProc (UINT message
, WPARAM wParam
, LPARAM lParam
)
754 list_hscroll (GetHWND(), (HWND
)lParam
, LOWORD(wParam
), HIWORD(wParam
));
757 list_vscroll (GetHWND(), (HWND
)lParam
, LOWORD(wParam
), HIWORD(wParam
));
760 // this is how many 'notches' the wheel scrolled, forward/up = positive
761 wheel_notches
= GET_WHEEL_DELTA_WPARAM(wParam
) / 120;
763 // determine how many lines the user has configred for a mouse scroll
764 SystemParametersInfo(SPI_GETWHEELSCROLLLINES
, 0, &wheel_lines
, 0);
766 if (wheel_lines
== 0) // do no scrolling
768 else if (wheel_lines
== WHEEL_PAGESCROLL
)
769 scroll (GetHWND (), SB_VERT
, &scroll_ulc_y
, (wheel_notches
> 0) ?
770 SB_PAGEUP
: SB_PAGEDOWN
);
772 scroll (GetHWND (), SB_VERT
, &scroll_ulc_y
, (wheel_notches
> 0) ?
773 SB_LINEUP
: SB_LINEDOWN
, wheel_lines
* abs (wheel_notches
));
776 list_click (GetHWND(), FALSE
, LOWORD(lParam
), HIWORD(lParam
), wParam
);
783 // pnmh = (LPNMHDR) lParam
784 LPNMHEADER phdr
= (LPNMHEADER
) lParam
;
785 switch (phdr
->hdr
.code
)
787 case HDN_ITEMCHANGED
:
788 if (phdr
->hdr
.hwndFrom
== ListHeader ())
790 if (phdr
->pitem
&& phdr
->pitem
->mask
& HDI_WIDTH
)
791 headers
[phdr
->iItem
].width
= phdr
->pitem
->cxy
;
793 for (int i
= 1; i
<= last_col
; i
++)
794 headers
[i
].x
= headers
[i
- 1].x
+ headers
[i
- 1].width
;
796 RECT r
= GetClientRect ();
798 si
.cbSize
= sizeof (si
);
799 si
.fMask
= SIF_ALL
| SIF_DISABLENOSCROLL
;
800 GetScrollInfo (GetHWND(), SB_HORZ
, &si
);
802 int oldMax
= si
.nMax
;
803 si
.nMax
= headers
[last_col
].x
+ headers
[last_col
].width
;
804 if (si
.nTrackPos
&& oldMax
> si
.nMax
)
805 si
.nTrackPos
+= si
.nMax
- oldMax
;
808 SetScrollInfo (GetHWND(), SB_HORZ
, &si
, TRUE
);
809 InvalidateRect (GetHWND(), &r
, TRUE
);
810 if (si
.nTrackPos
&& oldMax
> si
.nMax
)
811 scroll (GetHWND(), SB_HORZ
, &scroll_ulc_x
, SB_THUMBTRACK
);
819 // Note: WM_SIZE msgs only appear when 'just' scrolling the window
820 RECT windowRect
= GetWindowRect ();
824 if ((dx
= windowRect
.right
- windowRect
.left
-
825 lastWindowRect
.width ()) != 0)
827 cat_headers
[set_header_column_order (views::Category
)].width
+= dx
;
828 pkg_headers
[set_header_column_order (views::Package
)].width
+= dx
;
829 set_header_column_order (view_mode
);
831 ::MoveWindow (listheader
, -scroll_ulc_x
, 0,
832 headers
[last_col
].x
+
833 headers
[last_col
].width
, header_height
, TRUE
);
836 if (windowRect
.bottom
- windowRect
.top
- lastWindowRect
.height ())
837 set_vscroll_info (GetClientRect ());
840 hasWindowRect
= true;
842 lastWindowRect
= windowRect
;
847 // default: can't handle this message
848 return DefWindowProc (GetHWND(), message
, wParam
, lParam
);
852 // Turn black into foreground color and white into background color by
853 // 1) Filling a square with ~(FG^BG)
854 // 2) Blitting the bitmap on it with NOTSRCERASE (white->black; black->FG^BG)
855 // 3) Blitting the result on BG with SRCINVERT (white->BG; black->FG)
857 PickView::DrawIcon (HDC hdc
, int x
, int y
, HANDLE hIcon
)
859 SelectObject (bitmap_dc
, hIcon
);
860 FillRgn (icon_dc
, rect_icon
, bg_fg_brush
);
861 BitBlt (icon_dc
, 0, 0, 11, 11, bitmap_dc
, 0, 0, NOTSRCERASE
);
862 BitBlt (hdc
, x
, y
, 11, 11, icon_dc
, 0, 0, SRCINVERT
);
863 ///////////// On WinNT-based systems, we could've done the below instead
864 ///////////// See http://support.microsoft.com/default.aspx?scid=kb;en-us;79212
865 // SelectObject (hdc, GetSysColorBrush (COLOR_WINDOWTEXT));
866 // HBITMAP bm_icon = CreateBitmap (11, 11, 1, 1, NULL);
867 // SelectObject (icon_dc, bm_icon);
868 // BitBlt (icon_dc, 0, 0, 11, 11, bitmap_dc, 0, 0, SRCCOPY);
869 // MaskBlt (hdc, x2, by, 11, 11, bitmap_dc, 0, 0, bm_icon, 0, 0, MAKEROP4 (SRCAND, PATCOPY));
870 // DeleteObject (bm_icon);
874 PickView::paint (HWND hwnd
)
876 // we want to retrieve the update region before calling BeginPaint,
877 // because after we do that the update region is validated and we can
878 // no longer retrieve it
879 HRGN hUpdRgn
= CreateRectRgn (0, 0, 0, 0);
881 if (GetUpdateRgn (hwnd
, hUpdRgn
, FALSE
) == 0)
887 // tell the system that we're going to begin painting our window
888 // it will prevent further WM_PAINT messages from arriving until we're
889 // done, and if any part of our window was invalidated while we are
890 // painting, it will retrigger us so that we can fix it
892 HDC hdc
= BeginPaint (hwnd
, &ps
);
894 SelectObject (hdc
, sysfont
);
895 SetTextColor (hdc
, GetSysColor (COLOR_WINDOWTEXT
));
896 SetBkColor (hdc
, GetSysColor (COLOR_WINDOW
));
897 FillRgn (hdc
, hUpdRgn
, GetSysColorBrush(COLOR_WINDOW
));
899 COLORREF clr
= ~GetSysColor (COLOR_WINDOW
) ^ GetSysColor (COLOR_WINDOWTEXT
);
900 clr
= RGB (GetRValue (clr
), GetGValue (clr
), GetBValue (clr
)); // reconvert
901 bg_fg_brush
= CreateSolidBrush (clr
);
904 ::GetClientRect (hwnd
, &cr
);
906 int x
= cr
.left
- scroll_ulc_x
;
907 int y
= cr
.top
- scroll_ulc_y
+ header_height
;
909 contents
.paint (hdc
, hUpdRgn
, x
, y
, 0, (view_mode
==
910 PickView::views::Category
) ? 0 : 1);
912 if (contents
.itemcount () == 0)
914 static const char *msg
= "Nothing to Install/Update";
915 if (source
== IDC_SOURCE_DOWNLOAD
)
916 msg
= "Nothing to Download";
917 TextOut (hdc
, x
+ HMARGIN
, y
, msg
, strlen (msg
));
920 DeleteObject (hUpdRgn
);
921 DeleteObject (bg_fg_brush
);
922 EndPaint (hwnd
, &ps
);
927 PickView::Create (Window
* parent
, DWORD Style
, RECT
*r
)
930 // First register the window class, if we haven't already
931 if (!registerWindowClass ())
933 // Registration failed
937 // Save our parent, we'll probably need it eventually.
940 // Create the window instance
941 CreateWindowEx (// Extended Style
943 // window class atom (name)
944 "listview", //MAKEINTATOM(WindowClassAtom),
945 "listviewwindow", // no title-bar string yet
948 r
? r
->left
: CW_USEDEFAULT
,
949 r
? r
->top
: CW_USEDEFAULT
,
950 r
? r
->right
- r
->left
+ 1 : CW_USEDEFAULT
,
951 r
? r
->bottom
- r
->top
+ 1 : CW_USEDEFAULT
,
953 parent
== NULL
? (HWND
)NULL
: parent
->GetHWND (),
955 (HMENU
) MAKEINTRESOURCE (IDC_CHOOSE_LIST
),
956 // The application instance
958 // The this ptr, which we'll use to set up
959 // the WindowProc reflection.
960 reinterpret_cast<void *>((Window
*)this));
961 if (GetHWND() == NULL
)
963 log (LOG_BABBLE
) << "Failed to create PickView " << GetLastError () << endLog
;
971 PickView::defaultTrust (trusts trust
)
973 this->deftrust
= trust
;
976 db
.defaultTrust(trust
);
978 // force the picker to redraw
979 RECT r
= GetClientRect ();
980 InvalidateRect (this->GetHWND(), &r
, TRUE
);
983 /* This recalculates all column widths and resets the view */
987 HDC dc
= GetDC (GetHWND ());
989 // we must set the font of the DC here, otherwise the width calculations
990 // will be off because the system will use the wrong font metrics
991 sysfont
= GetStockObject (DEFAULT_GUI_FONT
);
992 SelectObject (dc
, sysfont
);
994 // init headers for the current mode
998 // save the current mode
999 views cur_view_mode
= view_mode
;
1001 // switch to the other type and do those headers
1002 view_mode
= (view_mode
== PickView::views::Category
) ?
1003 PickView::views::PackageFull
: PickView::views::Category
;
1006 ReleaseDC (GetHWND (), dc
);
1008 view_mode
= cur_view_mode
;
1009 setViewMode (view_mode
);