]> cygwin.com Git - cygwin-apps/setup.git/blame - PickView.cc
Remove cygpackage::destroy() because it does nothing
[cygwin-apps/setup.git] / PickView.cc
CommitLineData
97647369
RC
1/*
2 * Copyright (c) 2002 Robert Collins.
3 *
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.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 * Written by Robert Collins <robertc@hotmail.com>
13 *
14 */
15
16#include "PickView.h"
2e0aaec9
BD
17#include <algorithm>
18#include <limits.h>
97647369 19#include <commctrl.h>
1789ef54 20#include <shlwapi.h>
97647369
RC
21#include "PickPackageLine.h"
22#include "PickCategoryLine.h"
23#include "package_db.h"
24#include "package_version.h"
25#include "dialog.h"
26#include "resource.h"
693916f8
RC
27/* For 'source' */
28#include "state.h"
29#include "LogSingleton.h"
97647369 30
6625e635 31using namespace std;
97647369
RC
32
33static PickView::Header pkg_headers[] = {
82306ac2
BD
34 {"Current", 0, 0, true},
35 {"New", 0, 0, true},
36 {"Bin?", 0, 0, false},
37 {"Src?", 0, 0, false},
38 {"Categories", 0, 0, true},
0ac305ec 39 {"Size", 0, 0, true},
82306ac2
BD
40 {"Package", 0, 0, true},
41 {0, 0, 0, false}
97647369
RC
42};
43
44static PickView::Header cat_headers[] = {
82306ac2
BD
45 {"Category", 0, 0, true},
46 {"Current", 0, 0, true},
47 {"New", 0, 0, true},
48 {"Bin?", 0, 0, false},
49 {"Src?", 0, 0, false},
0ac305ec 50 {"Size", 0, 0, true},
82306ac2
BD
51 {"Package", 0, 0, true},
52 {0, 0, 0, false}
97647369
RC
53};
54
693916f8
RC
55ATOM PickView::WindowClassAtom = 0;
56
97647369
RC
57// DoInsertItem - inserts an item into a header control.
58// Returns the index of the new item.
59// hwndHeader - handle to the header control.
60// iInsertAfter - index of the previous item.
61// nWidth - width of the new item.
62// lpsz - address of the item string.
63static int
64DoInsertItem (HWND hwndHeader, int iInsertAfter, int nWidth, LPSTR lpsz)
65{
66 HDITEM hdi;
67 int index;
68
69 hdi.mask = HDI_TEXT | HDI_FORMAT | HDI_WIDTH;
70 hdi.pszText = lpsz;
71 hdi.cxy = nWidth;
72 hdi.cchTextMax = lstrlen (hdi.pszText);
73 hdi.fmt = HDF_LEFT | HDF_STRING;
74
75 index = SendMessage (hwndHeader, HDM_INSERTITEM,
76 (WPARAM) iInsertAfter, (LPARAM) & hdi);
77
78 return index;
79}
80
0baffe9a
DK
81int
82PickView::set_header_column_order (views vm)
97647369 83{
4f0fb3e4
JT
84 if (vm == views::PackageFull || vm == views::PackagePending
85 || vm == views::PackageKeeps || vm == views::PackageSkips
86 || vm == views::PackageUserPicked)
97647369
RC
87 {
88 headers = pkg_headers;
89 current_col = 0;
90 new_col = 1;
2fa7c5a4
RC
91 bintick_col = new_col + 1;
92 srctick_col = bintick_col + 1;
93 cat_col = srctick_col + 1;
0ac305ec
BD
94 size_col = cat_col + 1;
95 pkg_col = size_col + 1;
931f2755 96 last_col = pkg_col;
97647369 97 }
0baffe9a 98 else if (vm == views::Category)
97647369
RC
99 {
100 headers = cat_headers;
0baffe9a 101 cat_col = 0;
97647369 102 current_col = 1;
2fa7c5a4
RC
103 new_col = current_col + 1;
104 bintick_col = new_col + 1;
105 srctick_col = bintick_col + 1;
0ac305ec
BD
106 size_col = srctick_col + 1;
107 pkg_col = size_col + 1;
2fa7c5a4 108 last_col = pkg_col;
97647369
RC
109 }
110 else
0baffe9a
DK
111 return -1;
112 return last_col;
113}
114
115void
116PickView::set_headers ()
117{
118 if (set_header_column_order (view_mode) == -1)
97647369
RC
119 return;
120 while (int n = SendMessage (listheader, HDM_GETITEMCOUNT, 0, 0))
121 {
122 SendMessage (listheader, HDM_DELETEITEM, n - 1, 0);
123 }
124 int i;
125 for (i = 0; i <= last_col; i++)
126 DoInsertItem (listheader, i, headers[i].width, (char *) headers[i].text);
127}
128
129void
d19f12fd
MB
130PickView::note_width (PickView::Header *hdrs, HDC dc,
131 const std::string& string, int addend, int column)
97647369 132{
82306ac2
BD
133 SIZE s = { 0, 0 };
134
135 if (string.size())
136 GetTextExtentPoint32 (dc, string.c_str(), string.size(), &s);
97647369
RC
137 if (hdrs[column].width < s.cx + addend)
138 hdrs[column].width = s.cx + addend;
139}
140
525531ca 141void
82306ac2 142PickView::setViewMode (views mode)
525531ca 143{
82306ac2
BD
144 view_mode = mode;
145 set_headers ();
525531ca 146 packagedb db;
82306ac2
BD
147
148 contents.empty ();
149 if (view_mode == PickView::views::Category)
525531ca 150 {
82306ac2
BD
151 contents.ShowLabel (true);
152 /* start collapsed. TODO: make this a chooser flag */
153 for (packagedb::categoriesType::iterator n =
154 packagedb::categories.begin(); n != packagedb::categories.end();
155 ++n)
7c593196
IP
156 insert_category (&*n, (*n).first.c_str()[0] == '.'
157 ? CATEGORY_EXPANDED : CATEGORY_COLLAPSED);
525531ca 158 }
82306ac2 159 else
525531ca 160 {
82306ac2
BD
161 contents.ShowLabel (false);
162 // iterate through every package
263157cb 163 for (packagedb::packagecollection::iterator i = db.packages.begin ();
82306ac2
BD
164 i != db.packages.end (); ++i)
165 {
263157cb 166 packagemeta & pkg = *(i->second);
82306ac2
BD
167
168 if ( // "Full" : everything
169 (view_mode == PickView::views::PackageFull)
170
5a2eaf00 171 // "Pending" : packages that are being added/removed/upgraded
fa8967ca 172 || (view_mode == PickView::views::PackagePending &&
82306ac2
BD
173 ((!pkg.desired && pkg.installed) || // uninstall
174 (pkg.desired &&
175 (pkg.desired.picked () || // install bin
176 pkg.desired.sourcePackage ().picked ())))) // src
177
178 // "Up to date" : installed packages that will not be changed
179 || (view_mode == PickView::views::PackageKeeps &&
180 (pkg.installed && pkg.desired && !pkg.desired.picked ()
181 && !pkg.desired.sourcePackage ().picked ()))
182
183 // "Not installed"
184 || (view_mode == PickView::views::PackageSkips &&
b8752287
JT
185 (!pkg.desired && !pkg.installed))
186
187 // "UserPick" : installed packages that were picked by user
188 || (view_mode == PickView::views::PackageUserPicked &&
189 (pkg.installed && pkg.user_picked)))
059906b3
DK
190 {
191 // Filter by package name
192 if (packageFilterString.empty ()
1789ef54 193 || StrStrI (pkg.name.c_str (), packageFilterString.c_str ()))
059906b3
DK
194 insert_pkg (pkg);
195 }
82306ac2 196 }
525531ca
RC
197 }
198
bb8e2353 199 RECT r = GetClientRect ();
525531ca
RC
200 SCROLLINFO si;
201 memset (&si, 0, sizeof (si));
202 si.cbSize = sizeof (si);
203 si.fMask = SIF_ALL | SIF_DISABLENOSCROLL;
204 si.nMin = 0;
205 si.nMax = headers[last_col].x + headers[last_col].width; // + HMARGIN;
206 si.nPage = r.right;
207 SetScrollInfo (GetHWND(), SB_HORZ, &si, TRUE);
208
209 si.nMax = contents.itemcount () * row_height;
210 si.nPage = r.bottom - header_height;
211 SetScrollInfo (GetHWND(), SB_VERT, &si, TRUE);
212
213 scroll_ulc_x = scroll_ulc_y = 0;
214
215 InvalidateRect (GetHWND(), &r, TRUE);
216}
217
4f0fb3e4
JT
218PickView::views
219PickView::getViewMode ()
220{
221 return view_mode;
222}
223
97647369 224const char *
4f0fb3e4 225PickView::mode_caption (views mode)
97647369 226{
4f0fb3e4 227 switch (mode)
97647369 228 {
bf374ed9 229 case views::PackageFull:
97647369 230 return "Full";
fa8967ca 231 case views::PackagePending:
5a2eaf00 232 return "Pending";
bf374ed9 233 case views::PackageKeeps:
e0aec95e 234 return "Up To Date";
bf374ed9 235 case views::PackageSkips:
e0aec95e 236 return "Not Installed";
bf374ed9 237 case views::PackageUserPicked:
b8752287 238 return "Picked";
bf374ed9 239 case views::Category:
97647369
RC
240 return "Category";
241 default:
242 return "";
243 }
244}
245
82306ac2
BD
246/* meant to be called on packagemeta::categories */
247bool
d19f12fd 248isObsolete (set <std::string, casecompare_lt_op> &categories)
82306ac2 249{
d19f12fd 250 set <std::string, casecompare_lt_op>::const_iterator i;
82306ac2
BD
251
252 for (i = categories.begin (); i != categories.end (); ++i)
253 if (isObsolete (*i))
254 return true;
255 return false;
256}
257
258bool
d19f12fd 259isObsolete (const std::string& catname)
82306ac2 260{
afa76033
MB
261 if (casecompare(catname, "ZZZRemovedPackages") == 0
262 || casecompare(catname, "_", 1) == 0)
82306ac2
BD
263 return true;
264 return false;
265}
266
267/* Sets the mode for showing/hiding obsolete junk packages. */
268void
269PickView::setObsolete (bool doit)
270{
271 showObsolete = doit;
272 refresh ();
273}
274
275
97647369
RC
276void
277PickView::insert_pkg (packagemeta & pkg)
278{
82306ac2
BD
279 if (!showObsolete && isObsolete (pkg.categories))
280 return;
c938e8a6
JT
281
282 PickLine & line = *new PickPackageLine (*this, pkg);
283 contents.insert (line);
97647369
RC
284}
285
286void
82306ac2 287PickView::insert_category (Category *cat, bool collapsed)
97647369 288{
0cf68afd 289 // Urk, special case
afa76033 290 if (casecompare(cat->first, "All") == 0 ||
82306ac2 291 (!showObsolete && isObsolete (cat->first)))
97647369
RC
292 return;
293 PickCategoryLine & catline = *new PickCategoryLine (*this, *cat, 1, collapsed);
059906b3 294 int packageCount = 0;
0cf68afd
RC
295 for (vector <packagemeta *>::iterator i = cat->second.begin ();
296 i != cat->second.end () ; ++i)
97647369 297 {
059906b3 298 if (packageFilterString.empty () \
1789ef54
CV
299 || (*i
300 && StrStrI ((*i)->name.c_str (), packageFilterString.c_str ())))
059906b3
DK
301 {
302 PickLine & line = *new PickPackageLine (*this, **i);
303 catline.insert (line);
304 packageCount++;
305 }
97647369 306 }
059906b3
DK
307
308 if (packageFilterString.empty () || packageCount)
309 contents.insert (catline);
310 else
311 delete &catline;
97647369
RC
312}
313
97647369
RC
314int
315PickView::click (int row, int x)
316{
317 return contents.click (0, row, x);
318}
319
320
321void
82306ac2 322PickView::scroll (HWND hwnd, int which, int *var, int code, int howmany = 1)
97647369
RC
323{
324 SCROLLINFO si;
325 si.cbSize = sizeof (si);
e0aec95e 326 si.fMask = SIF_ALL | SIF_DISABLENOSCROLL;
97647369
RC
327 GetScrollInfo (hwnd, which, &si);
328
329 switch (code)
330 {
331 case SB_THUMBTRACK:
332 si.nPos = si.nTrackPos;
333 break;
334 case SB_THUMBPOSITION:
335 break;
336 case SB_BOTTOM:
337 si.nPos = si.nMax;
338 break;
339 case SB_TOP:
340 si.nPos = 0;
341 break;
342 case SB_LINEDOWN:
82306ac2 343 si.nPos += (row_height * howmany);
97647369
RC
344 break;
345 case SB_LINEUP:
82306ac2 346 si.nPos -= (row_height * howmany);
97647369
RC
347 break;
348 case SB_PAGEDOWN:
349 si.nPos += si.nPage * 9 / 10;
350 break;
351 case SB_PAGEUP:
352 si.nPos -= si.nPage * 9 / 10;
353 break;
354 }
355
356 if ((int) si.nPos < 0)
357 si.nPos = 0;
358 if (si.nPos + si.nPage > (unsigned int) si.nMax)
359 si.nPos = si.nMax - si.nPage;
360
361 si.fMask = SIF_POS;
362 SetScrollInfo (hwnd, which, &si, TRUE);
363
364 int ox = scroll_ulc_x;
365 int oy = scroll_ulc_y;
366 *var = si.nPos;
367
368 RECT cr, sr;
693916f8 369 ::GetClientRect (hwnd, &cr);
97647369
RC
370 sr = cr;
371 sr.top += header_height;
372 UpdateWindow (hwnd);
373 ScrollWindow (hwnd, ox - scroll_ulc_x, oy - scroll_ulc_y, &sr, &sr);
374 /*
375 sr.bottom = sr.top;
376 sr.top = cr.top;
377 ScrollWindow (hwnd, ox - scroll_ulc_x, 0, &sr, &sr);
378 */
379 if (ox - scroll_ulc_x)
380 {
693916f8 381 ::GetClientRect (listheader, &cr);
97647369
RC
382 sr = cr;
383// UpdateWindow (htmp);
693916f8 384 ::MoveWindow (listheader, -scroll_ulc_x, 0,
97647369
RC
385 headers[last_col].x +
386 headers[last_col].width, header_height, TRUE);
387 }
388 UpdateWindow (hwnd);
389}
390
82306ac2
BD
391/* this means to make the 'category' column wide enough to fit the first 'n'
392 categories for each package. */
393#define NUM_CATEGORY_COL_WIDTH 2
394
97647369
RC
395void
396PickView::init_headers (HDC dc)
397{
398 int i;
399
400 for (i = 0; headers[i].text; i++)
401 {
402 headers[i].width = 0;
403 headers[i].x = 0;
404 }
405
23761198
JT
406 // A margin of 3*GetSystemMetrics(SM_CXEDGE) is used at each side of the
407 // header text. (Probably should use that rather than hard-coding HMARGIN
408 // everywhere)
409 int addend = 2*3*GetSystemMetrics(SM_CXEDGE);
410
411 // accommodate widths of the 'bin' and 'src' checkbox columns
412 note_width (headers, dc, headers[bintick_col].text, addend, bintick_col);
413 note_width (headers, dc, headers[srctick_col].text, addend, srctick_col);
414
82306ac2 415 // accomodate the width of each category name
97647369 416 packagedb db;
0cf68afd
RC
417 for (packagedb::categoriesType::iterator n = packagedb::categories.begin();
418 n != packagedb::categories.end(); ++n)
82306ac2
BD
419 {
420 if (!showObsolete && isObsolete (n->first))
421 continue;
422 note_width (headers, dc, n->first, HMARGIN, cat_col);
423 }
424
425 /* For each package, accomodate the width of the installed version in the
426 current_col, the widths of all other versions in the new_col, and the
427 width of the sdesc for the pkg_col. Also, if this is not a Category
428 view, adjust the 'category' column so that the first NUM_CATEGORY_COL_WIDTH
429 categories from each package fits. */
263157cb 430 for (packagedb::packagecollection::iterator n = db.packages.begin ();
cfae3b8d 431 n != db.packages.end (); ++n)
97647369 432 {
263157cb 433 packagemeta & pkg = *(n->second);
82306ac2
BD
434 if (!showObsolete && isObsolete (pkg.categories))
435 continue;
97647369 436 if (pkg.installed)
3c196821 437 note_width (headers, dc, pkg.installed.Canonical_version (),
97647369 438 HMARGIN, current_col);
82306ac2
BD
439 for (set<packageversion>::iterator i = pkg.versions.begin ();
440 i != pkg.versions.end (); ++i)
0ac305ec
BD
441 {
442 if (*i != pkg.installed)
443 note_width (headers, dc, i->Canonical_version (),
444 HMARGIN + SPIN_WIDTH, new_col);
d19f12fd 445 std::string z = format_1000s(packageversion(*i).source ()->size);
0ac305ec
BD
446 note_width (headers, dc, z, HMARGIN, size_col);
447 z = format_1000s(packageversion(i->sourcePackage ()).source ()->size);
448 note_width (headers, dc, z, HMARGIN, size_col);
449 }
d19f12fd 450 std::string s = pkg.name;
3c054baf 451 if (pkg.SDesc ().size())
d19f12fd 452 s += std::string (": ") + std::string(pkg.SDesc ());
3c054baf 453 note_width (headers, dc, s, HMARGIN, pkg_col);
82306ac2
BD
454
455 if (view_mode != PickView::views::Category && pkg.categories.size () > 2)
456 {
d19f12fd
MB
457 std::string compound_cat("");
458 std::set<std::string, casecompare_lt_op>::const_iterator cat;
82306ac2
BD
459 size_t cnt;
460
461 for (cnt = 0, cat = pkg.categories.begin ();
462 cnt < NUM_CATEGORY_COL_WIDTH && cat != pkg.categories.end ();
463 ++cat)
464 {
afa76033 465 if (casecompare(*cat, "All") == 0)
82306ac2
BD
466 continue;
467 if (compound_cat.size ())
468 compound_cat += ", ";
469 compound_cat += *cat;
470 cnt++;
471 }
472 note_width (headers, dc, compound_cat, HMARGIN, cat_col);
473 }
97647369 474 }
82306ac2
BD
475
476 // ensure that the new_col is wide enough for all the labels
477 const char *captions[] = { "Uninstall", "Skip", "Reinstall", "Retrieve",
478 "Source", "Keep", NULL };
479 for (int i = 0; captions[i]; i++)
480 note_width (headers, dc, captions[i], HMARGIN + SPIN_WIDTH, new_col);
481
482 // finally, compute the actual x values based on widths
97647369
RC
483 headers[0].x = 0;
484 for (i = 1; i <= last_col; i++)
485 headers[i].x = headers[i - 1].x + headers[i - 1].width;
0baffe9a
DK
486 // and allow for resizing to ensure the last column reaches
487 // all the way to the end of the chooser box.
488 headers[last_col].width += total_delta_x;
97647369
RC
489}
490
491
693916f8 492PickView::PickView (Category &cat) : deftrust (TRUST_UNKNOWN),
82306ac2 493contents (*this, cat, 0, false, true), showObsolete (false),
325bb73a 494packageFilterString (), hasWindowRect (false), total_delta_x (0)
97647369 495{
693916f8 496}
97647369 497
693916f8
RC
498void
499PickView::init(views _mode)
500{
501 HDC dc = GetDC (GetHWND());
97647369
RC
502 sysfont = GetStockObject (DEFAULT_GUI_FONT);
503 SelectObject (dc, sysfont);
504 GetTextMetrics (dc, &tm);
505
506 bitmap_dc = CreateCompatibleDC (dc);
82306ac2
BD
507#define LI(x) LoadImage (hinstance, MAKEINTRESOURCE (x), IMAGE_BITMAP, 0, 0, 0);
508 bm_spin = LI (IDB_SPIN);
509 bm_checkyes = LI (IDB_CHECK_YES);
510 bm_checkno = LI (IDB_CHECK_NO);
511 bm_checkna = LI (IDB_CHECK_NA);
512 bm_treeplus = LI (IDB_TREE_PLUS);
513 bm_treeminus = LI (IDB_TREE_MINUS);
514#undef LI
3d4c5ebb
IP
515 icon_dc = CreateCompatibleDC (dc);
516 bm_icon = CreateCompatibleBitmap (dc, 11, 11);
517 SelectObject (icon_dc, bm_icon);
518 rect_icon = CreateRectRgn (0, 0, 11, 11);
97647369
RC
519
520 row_height = (tm.tmHeight + tm.tmExternalLeading + ROW_MARGIN);
82306ac2 521 int irh = tm.tmExternalLeading + tm.tmDescent + 11 + ROW_MARGIN;
97647369
RC
522 if (row_height < irh)
523 row_height = irh;
524
97647369
RC
525 HDLAYOUT hdl;
526 WINDOWPOS wp;
527
528 // Ensure that the common control DLL is loaded, and then create
529 // the header control.
82306ac2
BD
530 INITCOMMONCONTROLSEX controlinfo = { sizeof (INITCOMMONCONTROLSEX),
531 ICC_LISTVIEW_CLASSES };
97647369
RC
532 InitCommonControlsEx (&controlinfo);
533
534 if ((listheader = CreateWindowEx (0, WC_HEADER, (LPCTSTR) NULL,
535 WS_CHILD | WS_BORDER | CCS_NORESIZE |
536 // | HDS_BUTTONS
693916f8 537 HDS_HORZ, 0, 0, 0, 0, GetHWND(),
97647369
RC
538 (HMENU) IDC_CHOOSE_LISTHEADER, hinstance,
539 (LPVOID) NULL)) == NULL)
540 // FIXME: throw an exception
541 exit (10);
542
543 // Retrieve the bounding rectangle of the parent window's
544 // client area, and then request size and position values
545 // from the header control.
bb8e2353 546 RECT rcParent = GetClientRect ();
97647369
RC
547
548 hdl.prc = &rcParent;
549 hdl.pwpos = &wp;
550 if (!SendMessage (listheader, HDM_LAYOUT, 0, (LPARAM) & hdl))
551 // FIXME: throw an exception
552 exit (11);
553
09130e58
RC
554 // Set the font of the listheader, but don't redraw, because its not shown
555 // yet.This message does not return a value, so we are not checking it as we
556 // do above.
557 SendMessage (listheader, WM_SETFONT, (WPARAM) sysfont, FALSE);
97647369
RC
558
559 // Set the size, position, and visibility of the header control.
560 SetWindowPos (listheader, wp.hwndInsertAfter, wp.x, wp.y,
561 wp.cx, wp.cy, wp.flags | SWP_SHOWWINDOW);
562
563 header_height = wp.cy;
82306ac2 564 ReleaseDC (GetHWND (), dc);
97647369
RC
565
566 view_mode = _mode;
82306ac2 567 refresh ();
97647369 568}
49cf3899
RC
569
570PickView::~PickView()
571{
3d4c5ebb
IP
572 DeleteDC (bitmap_dc);
573 DeleteObject (bm_spin);
574 DeleteObject (bm_checkyes);
575 DeleteObject (bm_checkno);
576 DeleteObject (bm_checkna);
577 DeleteObject (bm_treeplus);
578 DeleteObject (bm_treeminus);
579 DeleteObject (rect_icon);
580 DeleteObject (bm_icon);
581 DeleteDC (icon_dc);
49cf3899 582}
693916f8
RC
583
584bool PickView::registerWindowClass ()
585{
586 if (WindowClassAtom != 0)
587 return true;
588
589 // We're not registered yet
590 WNDCLASSEX wc;
591
592 wc.cbSize = sizeof (wc);
593 // Some sensible style defaults
594 wc.style = CS_HREDRAW | CS_VREDRAW;
595 // Our default window procedure. This replaces itself
596 // on the first call with the simpler Window::WindowProcReflector().
597 wc.lpfnWndProc = Window::FirstWindowProcReflector;
598 // No class bytes
599 wc.cbClsExtra = 0;
600 // One pointer to REFLECTION_INFO in the extra window instance bytes
601 wc.cbWndExtra = 4;
602 // The app instance
603 wc.hInstance = hinstance; //GetInstance ();
604 // Use a bunch of system defaults for the GUI elements
605 wc.hIcon = LoadIcon (0, IDI_APPLICATION);
606 wc.hIconSm = NULL;
607 wc.hCursor = LoadCursor (0, IDC_ARROW);
82306ac2 608 wc.hbrBackground = NULL;
693916f8
RC
609 // No menu
610 wc.lpszMenuName = NULL;
611 // We'll get a little crazy here with the class name
612 wc.lpszClassName = "listview";
613
614 // All set, try to register
615 WindowClassAtom = RegisterClassEx (&wc);
616 if (WindowClassAtom == 0)
157dc2b8 617 Log (LOG_BABBLE) << "Failed to register listview " << GetLastError () << endLog;
693916f8
RC
618 return WindowClassAtom != 0;
619}
620
621LRESULT CALLBACK
622PickView::list_vscroll (HWND hwnd, HWND hctl, UINT code, int pos)
623{
d2be933d 624 scroll (hwnd, SB_VERT, &scroll_ulc_y, code);
693916f8
RC
625 return 0;
626}
627
628LRESULT CALLBACK
629PickView::list_hscroll (HWND hwnd, HWND hctl, UINT code, int pos)
630{
d2be933d 631 scroll (hwnd, SB_HORZ, &scroll_ulc_x, code);
693916f8
RC
632 return 0;
633}
634
325bb73a
DK
635void
636PickView::set_vscroll_info (const RECT &r)
637{
638 SCROLLINFO si;
639 memset (&si, 0, sizeof (si));
640 si.cbSize = sizeof (si);
641 si.fMask = SIF_ALL | SIF_DISABLENOSCROLL; /* SIF_RANGE was giving strange behaviour */
642 si.nMin = 0;
643
644 si.nMax = contents.itemcount () * row_height;
645 si.nPage = r.bottom - header_height;
646
647 /* if we are under the minimum display count ,
648 * set the offset to 0
649 */
650 if ((unsigned int) si.nMax <= si.nPage)
651 scroll_ulc_y = 0;
652 si.nPos = scroll_ulc_y;
653
654 SetScrollInfo (GetHWND(), SB_VERT, &si, TRUE);
655}
656
693916f8
RC
657LRESULT CALLBACK
658PickView::list_click (HWND hwnd, BOOL dblclk, int x, int y, UINT hitCode)
659{
c6bf266d 660 int row, refresh __attribute__ ((unused));
693916f8 661
d2be933d 662 if (contents.itemcount () == 0)
693916f8
RC
663 return 0;
664
d2be933d 665 if (y < header_height)
693916f8 666 return 0;
d2be933d
RC
667 x += scroll_ulc_x;
668 y += scroll_ulc_y - header_height;
693916f8 669
d2be933d 670 row = (y + ROW_MARGIN / 2) / row_height;
693916f8 671
d2be933d 672 if (row < 0 || row >= contents.itemcount ())
693916f8
RC
673 return 0;
674
d2be933d 675 refresh = click (row, x);
693916f8 676
325bb73a 677 // XXX we need a method to query the database to see if more
693916f8
RC
678 // than just one package has changed! Until then...
679#if 0
680 if (refresh)
681 {
682#endif
bb8e2353 683 RECT r = GetClientRect ();
325bb73a 684 set_vscroll_info (r);
9c9cfce7 685 InvalidateRect (GetHWND(), &r, TRUE);
693916f8
RC
686#if 0
687 }
688 else
689 {
690 RECT rect;
691 rect.left =
d2be933d 692 headers[new_col].x - scroll_ulc_x;
693916f8 693 rect.right =
d2be933d 694 headers[src_col + 1].x - scroll_ulc_x;
693916f8 695 rect.top =
d2be933d
RC
696 header_height + row * row_height -
697 scroll_ulc_y;
698 rect.bottom = rect.top + row_height;
693916f8
RC
699 InvalidateRect (hwnd, &rect, TRUE);
700 }
701#endif
702 return 0;
703}
704
705/*
706 * LRESULT CALLBACK
707 * PickView::listview_proc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
708 */
709LRESULT
710PickView::WindowProc (UINT message, WPARAM wParam, LPARAM lParam)
711{
82306ac2
BD
712 int wheel_notches;
713 UINT wheel_lines;
714
693916f8
RC
715 switch (message)
716 {
717 case WM_HSCROLL:
4875ac88
MB
718 list_hscroll (GetHWND(), (HWND)lParam, LOWORD(wParam), HIWORD(wParam));
719 return 0;
693916f8 720 case WM_VSCROLL:
4875ac88
MB
721 list_vscroll (GetHWND(), (HWND)lParam, LOWORD(wParam), HIWORD(wParam));
722 return 0;
82306ac2
BD
723 case WM_MOUSEWHEEL:
724 // this is how many 'notches' the wheel scrolled, forward/up = positive
725 wheel_notches = GET_WHEEL_DELTA_WPARAM(wParam) / 120;
726
727 // determine how many lines the user has configred for a mouse scroll
728 SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &wheel_lines, 0);
729
730 if (wheel_lines == 0) // do no scrolling
731 return 0;
732 else if (wheel_lines == WHEEL_PAGESCROLL)
733 scroll (GetHWND (), SB_VERT, &scroll_ulc_y, (wheel_notches > 0) ?
734 SB_PAGEUP : SB_PAGEDOWN);
735 else
736 scroll (GetHWND (), SB_VERT, &scroll_ulc_y, (wheel_notches > 0) ?
737 SB_LINEUP : SB_LINEDOWN, wheel_lines * abs (wheel_notches));
738 return 0; // handled
693916f8 739 case WM_LBUTTONDOWN:
4875ac88
MB
740 list_click (GetHWND(), FALSE, LOWORD(lParam), HIWORD(lParam), wParam);
741 return 0;
693916f8
RC
742 case WM_PAINT:
743 paint (GetHWND());
744 return 0;
745 case WM_NOTIFY:
746 {
82306ac2
BD
747 // pnmh = (LPNMHDR) lParam
748 LPNMHEADER phdr = (LPNMHEADER) lParam;
749 switch (phdr->hdr.code)
750 {
751 case HDN_ITEMCHANGED:
752 if (phdr->hdr.hwndFrom == ListHeader ())
753 {
754 if (phdr->pitem && phdr->pitem->mask & HDI_WIDTH)
755 headers[phdr->iItem].width = phdr->pitem->cxy;
756
757 for (int i = 1; i <= last_col; i++)
758 headers[i].x = headers[i - 1].x + headers[i - 1].width;
759
760 RECT r = GetClientRect ();
761 SCROLLINFO si;
762 si.cbSize = sizeof (si);
763 si.fMask = SIF_ALL | SIF_DISABLENOSCROLL;
764 GetScrollInfo (GetHWND(), SB_HORZ, &si);
765
766 int oldMax = si.nMax;
767 si.nMax = headers[last_col].x + headers[last_col].width;
768 if (si.nTrackPos && oldMax > si.nMax)
769 si.nTrackPos += si.nMax - oldMax;
770
771 si.nPage = r.right;
772 SetScrollInfo (GetHWND(), SB_HORZ, &si, TRUE);
773 InvalidateRect (GetHWND(), &r, TRUE);
774 if (si.nTrackPos && oldMax > si.nMax)
775 scroll (GetHWND(), SB_HORZ, &scroll_ulc_x, SB_THUMBTRACK);
776 }
777 break;
778 }
779 }
780 break;
ee91d9be
RC
781 case WM_SIZE:
782 {
783 // Note: WM_SIZE msgs only appear when 'just' scrolling the window
325bb73a 784 RECT windowRect = GetWindowRect ();
325bb73a 785 if (hasWindowRect)
82306ac2
BD
786 {
787 int dx;
325bb73a
DK
788 if ((dx = windowRect.right - windowRect.left -
789 lastWindowRect.width ()) != 0)
82306ac2 790 {
0baffe9a 791 cat_headers[set_header_column_order (views::Category)].width += dx;
fa8967ca 792 pkg_headers[set_header_column_order (views::PackagePending)].width += dx;
0baffe9a 793 set_header_column_order (view_mode);
82306ac2
BD
794 set_headers ();
795 ::MoveWindow (listheader, -scroll_ulc_x, 0,
796 headers[last_col].x +
797 headers[last_col].width, header_height, TRUE);
0baffe9a 798 total_delta_x += dx;
82306ac2 799 }
325bb73a
DK
800 if (windowRect.bottom - windowRect.top - lastWindowRect.height ())
801 set_vscroll_info (GetClientRect ());
82306ac2
BD
802 }
803 else
325bb73a 804 hasWindowRect = true;
82306ac2 805
325bb73a 806 lastWindowRect = windowRect;
82306ac2 807 return 0;
ee91d9be 808 }
693916f8 809 }
82306ac2
BD
810
811 // default: can't handle this message
812 return DefWindowProc (GetHWND(), message, wParam, lParam);
693916f8
RC
813}
814
3d4c5ebb
IP
815////
816// Turn black into foreground color and white into background color by
817// 1) Filling a square with ~(FG^BG)
818// 2) Blitting the bitmap on it with NOTSRCERASE (white->black; black->FG^BG)
819// 3) Blitting the result on BG with SRCINVERT (white->BG; black->FG)
820void
821PickView::DrawIcon (HDC hdc, int x, int y, HANDLE hIcon)
822{
823 SelectObject (bitmap_dc, hIcon);
824 FillRgn (icon_dc, rect_icon, bg_fg_brush);
825 BitBlt (icon_dc, 0, 0, 11, 11, bitmap_dc, 0, 0, NOTSRCERASE);
826 BitBlt (hdc, x, y, 11, 11, icon_dc, 0, 0, SRCINVERT);
827///////////// On WinNT-based systems, we could've done the below instead
828///////////// See http://support.microsoft.com/default.aspx?scid=kb;en-us;79212
829// SelectObject (hdc, GetSysColorBrush (COLOR_WINDOWTEXT));
830// HBITMAP bm_icon = CreateBitmap (11, 11, 1, 1, NULL);
831// SelectObject (icon_dc, bm_icon);
832// BitBlt (icon_dc, 0, 0, 11, 11, bitmap_dc, 0, 0, SRCCOPY);
833// MaskBlt (hdc, x2, by, 11, 11, bitmap_dc, 0, 0, bm_icon, 0, 0, MAKEROP4 (SRCAND, PATCOPY));
834// DeleteObject (bm_icon);
835}
836
693916f8
RC
837void
838PickView::paint (HWND hwnd)
839{
82306ac2
BD
840 // we want to retrieve the update region before calling BeginPaint,
841 // because after we do that the update region is validated and we can
842 // no longer retrieve it
843 HRGN hUpdRgn = CreateRectRgn (0, 0, 0, 0);
693916f8 844
82306ac2
BD
845 if (GetUpdateRgn (hwnd, hUpdRgn, FALSE) == 0)
846 {
847 // error?
848 return;
849 }
693916f8 850
82306ac2
BD
851 // tell the system that we're going to begin painting our window
852 // it will prevent further WM_PAINT messages from arriving until we're
853 // done, and if any part of our window was invalidated while we are
854 // painting, it will retrigger us so that we can fix it
855 PAINTSTRUCT ps;
856 HDC hdc = BeginPaint (hwnd, &ps);
857
d2be933d 858 SelectObject (hdc, sysfont);
693916f8 859 SetTextColor (hdc, GetSysColor (COLOR_WINDOWTEXT));
3d4c5ebb 860 SetBkColor (hdc, GetSysColor (COLOR_WINDOW));
82306ac2 861 FillRgn (hdc, hUpdRgn, GetSysColorBrush(COLOR_WINDOW));
693916f8 862
3d4c5ebb
IP
863 COLORREF clr = ~GetSysColor (COLOR_WINDOW) ^ GetSysColor (COLOR_WINDOWTEXT);
864 clr = RGB (GetRValue (clr), GetGValue (clr), GetBValue (clr)); // reconvert
865 bg_fg_brush = CreateSolidBrush (clr);
866
693916f8
RC
867 RECT cr;
868 ::GetClientRect (hwnd, &cr);
869
82306ac2
BD
870 int x = cr.left - scroll_ulc_x;
871 int y = cr.top - scroll_ulc_y + header_height;
693916f8 872
82306ac2
BD
873 contents.paint (hdc, hUpdRgn, x, y, 0, (view_mode ==
874 PickView::views::Category) ? 0 : 1);
693916f8 875
d2be933d 876 if (contents.itemcount () == 0)
693916f8
RC
877 {
878 static const char *msg = "Nothing to Install/Update";
879 if (source == IDC_SOURCE_DOWNLOAD)
82306ac2 880 msg = "Nothing to Download";
ee91d9be 881 TextOut (hdc, x + HMARGIN, y, msg, strlen (msg));
693916f8
RC
882 }
883
82306ac2 884 DeleteObject (hUpdRgn);
3d4c5ebb 885 DeleteObject (bg_fg_brush);
693916f8
RC
886 EndPaint (hwnd, &ps);
887}
888
889
890bool
891PickView::Create (Window * parent, DWORD Style, RECT *r)
892{
893
894 // First register the window class, if we haven't already
895 if (!registerWindowClass ())
896 {
897 // Registration failed
898 return false;
899 }
900
82306ac2 901 // Save our parent, we'll probably need it eventually.
693916f8
RC
902 setParent(parent);
903
904 // Create the window instance
82306ac2
BD
905 CreateWindowEx (// Extended Style
906 WS_EX_CLIENTEDGE,
907 // window class atom (name)
908 "listview", //MAKEINTATOM(WindowClassAtom),
909 "listviewwindow", // no title-bar string yet
910 // Style bits
693916f8 911 Style,
82306ac2
BD
912 r ? r->left : CW_USEDEFAULT,
913 r ? r->top : CW_USEDEFAULT,
914 r ? r->right - r->left + 1 : CW_USEDEFAULT,
915 r ? r->bottom - r->top + 1 : CW_USEDEFAULT,
916 // Parent Window
917 parent == NULL ? (HWND)NULL : parent->GetHWND (),
918 // use class menu
919 (HMENU) MAKEINTRESOURCE (IDC_CHOOSE_LIST),
920 // The application instance
921 GetInstance (),
922 // The this ptr, which we'll use to set up
923 // the WindowProc reflection.
693916f8 924 reinterpret_cast<void *>((Window *)this));
693916f8
RC
925 if (GetHWND() == NULL)
926 {
157dc2b8 927 Log (LOG_BABBLE) << "Failed to create PickView " << GetLastError () << endLog;
693916f8
RC
928 return false;
929 }
930
931 return true;
932}
22120c90
RC
933
934void
935PickView::defaultTrust (trusts trust)
936{
937 this->deftrust = trust;
db9818d7 938
22120c90 939 packagedb db;
db9818d7
JT
940 db.defaultTrust(trust);
941
942 // force the picker to redraw
bb8e2353 943 RECT r = GetClientRect ();
22120c90 944 InvalidateRect (this->GetHWND(), &r, TRUE);
22120c90 945}
ec2dbbf0 946
82306ac2 947/* This recalculates all column widths and resets the view */
ec2dbbf0
RC
948void
949PickView::refresh()
950{
82306ac2
BD
951 HDC dc = GetDC (GetHWND ());
952
953 // we must set the font of the DC here, otherwise the width calculations
954 // will be off because the system will use the wrong font metrics
955 sysfont = GetStockObject (DEFAULT_GUI_FONT);
956 SelectObject (dc, sysfont);
957
958 // init headers for the current mode
959 set_headers ();
960 init_headers (dc);
961
962 // save the current mode
963 views cur_view_mode = view_mode;
964
965 // switch to the other type and do those headers
966 view_mode = (view_mode == PickView::views::Category) ?
967 PickView::views::PackageFull : PickView::views::Category;
968 set_headers ();
969 init_headers (dc);
970 ReleaseDC (GetHWND (), dc);
971
972 view_mode = cur_view_mode;
973 setViewMode (view_mode);
ec2dbbf0 974}
This page took 0.158417 seconds and 5 git commands to generate.