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