Link with mingwex before libntll
[cygwin-setup.git] / PickView.cc
blob7d60d8a8ccdf46a2fc0c3eac048b2b99ce41e15a
1 /*
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
10 * http://www.gnu.org/
12 * Written by Robert Collins <robertc@hotmail.com>
16 #include "PickView.h"
17 #include "PickPackageLine.h"
18 #include "PickCategoryLine.h"
19 #include <algorithm>
20 #include <set>
21 #include <limits.h>
22 #include <shlwapi.h>
24 #include "package_db.h"
25 #include "dialog.h"
26 #include "resource.h"
27 /* For 'source' */
28 #include "state.h"
29 #include "LogSingleton.h"
30 #include "Exception.h"
32 // Scan desired packages and collect the names of packages which provide the
33 // dependencies of other desired packages or are member of category "Base".
34 static void FindNeededPackages (const packagedb & db, std::set<std::string> & needed)
36 std::map<std::string, std::string> providedBy;
37 for (const auto & p : db.packages)
39 const packagemeta & pkg = *p.second;
40 if (!pkg.isBinary ())
41 continue;
42 if (!pkg.desired)
43 continue;
44 for (const PackageSpecification *s : pkg.desired.provides ())
45 providedBy.insert ({s->packageName (), pkg.name});
47 for (const auto & p : db.packages)
49 const packagemeta & pkg = *p.second;
50 if (!pkg.isBinary ())
51 continue;
52 if (pkg.categories.count ("Base"))
53 needed.insert (pkg.name);
54 if (!pkg.desired)
55 continue;
56 for (const PackageSpecification *s : pkg.desired.depends ()) {
57 const auto i = providedBy.find (s->packageName ());
58 if (i == providedBy.end ())
59 continue;
60 needed.insert (i->second);
65 void
66 PickView::setViewMode (views mode)
68 view_mode = mode;
69 packagedb db;
71 size_t i;
72 for (i = 0; i < contents.size(); i++)
74 delete contents[i];
76 contents.clear();
78 if (view_mode == PickView::views::Category)
80 insert_category (cat_tree_root);
82 else
84 std::set<std::string> needed;
85 if (view_mode == PickView::views::PackageRemovable
86 || view_mode == PickView::views::PackageUnneeded)
87 FindNeededPackages (db, needed);
89 // iterate through every package
90 for (packagedb::packagecollection::iterator i = db.packages.begin ();
91 i != db.packages.end (); ++i)
93 packagemeta & pkg = *(i->second);
95 if (!pkg.isBinary())
96 continue;
98 if ( // "Full" : everything
99 (view_mode == PickView::views::PackageFull)
101 // "Pending" : packages that are being added/removed/upgraded
102 || (view_mode == PickView::views::PackagePending &&
103 ((!pkg.desired && pkg.installed) || // uninstall
104 (pkg.desired &&
105 (pkg.picked () || // install bin
106 pkg.srcpicked ())))) // src
108 // "Up to date" : installed packages that will not be changed
109 || (view_mode == PickView::views::PackageKeeps &&
110 (pkg.installed && pkg.desired && !pkg.picked ()
111 && !pkg.srcpicked ()))
113 // "Not installed"
114 || (view_mode == PickView::views::PackageSkips &&
115 (!pkg.desired && !pkg.installed))
117 // "UserPick" : installed packages that were picked by user
118 || (view_mode == PickView::views::PackageUserPicked &&
119 (pkg.installed && pkg.user_picked))
121 // "Removable" : user picked packages that could be safely removed
122 || (view_mode == PickView::views::PackageRemovable &&
123 (pkg.installed && pkg.user_picked && !needed.count (pkg.name)))
125 // "Unneeded" : auto installed packages that could be safely removed
126 || (view_mode == PickView::views::PackageUnneeded &&
127 (pkg.installed && !pkg.user_picked && !needed.count (pkg.name))))
129 // Filter by package name
130 if (packageFilterString.empty ()
131 || StrStrI (pkg.name.c_str (), packageFilterString.c_str ()))
132 insert_pkg (pkg);
137 listview->setContents(&contents, view_mode == PickView::views::Category);
140 PickView::views
141 PickView::getViewMode ()
143 return view_mode;
146 unsigned int
147 PickView::mode_caption (views mode)
149 switch (mode)
151 case views::PackageFull:
152 return IDS_VIEW_FULL;
153 case views::PackagePending:
154 return IDS_VIEW_PENDING;
155 case views::PackageKeeps:
156 return IDS_VIEW_UPTODATE;
157 case views::PackageSkips:
158 return IDS_VIEW_NOTINSTALLED;
159 case views::PackageUserPicked:
160 return IDS_VIEW_PICKED;
161 case views::PackageRemovable:
162 return IDS_VIEW_REMOVABLE;
163 case views::PackageUnneeded:
164 return IDS_VIEW_UNNEEDED;
165 case views::Category:
166 return IDS_VIEW_CATEGORY;
167 default:
168 return 0;
172 /* meant to be called on packagemeta::categories */
173 bool
174 isObsolete (std::set <std::string, casecompare_lt_op> &categories)
176 std::set <std::string, casecompare_lt_op>::const_iterator i;
178 for (i = categories.begin (); i != categories.end (); ++i)
179 if (isObsolete (*i))
180 return true;
181 return false;
184 bool
185 isObsolete (const std::string& catname)
187 if (casecompare(catname, "ZZZRemovedPackages") == 0
188 || casecompare(catname, "_", 1) == 0)
189 return true;
190 return false;
193 /* Sets the mode for showing/hiding obsolete junk packages. */
194 void
195 PickView::setObsolete (bool doit)
197 showObsolete = doit;
198 refresh ();
201 void
202 PickView::insert_pkg (packagemeta & pkg, int indent)
204 if (!showObsolete && isObsolete (pkg.categories))
205 return;
207 contents.push_back(new PickPackageLine(*this, pkg, indent));
210 void
211 PickView::insert_category (CategoryTree *cat_tree)
213 if (!cat_tree)
214 return;
216 const Category *cat = &(cat_tree->category());
218 // Suppress obsolete category when not showing obsolete
219 if ((!showObsolete && isObsolete (cat->first)))
220 return;
222 // if it's not the "All" category
223 int packageCount = 0;
224 bool hasContents = false;
225 bool isAll = casecompare(cat->first, "All") == 0;
226 if (!isAll)
228 // count the number of packages in this category
229 for (std::vector <packagemeta *>::const_iterator i = cat->second.begin ();
230 i != cat->second.end () ; ++i)
232 if (packageFilterString.empty () \
233 || (*i
234 && StrStrI ((*i)->name.c_str (), packageFilterString.c_str ())))
236 packageCount++;
240 // if there are some packages in the category, or we are showing everything,
241 if (packageFilterString.empty () || packageCount)
243 hasContents = true;
247 if (!isAll && !hasContents)
248 return;
250 // insert line for the category
251 contents.push_back(new PickCategoryLine(*this, cat_tree, packageCount, isAll ? 0 : 1));
253 // if not collapsed
254 if (!cat_tree->collapsed())
256 // insert lines for the packages in this category
257 if (!isAll)
259 for (std::vector <packagemeta *>::const_iterator i = cat->second.begin ();
260 i != cat->second.end () ; ++i)
262 if (packageFilterString.empty () \
263 || (*i
264 && StrStrI ((*i)->name.c_str (), packageFilterString.c_str ())))
266 insert_pkg(**i, 2);
271 // recurse for contained categories
272 for (std::vector <CategoryTree *>::iterator i = cat_tree->bucket().begin ();
273 i != cat_tree->bucket().end();
274 i++)
276 insert_category(*i);
281 /* this means to make the 'category' column wide enough to fit the first 'n'
282 categories for each package. */
283 #define NUM_CATEGORY_COL_WIDTH 2
285 void
286 PickView::init_headers (void)
288 listview->noteColumnWidthStart();
290 // width of the 'src' checkbox column just needs to accommodate the
291 // column name
292 listview->noteColumnWidth (srctick_col, std::string(""));
294 // (In category view) accommodate the width of each category name
295 packagedb db;
296 for (packagedb::categoriesType::iterator n = packagedb::categories.begin();
297 n != packagedb::categories.end(); ++n)
299 listview->noteColumnWidth (cat_col, n->first);
302 /* For each package, accomodate the width of the installed version in the
303 current_col, the widths of all other versions in the new_col, and the width
304 of the sdesc for the pkg_col and the first NUM_CATEGORY_COL_WIDTH
305 categories in the category column. */
306 for (packagedb::packagecollection::iterator n = db.packages.begin ();
307 n != db.packages.end (); ++n)
309 packagemeta & pkg = *(n->second);
310 if (pkg.installed)
311 listview->noteColumnWidth (current_col, pkg.installed.Canonical_version ());
312 for (std::set<packageversion>::iterator i = pkg.versions.begin ();
313 i != pkg.versions.end (); ++i)
315 if (*i != pkg.installed)
316 listview->noteColumnWidth (new_col, i->Canonical_version ());
317 std::string z = format_1000s(i->source ()->size);
318 listview->noteColumnWidth (size_col, z);
319 z = format_1000s(i->sourcePackage ().source ()->size);
320 listview->noteColumnWidth (size_col, z);
322 std::string s = pkg.name;
323 listview->noteColumnWidth (pkgname_col, s);
325 s = pkg.SDesc ();
326 listview->noteColumnWidth (pkg_col, s);
328 if (pkg.categories.size () > 2)
330 std::string compound_cat("");
331 std::set<std::string, casecompare_lt_op>::const_iterator cat;
332 size_t cnt;
334 for (cnt = 0, cat = pkg.categories.begin ();
335 cnt < NUM_CATEGORY_COL_WIDTH && cat != pkg.categories.end ();
336 ++cat)
338 if (casecompare(*cat, "All") == 0)
339 continue;
340 if (compound_cat.size ())
341 compound_cat += ", ";
342 compound_cat += *cat;
343 cnt++;
345 listview->noteColumnWidth (cat_col, compound_cat);
349 // also ensure that new_col is wide enough for all the action labels
350 unsigned int captions[] = {
351 IDS_ACTION_UNINSTALL, IDS_ACTION_SKIP, IDS_ACTION_REINSTALL,
352 IDS_ACTION_RETRIEVE, IDS_ACTION_SOURCE, IDS_ACTION_KEEP,
353 IDS_ACTION_UNKNOWN, 0
355 for (int i = 0; captions[i]; i++)
356 listview->noteColumnWidth (new_col, LoadStringW(captions[i]));
358 listview->noteColumnWidthEnd();
359 listview->resizeColumns();
362 PickView::PickView() :
363 deftrust (TRUST_UNKNOWN),
364 showObsolete (false),
365 packageFilterString (),
366 cat_tree_root (NULL)
370 void
371 PickView::init(views _mode, ListView *_listview, Window *_parent)
373 view_mode = _mode;
374 listview = _listview;
375 parent = _parent;
378 void
379 PickView::build_category_tree()
381 /* Build the category tree */
383 /* Start collapsed. TODO: make that a flag */
384 bool collapsed = true;
386 /* Dispose of any existing category tree */
387 if (cat_tree_root)
389 for (std::vector <CategoryTree *>::const_iterator i = cat_tree_root->bucket().begin();
390 i != cat_tree_root->bucket().end();
391 i++)
392 delete *i;
394 delete cat_tree_root;
395 cat_tree_root = NULL;
398 /* Find the 'All' category */
399 for (packagedb::categoriesType::iterator n =
400 packagedb::categories.begin(); n != packagedb::categories.end();
401 ++n)
403 if (casecompare(n->first, "All") == 0)
405 cat_tree_root = new CategoryTree(*n, collapsed);
406 break;
410 /* Add all the other categories as children */
411 for (packagedb::categoriesType::iterator n =
412 packagedb::categories.begin(); n != packagedb::categories.end();
413 ++n)
415 if (casecompare(n->first, "All") == 0)
416 continue;
418 CategoryTree *cat_tree = new CategoryTree(*n, collapsed);
419 cat_tree_root->bucket().push_back(cat_tree);
422 refresh ();
425 PickView::~PickView()
429 void
430 PickView::defaultTrust (trusts trust)
432 this->deftrust = trust;
435 void
436 PickView::refresh()
438 setViewMode (view_mode);