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>
17 #include "PickPackageLine.h"
18 #include "PickCategoryLine.h"
24 #include "package_db.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
;
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
;
52 if (pkg
.categories
.count ("Base"))
53 needed
.insert (pkg
.name
);
56 for (const PackageSpecification
*s
: pkg
.desired
.depends ()) {
57 const auto i
= providedBy
.find (s
->packageName ());
58 if (i
== providedBy
.end ())
60 needed
.insert (i
->second
);
66 PickView::setViewMode (views mode
)
72 for (i
= 0; i
< contents
.size(); i
++)
78 if (view_mode
== PickView::views::Category
)
80 insert_category (cat_tree_root
);
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
);
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
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 ()))
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 ()))
137 listview
->setContents(&contents
, view_mode
== PickView::views::Category
);
141 PickView::getViewMode ()
147 PickView::mode_caption (views 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
;
172 /* meant to be called on packagemeta::categories */
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
)
185 isObsolete (const std::string
& catname
)
187 if (casecompare(catname
, "ZZZRemovedPackages") == 0
188 || casecompare(catname
, "_", 1) == 0)
193 /* Sets the mode for showing/hiding obsolete junk packages. */
195 PickView::setObsolete (bool doit
)
202 PickView::insert_pkg (packagemeta
& pkg
, int indent
)
204 if (!showObsolete
&& isObsolete (pkg
.categories
))
207 contents
.push_back(new PickPackageLine(*this, pkg
, indent
));
211 PickView::insert_category (CategoryTree
*cat_tree
)
216 const Category
*cat
= &(cat_tree
->category());
218 // Suppress obsolete category when not showing obsolete
219 if ((!showObsolete
&& isObsolete (cat
->first
)))
222 // if it's not the "All" category
223 int packageCount
= 0;
224 bool hasContents
= false;
225 bool isAll
= casecompare(cat
->first
, "All") == 0;
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 () \
234 && StrStrI ((*i
)->name
.c_str (), packageFilterString
.c_str ())))
240 // if there are some packages in the category, or we are showing everything,
241 if (packageFilterString
.empty () || packageCount
)
247 if (!isAll
&& !hasContents
)
250 // insert line for the category
251 contents
.push_back(new PickCategoryLine(*this, cat_tree
, packageCount
, isAll
? 0 : 1));
254 if (!cat_tree
->collapsed())
256 // insert lines for the packages in this category
259 for (std::vector
<packagemeta
*>::const_iterator i
= cat
->second
.begin ();
260 i
!= cat
->second
.end () ; ++i
)
262 if (packageFilterString
.empty () \
264 && StrStrI ((*i
)->name
.c_str (), packageFilterString
.c_str ())))
271 // recurse for contained categories
272 for (std::vector
<CategoryTree
*>::iterator i
= cat_tree
->bucket().begin ();
273 i
!= cat_tree
->bucket().end();
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
286 PickView::init_headers (void)
288 listview
->noteColumnWidthStart();
290 // width of the 'src' checkbox column just needs to accommodate the
292 listview
->noteColumnWidth (srctick_col
, std::string(""));
294 // (In category view) accommodate the width of each category name
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
);
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
);
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
;
334 for (cnt
= 0, cat
= pkg
.categories
.begin ();
335 cnt
< NUM_CATEGORY_COL_WIDTH
&& cat
!= pkg
.categories
.end ();
338 if (casecompare(*cat
, "All") == 0)
340 if (compound_cat
.size ())
341 compound_cat
+= ", ";
342 compound_cat
+= *cat
;
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 (),
371 PickView::init(views _mode
, ListView
*_listview
, Window
*_parent
)
374 listview
= _listview
;
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 */
389 for (std::vector
<CategoryTree
*>::const_iterator i
= cat_tree_root
->bucket().begin();
390 i
!= cat_tree_root
->bucket().end();
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();
403 if (casecompare(n
->first
, "All") == 0)
405 cat_tree_root
= new CategoryTree(*n
, collapsed
);
410 /* Add all the other categories as children */
411 for (packagedb::categoriesType::iterator n
=
412 packagedb::categories
.begin(); n
!= packagedb::categories
.end();
415 if (casecompare(n
->first
, "All") == 0)
418 CategoryTree
*cat_tree
= new CategoryTree(*n
, collapsed
);
419 cat_tree_root
->bucket().push_back(cat_tree
);
425 PickView::~PickView()
430 PickView::defaultTrust (trusts trust
)
432 this->deftrust
= trust
;
438 setViewMode (view_mode
);