Author: mkudlvasr
Date: Thu Jun 4 12:11:35 2009
New Revision: 57423
URL: http://svn.opensuse.org/viewcvs/yast?rev=57423&view=rev
Log:
Initial commit of package selector plugin. Teared away from yast2-gtk.
Added:
trunk/gtk-pkg/
trunk/gtk-pkg/ChangeLog
trunk/gtk-pkg/MAINTAINER
trunk/gtk-pkg/Makefile.cvs
trunk/gtk-pkg/POTFILES
trunk/gtk-pkg/README
trunk/gtk-pkg/RPMNAME
trunk/gtk-pkg/SUBDIRS
trunk/gtk-pkg/TODO
trunk/gtk-pkg/VERSION
trunk/gtk-pkg/doc/
trunk/gtk-pkg/doc/Makefile.am
trunk/gtk-pkg/doc/autodocs/
trunk/gtk-pkg/doc/autodocs/Makefile.am
trunk/gtk-pkg/src/
trunk/gtk-pkg/src/Makefile.am
trunk/gtk-pkg/src/YGPackageSelector.cc
trunk/gtk-pkg/src/YGPackageSelector.h
trunk/gtk-pkg/src/YGPackageSelectorPluginImpl.cc
trunk/gtk-pkg/src/YGPackageSelectorPluginImpl.h
trunk/gtk-pkg/src/hr.xpm
trunk/gtk-pkg/src/icons/
trunk/gtk-pkg/src/icons/harddisk-full.png (with props)
trunk/gtk-pkg/src/icons/harddisk.png (with props)
trunk/gtk-pkg/src/icons/pkg-available-locked.png (with props)
trunk/gtk-pkg/src/icons/pkg-available.png (with props)
trunk/gtk-pkg/src/icons/pkg-install-auto.png (with props)
trunk/gtk-pkg/src/icons/pkg-install.png (with props)
trunk/gtk-pkg/src/icons/pkg-installed-locked.png (with props)
trunk/gtk-pkg/src/icons/pkg-installed-upgradable-locked.png (with props)
trunk/gtk-pkg/src/icons/pkg-installed-upgradable.png (with props)
trunk/gtk-pkg/src/icons/pkg-installed.png (with props)
trunk/gtk-pkg/src/icons/pkg-list-mode.xpm
trunk/gtk-pkg/src/icons/pkg-locked.png (with props)
trunk/gtk-pkg/src/icons/pkg-remove-auto.png (with props)
trunk/gtk-pkg/src/icons/pkg-remove.png (with props)
trunk/gtk-pkg/src/icons/pkg-tiles-mode.xpm
trunk/gtk-pkg/src/icons/pkg-unlocked.png (with props)
trunk/gtk-pkg/src/icons/pkg-upgrade.png (with props)
trunk/gtk-pkg/src/pkg-selector-help.h
trunk/gtk-pkg/src/ygtkhandlebox.c
trunk/gtk-pkg/src/ygtkhandlebox.h
trunk/gtk-pkg/src/ygtktogglebutton.c
trunk/gtk-pkg/src/ygtktogglebutton.h
trunk/gtk-pkg/src/ygtktooltip.c
trunk/gtk-pkg/src/ygtktooltip.h
trunk/gtk-pkg/src/ygtkzyppwrapper.cc
trunk/gtk-pkg/src/ygtkzyppwrapper.h
trunk/gtk-pkg/src/yzypptags.cc
trunk/gtk-pkg/src/yzypptags.h
trunk/gtk-pkg/src/yzyppwrapper.cc
trunk/gtk-pkg/src/yzyppwrapper.h
Added: trunk/gtk-pkg/ChangeLog
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/ChangeLog?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/ChangeLog (added)
+++ trunk/gtk-pkg/ChangeLog Thu Jun 4 12:11:35 2009
@@ -0,0 +1,4 @@
+2009-05-07 Martin Kudlvasr
+
+ * Make GtkPackageSelector into a plugin package
+ * See yast-gtk Changelog for previous changes
Added: trunk/gtk-pkg/MAINTAINER
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/MAINTAINER?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/MAINTAINER (added)
+++ trunk/gtk-pkg/MAINTAINER Thu Jun 4 12:11:35 2009
@@ -0,0 +1 @@
+Martin Kudlvasr , Ricardo Cruz
Added: trunk/gtk-pkg/Makefile.cvs
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/Makefile.cvs?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/Makefile.cvs (added)
+++ trunk/gtk-pkg/Makefile.cvs Thu Jun 4 12:11:35 2009
@@ -0,0 +1,23 @@
+#
+# Makefile.cvs
+#
+
+LIB = $(shell y2tool get-lib)
+
+PREFIX = /usr
+
+configure: all
+ ./configure --prefix=$(PREFIX) --libdir=$(PREFIX)/$(LIB)
+
+all:
+ y2tool y2autoconf
+ y2tool y2automake
+ autoreconf --force --install
+
+install: configure
+ make
+ make install
+
+reconf: all
+ ./config.status --recheck
+ ./config.status
Added: trunk/gtk-pkg/POTFILES
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/POTFILES?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/POTFILES (added)
+++ trunk/gtk-pkg/POTFILES Thu Jun 4 12:11:35 2009
@@ -0,0 +1,3 @@
+src/YGPackageSelector.cc
+src/yzyppwrapper.cc
+src/pkg-selector-help.h
Added: trunk/gtk-pkg/README
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/README?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/README (added)
+++ trunk/gtk-pkg/README Thu Jun 4 12:11:35 2009
@@ -0,0 +1,48 @@
+/* Light information on YaST-GTK */
+
+License
+
+ This code is licensed under the GNU Lesser General Public License (LGPL)
+ version 2, or, at your option, any higher.
+
+A native GTK+ YaST2 UI !
+
+ This code creates a GTK+ plugin for YaST2. This plugin parallel
+ installs with everything else, and will never be used unless
+ explicitely invoked on the yast2 command line - ie. it won't break
+ your system; go-on you know you want to install it.
+
+Build pre-requisites
+
+ To make this compile you'll need the following packages installed
+ (at a minimum):
+
+ gcc-c++, gtk2-devel, yast2-devtools, yast2-core-devel, yast2-libyui-devel,
+ and libzypp-devel
+
+ They all are distributed with Suse's CDs.
+
+Building / Installing
+
+ make -f Makefile.cvs
+ make && sudo make install [1]
+
+ [1] - if you want sudo not to ask you a password, add yourself to the
+ wheel group, and uncomment the related lines in /etc/sudoers
+
+Running
+
+ /usr/lib/YaST2/bin/y2base /usr/share/doc/packages/yast2-core/libyui/examples/HelloWorld.ycp gtk
+
+ From OpenSuse 10.3 on, it should be picked up automatically if you use Gnome.
+ For other desktops, you can set yast-gtk to be used by editing /etc/sysconfig/yast2 .
+
+ In case of oddness append --nothreads to the cmdline,
+ Also check the log file: ~/.y2log
+
+Documentation
+
+ A code overview is given on the HACKING file.
+ For documentation of YaST in general:
+ http://developer.novell.com/wiki/index.php/Special:Downloads/yast/doc
+
Added: trunk/gtk-pkg/RPMNAME
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/RPMNAME?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/RPMNAME (added)
+++ trunk/gtk-pkg/RPMNAME Thu Jun 4 12:11:35 2009
@@ -0,0 +1 @@
+yast2-gtk-pkg
Added: trunk/gtk-pkg/SUBDIRS
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/SUBDIRS?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/SUBDIRS (added)
+++ trunk/gtk-pkg/SUBDIRS Thu Jun 4 12:11:35 2009
@@ -0,0 +1 @@
+src
Added: trunk/gtk-pkg/TODO
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/TODO?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/TODO (added)
+++ trunk/gtk-pkg/TODO Thu Jun 4 12:11:35 2009
@@ -0,0 +1,33 @@
+/* List of missing features, actual bugs and other issues */
+
+= Regression testing =
+
+* Setup LDTP to run through all the tests/ and provoke as many
+ code-paths as possible
+
+= Look and feel =
+
+* YGRichText: should use GtkHtml when available, so that we get support for
+ tables.
+
+* YGTextEntry / YGMultiLineEdit: Add undo/redo support. The backend code should
+ be shared. We probably want to make an interface for it that is then implemented
+ by those two GTK widgets. Work out a patch for GTK+.
+
+= Package Selector =
+(this little monster diserves a section of its own. =))
+
+* Search syntax: add proper Google syntax support. Consider also adding regex
+ support when Glib ships with it (add radio boxes to entry's context menu).
+
+= Yast-Core =
+
+* Stock icons for buttons (at least the wizard ones)
+ Currently the support is limited to English because it's done by comparing
+ the strings to a list of stock icon ones.
+
+* Button order
+ Should be possible to specify button order. eg: [Ok] [Cancel] vs [Cancel] [Ok]
+ We could hack this through if we had stock images support (may depend
+ on the way they are implemented).
+
Added: trunk/gtk-pkg/VERSION
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/VERSION?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/VERSION (added)
+++ trunk/gtk-pkg/VERSION Thu Jun 4 12:11:35 2009
@@ -0,0 +1 @@
+2.18.0
Added: trunk/gtk-pkg/doc/Makefile.am
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/doc/Makefile.am?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/doc/Makefile.am (added)
+++ trunk/gtk-pkg/doc/Makefile.am Thu Jun 4 12:11:35 2009
@@ -0,0 +1 @@
+SUBDIRS = autodocs
Added: trunk/gtk-pkg/doc/autodocs/Makefile.am
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/doc/autodocs/Makefile.am?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/doc/autodocs/Makefile.am (added)
+++ trunk/gtk-pkg/doc/autodocs/Makefile.am Thu Jun 4 12:11:35 2009
@@ -0,0 +1,5 @@
+#
+# Makefile.am for gtk-pkg/doc/autodocs
+#
+
+include $(top_srcdir)/autodocs-cc-off.ami
Added: trunk/gtk-pkg/src/Makefile.am
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/Makefile.am?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/src/Makefile.am (added)
+++ trunk/gtk-pkg/src/Makefile.am Thu Jun 4 12:11:35 2009
@@ -0,0 +1,73 @@
+#
+# Makefile.am for gtk-pkg/src/
+#
+DATADIR=/usr/share/YaST2/gtk/
+
+AM_CFLAGS = $(GTK_CFLAGS) \
+ -DY2LOG=\"ui-gtk\" \
+ -DTHEMEDIR=\"${themedir}/current\" \
+ -DLOCALEDIR=\"${localedir}\" \
+ -DDATADIR=\"${DATADIR}\"
+AM_CXXFLAGS = $(AM_CFLAGS)
+
+# plugin, libtool forces 'lib' prefix
+# plugin_LTLIBRARIES = libpy2gtk_pkg.la
+plugin_LTLIBRARIES = libpy2gtk_pkg.la
+# XXX ask about version info
+libpy2gtk_pkg_la_LDFLAGS = -version-info 2:0
+
+libpy2gtk_pkg_la_LIBADD = \
+ -L$(plugindir) ${ZYPP_LIBS} \
+ -L$(plugindir) -L$(libdir) -lycp -ly2 -lyui -lm \
+ $(GTK_LIBS) $(ZYPP_LIBS) -ly2util
+
+# XXX prepsat headery
+noinst_HEADERS = \
+ YGPackageSelectorPluginImpl.h \
+ YGPackageSelector.h \
+ pkg-selector-help.h \
+ ygtkhandlebox.h \
+ ygtktogglebutton.h \
+ ygtktooltip.h \
+ ygtkzyppwrapper.h \
+ yzypptags.h \
+ yzyppwrapper.h
+
+libpy2gtk_pkg_la_SOURCES = \
+ YGPackageSelectorPluginImpl.cc \
+ YGPackageSelector.cc \
+ ygtkhandlebox.c \
+ ygtktogglebutton.c \
+ ygtktooltip.c \
+ ygtkzyppwrapper.cc \
+ yzypptags.cc \
+ yzyppwrapper.cc
+
+
+INCLUDES = -I$(includedir) -I$(includedir)/yui -I$(includedir)/gtk ${ZYPP_CFLAGS} $(GTKHTML_CFLAGS) $(WEBKIT_CFLAGS)
+
+EXTRA_DIST = $(dist_share_DATA) \
+ pkg-selector-help.h
+
+sharedir = $(DATADIR)
+dist_share_DATA = \
+ icons/pkg-available-locked.png \
+ icons/pkg-installed-upgradable.png \
+ icons/pkg-remove-auto.png \
+ icons/pkg-available.png \
+ icons/pkg-installed.png \
+ icons/pkg-remove.png \
+ icons/pkg-install.png \
+ icons/pkg-install-auto.png \
+ icons/pkg-upgrade.png \
+ icons/pkg-installed-locked.png \
+ icons/pkg-unlocked.png \
+ icons/pkg-installed-upgradable-locked.png \
+ icons/pkg-locked.png \
+ icons/pkg-tiles-mode.xpm \
+ icons/pkg-list-mode.xpm \
+ icons/harddisk.png \
+ icons/harddisk-full.png
+EXTRA_DIST = $(dist_share_DATA) \
+ hr.xpm
+
Added: trunk/gtk-pkg/src/YGPackageSelector.cc
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/YGPackageSelector.cc?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/src/YGPackageSelector.cc (added)
+++ trunk/gtk-pkg/src/YGPackageSelector.cc Thu Jun 4 12:11:35 2009
@@ -0,0 +1,3362 @@
+/********************************************************************
+ * YaST2-GTK - http://en.opensuse.org/YaST2-GTK *
+ ********************************************************************/
+/*
+ Textdomain "yast2-gtk"
+ */
+
+#define YUILogComponent "gtk"
+#include
+#include
+#include "YGUI.h"
+#include "YGUtils.h"
+#include "YGi18n.h"
+#include "YGDialog.h"
+#include "YPackageSelector.h"
+#include "YGPackageSelector.h"
+
+// singleton like Ypp -- used for the flags
+static YPackageSelector *pkg_selector = 0;
+
+#if YGPackageSelector_ENABLED
+#include "ygtkwizard.h"
+#include "ygtkfindentry.h"
+#include "ygtkmenubutton.h"
+#include "ygtkscrolledwindow.h"
+#include "ygtktogglebutton.h"
+#include "ygtkhtmlwrap.h"
+#include "ygtkrichtext.h"
+#include "ygtkhandlebox.h"
+#include "ygtktooltip.h"
+#include "ygtkzyppwrapper.h"
+
+// utilities
+static GtkWidget *image_new_from_file (const char *filename)
+{
+ std::string file = std::string (DATADIR) + "/" + filename;
+ return gtk_image_new_from_file (file.c_str());
+}
+
+#define GNOME_OPEN_PATH "/usr/bin/gnome-open"
+inline bool CAN_OPEN_URIS()
+{ return g_file_test (GNOME_OPEN_PATH, G_FILE_TEST_IS_EXECUTABLE); }
+inline void OPEN_URI (const char *uri)
+{ system ((std::string (GNOME_OPEN_PATH " ") + uri + " &").c_str()); }
+
+static int busyI = 0;
+static void busyCursor()
+{
+ if (!busyI)
+ YGUI::ui()->busyCursor();
+ // ensure the cursor is actually set and update the UI...
+ while (g_main_context_iteration (NULL, FALSE)) ;
+ busyI++;
+}
+static void normalCursor()
+{
+ busyI = MAX (0, busyI-1);
+ if (!busyI)
+ YGUI::ui()->normalCursor();
+}
+
+static gboolean is_tree_model_iter_separator_cb (GtkTreeModel *model, GtkTreeIter *iter,
+ gpointer data)
+{
+ gint col = data ? GPOINTER_TO_INT (data) : 0;
+ gpointer ptr;
+ gtk_tree_model_get (model, iter, col, &ptr, -1);
+ return ptr == NULL;
+}
+
+static void ensure_visible_size_allocate_cb (GtkWidget *widget, GtkAllocation *alloc)
+{
+ GList *paths;
+ if (GTK_IS_TREE_VIEW (widget)) {
+ GtkTreeView *view = GTK_TREE_VIEW (widget);
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (view);
+ paths = gtk_tree_selection_get_selected_rows (selection, NULL);
+ if (paths && !paths->next) {
+ GtkTreePath *path = (GtkTreePath *) paths->data;
+ gtk_tree_view_scroll_to_cell (view, path, NULL, FALSE, 0, 0);
+ }
+ }
+ else { // if (GTK_IS_ICON_VIEW (widget))
+ GtkIconView *view = GTK_ICON_VIEW (widget);
+ paths = gtk_icon_view_get_selected_items (view);
+ if (paths && !paths->next) {
+ GtkTreePath *path = (GtkTreePath *) paths->data;
+ gtk_icon_view_scroll_to_path (view, path, FALSE, 0, 0);
+ }
+ }
+ g_list_foreach (paths, (GFunc) gtk_tree_path_free, 0);
+ g_list_free (paths);
+}
+
+static void ensure_view_visible_hook (GtkWidget *widget /* tree view or icon view */)
+{
+ g_signal_connect_after (G_OBJECT (widget), "size-allocate",
+ G_CALLBACK (ensure_visible_size_allocate_cb), NULL);
+}
+
+const char *lock_tooltip =
+ "<b>Package lock:</b> prevents the package status from being modified by "
+ "the solver (that is, it won't honour dependencies or collections ties.)";
+
+struct PkgList
+{
+ bool empty() const
+ { return packages.empty(); }
+ bool single() const
+ { return packages.size() == 1; }
+ Ypp::Package *front() const
+ { return packages.front(); }
+
+ bool installed() const
+ { init(); return _allInstalled; }
+ bool notInstalled() const
+ { init(); return _allNotInstalled; }
+ bool upgradable() const
+ { init(); return _allUpgradable; }
+ bool modified() const
+ { init(); return _allModified; }
+ bool locked() const
+ { init(); return _allLocked; }
+ bool unlocked() const
+ { init(); return _allUnlocked; }
+ bool canLock() const
+ { init(); return _allCanLock; }
+
+ void install() // or upgrade
+ {
+ busyCursor();
+ Ypp::get()->startTransactions();
+ for (std::list ::iterator it = packages.begin();
+ it != packages.end(); it++)
+ (*it)->install (0);
+ Ypp::get()->finishTransactions();
+ normalCursor();
+ }
+
+ void remove()
+ {
+ busyCursor();
+ Ypp::get()->startTransactions();
+ for (std::list ::iterator it = packages.begin();
+ it != packages.end(); it++)
+ (*it)->remove();
+ Ypp::get()->finishTransactions();
+ normalCursor();
+ }
+
+ void lock (bool toLock)
+ {
+ busyCursor();
+ Ypp::get()->startTransactions();
+ for (std::list ::iterator it = packages.begin();
+ it != packages.end(); it++)
+ (*it)->lock (toLock);
+ Ypp::get()->finishTransactions();
+ normalCursor();
+ }
+
+ void undo()
+ {
+ busyCursor();
+ Ypp::get()->startTransactions();
+ for (std::list ::iterator it = packages.begin();
+ it != packages.end(); it++)
+ (*it)->undo();
+ Ypp::get()->finishTransactions();
+ normalCursor();
+ }
+
+ void push (Ypp::Package *package)
+ { packages.push_back (package); }
+
+ bool contains (const Ypp::Package *package) const
+ {
+ const_iterator it;
+ for (it = packages.begin(); it != packages.end(); it++)
+ if (*it == package)
+ return true;
+ return false;
+ }
+
+ PkgList() : inited (0)
+ {}
+
+ void clearCache()
+ { inited = 0; }
+
+ typedef std::list ::const_iterator const_iterator;
+ const_iterator begin() const
+ { return packages.begin(); }
+ const_iterator end() const
+ { return packages.end(); }
+
+private:
+ void init() const
+ { PkgList *packages = const_cast (this); packages->_init(); }
+ void _init()
+ {
+ if (inited) return; inited = 1;
+ if (packages.empty())
+ _allInstalled = _allNotInstalled = _allUpgradable = _allModified =
+ _allLocked = _allUnlocked = _allCanLock = false;
+ else {
+ _allInstalled = _allNotInstalled = _allUpgradable = _allModified =
+ _allLocked = _allUnlocked = _allCanLock = true;
+ for (std::list ::const_iterator it = packages.begin();
+ it != packages.end(); it++) {
+ if (!(*it)->isInstalled()) {
+ _allInstalled = false;
+ _allUpgradable = false;
+ }
+ else {
+ _allNotInstalled = false;
+ const Ypp::Package::Version *version = (*it)->getAvailableVersion(0);
+ if (!version || version->cmp <= 0)
+ _allUpgradable = false;
+ }
+ if ((*it)->toModify()) {
+ // if modified, can't be locked or unlocked
+ _allLocked = _allUnlocked = false;
+ }
+ else
+ _allModified = false;
+ if ((*it)->isLocked())
+ _allUnlocked = false;
+ else
+ _allLocked = false;
+ if (!(*it)->canLock())
+ _allCanLock = false;
+ }
+ }
+ }
+
+ std::list packages;
+ guint inited : 2, _allInstalled : 2, _allNotInstalled : 2, _allUpgradable : 2,
+ _allModified : 2, _allLocked : 2, _allUnlocked : 2, _allCanLock : 2;
+};
+
+// UI controls
+
+class PackagesView
+{
+public:
+ struct Listener {
+ virtual void packagesSelected (const PkgList &packages) = 0;
+ };
+ void setListener (Listener *listener)
+ { m_listener = listener; }
+
+private:
+Listener *m_listener;
+
+ void packagesSelected (const PkgList &packages)
+ {
+ if (m_listener && GTK_WIDGET_REALIZED (m_bin)) {
+ busyCursor();
+ m_listener->packagesSelected (packages);
+ normalCursor();
+ }
+ }
+
+ struct View
+ {
+ PackagesView *m_parent;
+ GtkWidget *m_widget, *m_popup_hack;
+ View (PackagesView *parent) : m_parent (parent), m_popup_hack (NULL)
+ {}
+
+ virtual ~View()
+ {
+ if (m_popup_hack) gtk_widget_destroy (m_popup_hack);
+ }
+
+ virtual void setModel (GtkTreeModel *model) = 0;
+ virtual GList *getSelectedPaths (GtkTreeModel **model) = 0;
+ virtual void selectAll() = 0;
+ virtual void unselectAll() = 0;
+
+ virtual int countSelected()
+ {
+ int count = 0;
+ GtkTreeModel *model;
+ GList *paths = getSelectedPaths (&model);
+ for (GList *i = paths; i; i = i->next) {
+ GtkTreePath *path = (GtkTreePath *) i->data;
+ gtk_tree_path_free (path);
+ count++;
+ }
+ g_list_free (paths);
+ return count;
+ }
+
+ PkgList getSelected()
+ {
+ GtkTreeModel *model;
+ GList *paths = getSelectedPaths (&model);
+ PkgList packages;
+ for (GList *i = paths; i; i = i->next) {
+ Ypp::Package *package;
+ GtkTreePath *path = (GtkTreePath *) i->data;
+ GtkTreeIter iter;
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter, YGtkZyppModel::PTR_COLUMN, &package, -1);
+ gtk_tree_path_free (path);
+
+ if (package)
+ packages.push (package);
+ }
+ g_list_free (paths);
+ return packages;
+ }
+
+ void signalSelected()
+ {
+ PkgList packages = getSelected();
+ m_parent->packagesSelected (packages);
+ }
+
+ void signalPopup (int button, int event_time)
+ {
+ // GtkMenu emits "deactivate" before Items notifications, so there isn't
+ // a better way to de-allocate the popup
+ if (m_popup_hack) gtk_widget_destroy (m_popup_hack);
+ GtkWidget *menu = m_popup_hack = gtk_menu_new();
+
+ struct inner {
+ static void appendItem (GtkWidget *menu, const char *label,
+ const char *tooltip, const char *icon, bool sensitive,
+ void (& callback) (GtkMenuItem *item, View *pThis), View *pThis)
+ {
+ GtkWidget *item;
+ if (icon) {
+ if (label) {
+ item = gtk_image_menu_item_new_with_mnemonic (label);
+ GtkWidget *image;
+ if (*icon == 'g')
+ image = gtk_image_new_from_stock (icon, GTK_ICON_SIZE_MENU);
+ else
+ image = image_new_from_file (icon);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+ }
+ else
+ item = gtk_image_menu_item_new_from_stock (icon, NULL);
+ }
+ else
+ item = gtk_menu_item_new_with_mnemonic (label);
+ if (tooltip)
+ gtk_widget_set_tooltip_markup (item, tooltip);
+ if (!sensitive)
+ gtk_widget_set_sensitive (item, FALSE);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (callback), pThis);
+ }
+ static void install_cb (GtkMenuItem *item, View *pThis)
+ {
+ PkgList packages = pThis->getSelected();
+ packages.install();
+ }
+ static void remove_cb (GtkMenuItem *item, View *pThis)
+ {
+ PkgList packages = pThis->getSelected();
+ packages.remove();
+ }
+ static void undo_cb (GtkMenuItem *item, View *pThis)
+ {
+ PkgList packages = pThis->getSelected();
+ packages.undo();
+ }
+ static void lock_cb (GtkMenuItem *item, View *pThis)
+ {
+ PkgList packages = pThis->getSelected();
+ packages.lock (true);
+ }
+ static void unlock_cb (GtkMenuItem *item, View *pThis)
+ {
+ PkgList packages = pThis->getSelected();
+ packages.lock (false);
+ }
+ static void select_all_cb (GtkMenuItem *item, View *pThis)
+ {
+ pThis->selectAll();
+ }
+ };
+
+ PkgList packages = getSelected();
+ bool empty = true, canLock = packages.canLock(), unlocked = packages.unlocked();
+ bool locked = !unlocked && canLock;
+ if (packages.notInstalled())
+ inner::appendItem (menu, _("_Install"), 0, GTK_STOCK_SAVE,
+ !locked, inner::install_cb, this), empty = false;
+ if (packages.upgradable())
+ inner::appendItem (menu, _("_Upgrade"), 0, GTK_STOCK_GOTO_TOP,
+ !locked, inner::install_cb, this), empty = false;
+ if (packages.installed())
+ inner::appendItem (menu, _("_Remove"), 0, GTK_STOCK_DELETE,
+ !locked, inner::remove_cb, this), empty = false;
+ if (packages.modified())
+ inner::appendItem (menu, _("_Undo"), 0, GTK_STOCK_UNDO,
+ true, inner::undo_cb, this), empty = false;
+ if (canLock) {
+ if (packages.locked())
+ inner::appendItem (menu, _("_Unlock"), _(lock_tooltip), "pkg-unlocked.png",
+ true, inner::unlock_cb, this), empty = false;
+ if (unlocked)
+ inner::appendItem (menu, _("_Lock"), _(lock_tooltip), "pkg-locked.png",
+ true, inner::lock_cb, this), empty = false;
+ }
+ if (!empty)
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), gtk_separator_menu_item_new());
+ inner::appendItem (menu, 0, 0, GTK_STOCK_SELECT_ALL,
+ true, inner::select_all_cb, this);
+
+ gtk_menu_attach_to_widget (GTK_MENU (menu), m_widget, NULL);
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, button, event_time);
+ gtk_widget_show_all (menu);
+ }
+ };
+ // TreeView: base class for ListView and CheckView (see append*Col methods)
+ struct TreeView : public View
+ {
+ bool m_isTree, m_descriptiveTooltip;
+ TreeView (bool isTree, bool descriptiveTooltip, bool editable, PackagesView *parent)
+ : View (parent), m_isTree (isTree), m_descriptiveTooltip (descriptiveTooltip)
+ {
+ GtkTreeView *view = GTK_TREE_VIEW (m_widget = ygtk_tree_view_new());
+ gtk_tree_view_set_headers_visible (view, FALSE);
+ gtk_tree_view_set_search_column (view, YGtkZyppModel::NAME_COLUMN);
+ gtk_tree_view_set_fixed_height_mode (view, TRUE);
+ gtk_tree_view_set_show_expanders (view, FALSE); /* would conflict with icons */
+
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (view);
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
+ g_signal_connect (G_OBJECT (selection), "changed",
+ G_CALLBACK (packages_selected_cb), this);
+ gtk_tree_selection_set_select_function (selection, can_select_row_cb,
+ this, NULL);
+ gtk_widget_show (m_widget);
+
+ if (editable) {
+ g_signal_connect (G_OBJECT (m_widget), "row-activated",
+ G_CALLBACK (package_activated_cb), this);
+ g_signal_connect (G_OBJECT (m_widget), "right-click",
+ G_CALLBACK (popup_menu_cb), this);
+ }
+ gtk_widget_set_has_tooltip (m_widget, TRUE);
+ g_signal_connect (G_OBJECT (m_widget), "query-tooltip",
+ G_CALLBACK (query_tooltip_cb), this);
+ ensure_view_visible_hook (m_widget);
+ }
+
+ void appendIconCol()
+ {
+ GtkTreeView *view = GTK_TREE_VIEW (m_widget);
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer = gtk_cell_renderer_pixbuf_new();
+ if (m_isTree) {
+ int height = MAX (34, YGUtils::getCharsHeight (m_widget, 2));
+ gtk_cell_renderer_set_fixed_size (renderer, -1, height);
+ }
+ column = gtk_tree_view_column_new_with_attributes (
+ "", renderer, "pixbuf", YGtkZyppModel::ICON_COLUMN, NULL);
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
+ gtk_tree_view_column_set_fixed_width (column, 38);
+ gtk_tree_view_append_column (view, column);
+ }
+ void appendTextCol (int modelCol)
+ {
+ GtkTreeView *view = GTK_TREE_VIEW (m_widget);
+ GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
+ g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+ gboolean reverse = gtk_widget_get_default_direction() == GTK_TEXT_DIR_RTL;
+ if (reverse) { // work-around: Pango ignored alignment flag on RTL
+ gtk_widget_set_direction (m_widget, GTK_TEXT_DIR_LTR);
+ g_object_set (renderer, "alignment", PANGO_ALIGN_RIGHT, NULL);
+ }
+ GtkTreeViewColumn *column;
+ column = gtk_tree_view_column_new_with_attributes (
+ "", renderer, "markup", modelCol, NULL);
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
+ gtk_tree_view_column_set_fixed_width (column, 50 /* it will expand */);
+ gtk_tree_view_column_set_expand (column, TRUE);
+ gtk_tree_view_insert_column (view, column, reverse ? 0 : -1);
+ }
+ void appendCheckCol()
+ {
+ GtkTreeView *view = GTK_TREE_VIEW (m_widget);
+ GtkCellRenderer *renderer = gtk_cell_renderer_toggle_new();
+ GtkTreeViewColumn *column;
+ column = gtk_tree_view_column_new_with_attributes (
+ "", renderer, "active", YGtkZyppModel::IS_INSTALLED_COLUMN, NULL);
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
+ // it seems like GtkCellRendererToggle has no width at start, so fixed doesn't work
+ gtk_tree_view_column_set_fixed_width (column, 25);
+ gtk_tree_view_append_column (view, column);
+ g_signal_connect (G_OBJECT (renderer), "toggled",
+ G_CALLBACK (toggled_cb), this);
+ }
+
+ virtual void setModel (GtkTreeModel *model)
+ {
+ GtkTreeView *view = GTK_TREE_VIEW (m_widget);
+ gtk_tree_view_set_model (view, model);
+ if (m_isTree)
+ gtk_tree_view_expand_all (view);
+ if (GTK_WIDGET_REALIZED (m_widget))
+ gtk_tree_view_scroll_to_point (view, 0, 0);
+ }
+
+ GtkTreeSelection *getTreeSelection()
+ { return gtk_tree_view_get_selection (GTK_TREE_VIEW (m_widget)); }
+
+ virtual GList *getSelectedPaths (GtkTreeModel **model)
+ { return gtk_tree_selection_get_selected_rows (getTreeSelection(), model); }
+
+ virtual void selectAll()
+ { gtk_tree_selection_select_all (getTreeSelection()); }
+
+ virtual void unselectAll()
+ { gtk_tree_selection_unselect_all (getTreeSelection()); }
+
+ virtual int countSelected()
+ { return gtk_tree_selection_count_selected_rows (getTreeSelection()); }
+
+ static void packages_selected_cb (GtkTreeSelection *selection, View *pThis)
+ { pThis->signalSelected(); }
+
+ static void package_activated_cb (GtkTreeView *view, GtkTreePath *path,
+ GtkTreeViewColumn *column, View *pThis)
+ {
+ PkgList packages = pThis->getSelected();
+ if (packages.notInstalled() || packages.upgradable())
+ packages.install();
+ }
+
+ static void toggled_cb (GtkCellRendererToggle *renderer, gchar *path_str,
+ TreeView *pThis)
+ {
+ Ypp::Package *package = 0;
+ GtkTreeIter iter;
+ GtkTreeView *view = GTK_TREE_VIEW (pThis->m_widget);
+ GtkTreeModel *model = gtk_tree_view_get_model (view);
+ gtk_tree_model_get_iter_from_string (model, &iter, path_str);
+ gtk_tree_model_get (model, &iter, YGtkZyppModel::PTR_COLUMN, &package, -1);
+ if (package->toModify())
+ package->undo();
+ else if (package->isInstalled())
+ package->remove();
+ else
+ package->install (0);
+ }
+
+ static void popup_menu_cb (YGtkTreeView *view, gboolean outreach, View *pThis)
+ { if (!outreach) pThis->signalPopup(3, gtk_get_current_event_time()); }
+
+ static gboolean can_select_row_cb (GtkTreeSelection *selection, GtkTreeModel *model,
+ GtkTreePath *path, gboolean path_currently_selected, gpointer data)
+ {
+ void *package;
+ GtkTreeIter iter;
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter, YGtkZyppModel::PTR_COLUMN, &package, -1);
+ return package != NULL;
+ }
+
+ static gboolean query_tooltip_cb (GtkWidget *widget, gint x, gint y,
+ gboolean keyboard_mode, GtkTooltip *tooltip, TreeView *pThis)
+ {
+ GtkTreeView *view = GTK_TREE_VIEW (widget);
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ if (gtk_tree_view_get_tooltip_context (view,
+ &x, &y, keyboard_mode, &model, &path, &iter)) {
+ gtk_tree_view_set_tooltip_row (view, tooltip, path);
+ gtk_tree_path_free (path);
+
+ Ypp::Package *package = 0;
+ gtk_tree_model_get (model, &iter, YGtkZyppModel::PTR_COLUMN, &package, -1);
+ if (!package) return FALSE;
+
+ std::string text;
+ if (!pThis->m_descriptiveTooltip) {
+ GtkTreeViewColumn *column;
+ int bx, by;
+ gtk_tree_view_convert_widget_to_bin_window_coords (
+ view, x, y, &bx, &by);
+ gtk_tree_view_get_path_at_pos (
+ view, x, y, NULL, &column, NULL, NULL);
+ int status_col =
+ gtk_widget_get_default_direction() == GTK_TEXT_DIR_RTL ? 1 : 0;
+ if (column == gtk_tree_view_get_column (view, status_col)) {
+ if (package->toInstall()) {
+ if (package->isInstalled())
+ text = _("To re-install a different version");
+ else
+ text = _("To install");
+ }
+ else if (package->toRemove())
+ text = _("To remove");
+ else if (package->isInstalled()) {
+ text = _("Installed");
+ if (package->hasUpgrade())
+ text += _(" (upgrade available)");
+ }
+ else
+ text = _("Not installed");
+ if (package->isAuto())
+ text += _("\n<i>status changed by the dependency solver</i>");
+ if (package->isLocked())
+ text += _("\n<i>locked: right-click to unlock</i>");
+ }
+ }
+ else {
+ text = std::string ("<b>") + package->name() + "</b>\n";
+ text += package->description (GTK_MARKUP);
+ }
+ if (text.empty())
+ return FALSE;
+ gtk_tooltip_set_markup (tooltip, text.c_str());
+
+ GdkPixbuf *pixbuf = 0;
+ switch (package->type())
+ {
+ case Ypp::Package::LANGUAGE_TYPE: {
+ std::string filename (package->icon());
+ if (!filename.empty())
+ pixbuf = YGUtils::loadPixbuf (filename.c_str());
+ break;
+ }
+ default:
+ break;
+ }
+ if (!pixbuf)
+ gtk_tree_model_get (model, &iter,
+ YGtkZyppModel::ICON_COLUMN, &pixbuf, -1);
+ if (pixbuf) {
+ gtk_tooltip_set_icon (tooltip, pixbuf);
+ g_object_unref (G_OBJECT (pixbuf));
+ }
+ return TRUE;
+ }
+ return FALSE;
+ }
+ };
+ struct ListView : public TreeView
+ {
+ ListView (bool isTree, bool descriptiveTooltip, bool editable, PackagesView *parent)
+ : TreeView (isTree, descriptiveTooltip, editable, parent)
+ {
+ appendIconCol();
+ appendTextCol (YGtkZyppModel::NAME_DESCRIPTION_COLUMN);
+ }
+ };
+ struct CheckView : public TreeView
+ {
+ CheckView (PackagesView *parent)
+ : TreeView (false, false, true, parent)
+ {
+ appendCheckCol();
+ appendTextCol (YGtkZyppModel::NAME_COLUMN);
+ }
+ };
+ struct IconView : public View
+ {
+ IconView (bool editable, PackagesView *parent)
+ : View (parent)
+ {
+ GtkIconView *view = GTK_ICON_VIEW (m_widget = gtk_icon_view_new());
+ gtk_icon_view_set_text_column (view, YGtkZyppModel::NAME_TRUNCATE_COLUMN);
+ gtk_icon_view_set_pixbuf_column (view, YGtkZyppModel::ICON_COLUMN);
+ gtk_icon_view_set_selection_mode (view, GTK_SELECTION_MULTIPLE);
+ g_signal_connect (G_OBJECT (m_widget), "selection-changed",
+ G_CALLBACK (packages_selected_cb), this);
+ gtk_widget_show (m_widget);
+
+ if (editable) {
+ g_signal_connect (G_OBJECT (m_widget), "popup-menu",
+ G_CALLBACK (popup_key_cb), this);
+ g_signal_connect_after (G_OBJECT (m_widget), "button-press-event",
+ G_CALLBACK (popup_button_after_cb), this);
+ }
+ ensure_view_visible_hook (m_widget);
+ }
+
+ virtual void setModel (GtkTreeModel *model)
+ {
+ gtk_icon_view_set_model (GTK_ICON_VIEW (m_widget), model);
+ if (GTK_WIDGET_REALIZED (m_widget)) {
+ GtkTreePath *path = gtk_tree_path_new_first();
+ gtk_icon_view_scroll_to_path (GTK_ICON_VIEW (m_widget),
+ path, FALSE, 0, 0);
+ gtk_tree_path_free (path);
+ }
+ }
+
+ virtual GList *getSelectedPaths (GtkTreeModel **model)
+ {
+ GtkIconView *view = GTK_ICON_VIEW (m_widget);
+ if (model)
+ *model = gtk_icon_view_get_model (view);
+ GList *paths = gtk_icon_view_get_selected_items (view);
+ return paths;
+ }
+
+ virtual void selectAll()
+ { gtk_icon_view_select_all (GTK_ICON_VIEW (m_widget)); }
+ virtual void unselectAll()
+ { gtk_icon_view_unselect_all (GTK_ICON_VIEW (m_widget)); }
+
+ static void packages_selected_cb (GtkIconView *view, View *pThis)
+ { pThis->signalSelected(); }
+
+ static gboolean popup_button_after_cb (GtkWidget *widget, GdkEventButton *event,
+ View *pThis)
+ {
+ if (event->type == GDK_BUTTON_PRESS && event->button == 3)
+ pThis->signalPopup (3, event->time);
+ return FALSE;
+ }
+ static gboolean popup_key_cb (GtkWidget *widget, View *pThis)
+ { pThis->signalPopup (0, gtk_get_current_event_time()); return TRUE; }
+ };
+
+GtkWidget *m_bin;
+GtkTreeModel *m_model;
+View *m_view;
+bool m_isTree, m_descriptiveTooltip;
+
+public:
+ GtkWidget *getWidget()
+ { return m_bin; }
+
+ PackagesView (bool useScrollWindow, bool isTree, bool descriptiveTooltip, bool enableTilesMode, bool editable)
+ : m_listener (NULL), m_model (NULL), m_view (NULL), m_isTree (isTree), m_descriptiveTooltip (descriptiveTooltip)
+ {
+ if (useScrollWindow) {
+ m_bin = ygtk_scrolled_window_new();
+ if (enableTilesMode) {
+ GtkWidget *buttons = gtk_vbox_new (FALSE, 0), *button;
+ button = create_toggle_button ("pkg-list-mode.xpm", _("View as list"), NULL);
+ gtk_box_pack_start (GTK_BOX (buttons), button, FALSE, TRUE, 0);
+ button = create_toggle_button ("pkg-tiles-mode.xpm", _("View as grid"), button);
+ gtk_box_pack_start (GTK_BOX (buttons), button, FALSE, TRUE, 0);
+ gtk_widget_show_all (buttons);
+
+ ygtk_scrolled_window_set_corner_widget (YGTK_SCROLLED_WINDOW (m_bin), buttons);
+ }
+ }
+ else
+ m_bin = gtk_event_box_new();
+ setMode (LIST_MODE, editable);
+ }
+
+ ~PackagesView()
+ {
+ if (m_model)
+ g_object_unref (G_OBJECT (m_model));
+ delete m_view;
+ }
+
+ enum ViewMode {
+ LIST_MODE, ICON_MODE, CHECK_MODE
+ };
+ void setMode (ViewMode mode, bool editable)
+ {
+ busyCursor();
+ if (m_view)
+ gtk_container_remove (GTK_CONTAINER (m_bin), m_view->m_widget);
+ delete m_view;
+ switch (mode) {
+ case LIST_MODE:
+ m_view = new ListView (m_isTree, m_descriptiveTooltip, editable, this);
+ break;
+ case ICON_MODE:
+ m_view = new IconView (editable, this);
+ break;
+ case CHECK_MODE:
+ m_view = new CheckView (this);
+ break;
+ }
+ gtk_container_add (GTK_CONTAINER (m_bin), m_view->m_widget);
+ if (m_model)
+ m_view->setModel (m_model);
+
+ packagesSelected (PkgList());
+ gtk_widget_show_all (m_bin);
+ normalCursor();
+ }
+
+ void setPool (Ypp::Pool *pool)
+ {
+ busyCursor();
+ if (m_model)
+ g_object_unref (G_OBJECT (m_model));
+
+ YGtkZyppModel *zmodel = ygtk_zypp_model_new (pool);
+ m_model = GTK_TREE_MODEL (zmodel);
+ if (m_view) {
+ m_view->setModel (m_model);
+ packagesSelected (PkgList());
+ }
+ normalCursor();
+ }
+
+ void setQuery (Ypp::QueryPool::Query *query)
+ {
+ Ypp::QueryPool *pool = new Ypp::QueryPool (query);
+ setPool (pool);
+ }
+
+ PkgList getSelected()
+ { return m_view->getSelected(); }
+
+ void unselectAll()
+ { m_view->unselectAll(); }
+
+private:
+ GtkWidget *create_toggle_button (const char *icon, const char *tooltip, GtkWidget *member)
+ {
+ GSList *group = NULL;
+ if (member)
+ group = ygtk_toggle_button_get_group (YGTK_TOGGLE_BUTTON (member));
+ GtkWidget *button = ygtk_toggle_button_new (group);
+ gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+ gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
+ if (!member)
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
+
+ // set button tiny
+ GtkRcStyle *rcstyle = gtk_rc_style_new();
+ rcstyle->xthickness = rcstyle->ythickness = 0;
+ gtk_widget_modify_style (button, rcstyle);
+ gtk_rc_style_unref (rcstyle),
+
+ gtk_widget_set_tooltip_text (button, tooltip);
+ g_signal_connect (G_OBJECT (button), "toggle-changed",
+ G_CALLBACK (mode_toggled_cb), this);
+
+ GtkWidget *image = image_new_from_file (icon);
+ gtk_container_add (GTK_CONTAINER (button), image);
+ return button;
+ }
+
+ static void mode_toggled_cb (GtkToggleButton *toggle, gint nb, PackagesView *pThis)
+ { pThis->setMode ((ViewMode) nb, true); }
+};
+
+class ChangesPane : public Ypp::Pool::Listener
+{
+ struct Entry {
+ GtkWidget *m_box, *m_label, *m_button;
+ GtkWidget *getWidget() { return m_box; }
+
+ Entry (Ypp::Package *package)
+ {
+ m_label = gtk_label_new ("");
+ gtk_misc_set_alignment (GTK_MISC (m_label), 0, 0.5);
+ gtk_label_set_ellipsize (GTK_LABEL (m_label), PANGO_ELLIPSIZE_END);
+ m_button = gtk_button_new();
+ gtk_widget_set_tooltip_text (m_button, _("Undo"));
+ GtkWidget *undo_image = gtk_image_new_from_stock (GTK_STOCK_UNDO, GTK_ICON_SIZE_MENU);
+ gtk_button_set_image (GTK_BUTTON (m_button), undo_image);
+ m_box = gtk_hbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (m_box), m_label, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (m_box), m_button, FALSE, FALSE, 0);
+ gtk_widget_show_all (m_box);
+ modified (package);
+ g_signal_connect (G_OBJECT (m_button), "clicked",
+ G_CALLBACK (undo_clicked_cb), package);
+ }
+
+ void modified (Ypp::Package *package)
+ {
+ const Ypp::Package::Version *version = 0;
+ std::string text, action;
+ if (package->toInstall (&version)) {
+ if (package->isInstalled()) {
+ if (version->cmp > 0)
+ action = _("upgrade");
+ else if (version->cmp < 0)
+ action = _("downgrade");
+ else
+ action = _("re-install");
+ }
+ else if (package->type() == Ypp::Package::PATCH_TYPE)
+ action = _("patch");
+ else
+ action = _("install");
+ }
+ else
+ action = _("remove");
+ text = action + " " + package->name();
+ if (package->isAuto()) {
+ text = "\t" + text;
+ gtk_widget_hide (m_button);
+ }
+ else
+ gtk_widget_show (m_button);
+ gtk_label_set_text (GTK_LABEL (m_label), text.c_str());
+ std::string tooltip = action + " " + package->name();
+ if (version)
+ tooltip += std::string (_("\nfrom")) + " <i>" + version->repo->name + "</i>";
+ gtk_widget_set_tooltip_markup (m_label, tooltip.c_str());
+ }
+
+ static void undo_clicked_cb (GtkButton *button, Ypp::Package *package)
+ {
+ package->undo();
+ }
+ };
+
+GtkWidget *m_box, *m_entries_box;
+Ypp::Pool *m_pool;
+GList *m_entries;
+
+public:
+ GtkWidget *getWidget()
+ { return m_box; }
+
+ ChangesPane()
+ : m_entries (NULL)
+ {
+ GtkWidget *heading = gtk_label_new (_("Changes:"));
+ YGUtils::setWidgetFont (heading, PANGO_STYLE_NORMAL, PANGO_WEIGHT_BOLD, PANGO_SCALE_MEDIUM);
+ gtk_misc_set_alignment (GTK_MISC (heading), 0, 0.5);
+ m_entries_box = gtk_vbox_new (FALSE, 4);
+
+ GtkWidget *scroll = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
+ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scroll),
+ m_entries_box);
+ GtkWidget *port = gtk_bin_get_child (GTK_BIN (scroll));
+ gtk_viewport_set_shadow_type (GTK_VIEWPORT (port), GTK_SHADOW_NONE);
+
+ GtkWidget *vbox = gtk_vbox_new (FALSE, 6);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
+ gtk_box_pack_start (GTK_BOX (vbox), heading, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), scroll, TRUE, TRUE, 0);
+
+ ygtk_wizard_set_information_expose_hook (vbox, &vbox->allocation);
+ ygtk_wizard_set_information_expose_hook (m_entries_box, &m_entries_box->allocation);
+
+ int width = YGUtils::getCharsWidth (vbox, 32);
+ gtk_widget_set_size_request (vbox, width, -1);
+ gtk_widget_show_all (vbox);
+
+ m_box = ygtk_handle_box_new();
+ gtk_container_add (GTK_CONTAINER (m_box), vbox);
+ gtk_handle_box_set_handle_position (GTK_HANDLE_BOX (m_box), GTK_POS_TOP);
+ gtk_handle_box_set_snap_edge (GTK_HANDLE_BOX (m_box), GTK_POS_RIGHT);
+
+ Ypp::QueryPool::Query *query = new Ypp::QueryPool::Query();
+ query->setToModify (true);
+ if (pkg_selector->onlineUpdateMode())
+ query->addType (Ypp::Package::PATCH_TYPE);
+ m_pool = new Ypp::QueryPool (query);
+ // initialize list -- there could already be packages modified
+ for (Ypp::Pool::Iter it = m_pool->getFirst(); it; it = m_pool->getNext (it))
+ ChangesPane::entryInserted (it, m_pool->get (it));
+ m_pool->setListener (this);
+ }
+
+ ~ChangesPane()
+ {
+ delete m_pool;
+ for (GList *i = m_entries; i; i = i->next)
+ delete (Entry *) i->data;
+ g_list_free (m_entries);
+ }
+
+ void startHack() // call after init, after you did a show_all in the dialog
+ {
+ UpdateVisible();
+ // ugly: signal modified for all entries to allow them to hide undo buttons
+ GList *i;
+ Ypp::Pool::Iter it;
+ for (it = m_pool->getFirst(), i = m_entries; it && i;
+ it = m_pool->getNext (it), i = i->next)
+ ((Entry *) i->data)->modified (m_pool->get (it));
+ }
+
+ void UpdateVisible()
+ {
+ m_entries != NULL ? gtk_widget_show (m_box) : gtk_widget_hide (m_box);
+ }
+
+ virtual void entryInserted (Ypp::Pool::Iter iter, Ypp::Package *package)
+ {
+ Entry *entry = new Entry (package);
+ gtk_box_pack_start (GTK_BOX (m_entries_box), entry->getWidget(), FALSE, TRUE, 0);
+ int index = m_pool->toPath (iter).front();
+ m_entries = g_list_insert (m_entries, entry, index);
+ UpdateVisible();
+ }
+
+ virtual void entryDeleted (Ypp::Pool::Iter iter, Ypp::Package *package)
+ {
+ int index = m_pool->toPath (iter).front();
+ GList *i = g_list_nth (m_entries, index);
+ Entry *entry = (Entry *) i->data;
+ gtk_container_remove (GTK_CONTAINER (m_entries_box), entry->getWidget());
+ delete entry;
+ m_entries = g_list_delete_link (m_entries, i);
+ UpdateVisible();
+ }
+
+ virtual void entryChanged (Ypp::Pool::Iter iter, Ypp::Package *package)
+ {
+ int index = m_pool->toPath (iter).front();
+ Entry *entry = (Entry *) g_list_nth_data (m_entries, index);
+ entry->modified (package);
+ }
+};
+
+class Collections
+{
+public:
+ struct Listener {
+ virtual void collectionChanged (bool immediate) = 0;
+ };
+
+private:
+ struct View
+ {
+ virtual void writeQuery (Ypp::QueryPool::Query *query) = 0;
+
+ Collections::Listener *m_listener;
+ View (Collections::Listener *listener)
+ : m_listener (listener)
+ {
+ m_box = gtk_vbox_new (FALSE, 2);
+ }
+ virtual ~View() {}
+
+ GtkWidget *getWidget()
+ { return m_box; }
+
+ void signalChanged() { m_listener->collectionChanged (true); }
+ void signalChangedDelay() { m_listener->collectionChanged (false); }
+
+ protected:
+ GtkWidget *m_box;
+ };
+
+ struct StoreView : public View
+ {
+ protected:
+ GtkWidget *m_view, *m_scroll;
+ enum Column { TEXT_COL, ICON_COL, ENABLED_COL, PTR_COL, TOTAL_COLS };
+
+ virtual void doBuild (GtkTreeStore *store) = 0;
+ virtual void writeQuery (Ypp::QueryPool::Query *query,
+ const std::list <gpointer> &ptr) = 0;
+
+ public:
+ StoreView (Collections::Listener *listener)
+ : View (listener)
+ {
+ m_scroll = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (m_scroll),
+ GTK_SHADOW_IN);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (m_scroll),
+ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+ m_view = NULL;
+
+ gtk_box_pack_start (GTK_BOX (m_box), m_scroll, TRUE, TRUE, 0);
+
+ // parent constructor should call build()
+ }
+
+ void build (bool tree_mode, bool with_icons, bool multi_selection,
+ bool do_tooltip)
+ {
+ if (m_view)
+ gtk_container_remove (GTK_CONTAINER (m_scroll), m_view);
+
+ m_view = gtk_tree_view_new();
+ GtkTreeView *view = GTK_TREE_VIEW (m_view);
+ gtk_tree_view_set_headers_visible (view, FALSE);
+ gtk_tree_view_set_search_column (view, TEXT_COL);
+ if (do_tooltip)
+ gtk_tree_view_set_tooltip_column (view, TEXT_COL);
+ gtk_tree_view_set_show_expanders (view, tree_mode);
+
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+ if (with_icons) {
+ renderer = gtk_cell_renderer_pixbuf_new();
+ column = gtk_tree_view_column_new_with_attributes ("",
+ renderer, "icon-name", ICON_COL, "sensitive", ENABLED_COL, NULL);
+ gtk_tree_view_append_column (view, column);
+ }
+ renderer = gtk_cell_renderer_text_new();
+ g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_MIDDLE, NULL);
+ column = gtk_tree_view_column_new_with_attributes ("",
+ renderer, "markup", TEXT_COL, "sensitive", ENABLED_COL, NULL);
+ gtk_tree_view_append_column (view, column);
+
+ GtkTreeStore *store = gtk_tree_store_new (TOTAL_COLS,
+ G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_POINTER);
+ GtkTreeModel *model = GTK_TREE_MODEL (store);
+ gtk_tree_view_set_model (view, model);
+ g_object_unref (G_OBJECT (model));
+
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (view);
+ gtk_tree_selection_set_mode (selection,
+ multi_selection ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_BROWSE);
+ g_signal_connect (G_OBJECT (selection), "changed",
+ G_CALLBACK (selection_cb), this);
+ gtk_tree_selection_set_select_function (selection, can_select_cb, this, NULL);
+
+ block();
+ GtkTreeIter iter;
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter, TEXT_COL, _("All"), ENABLED_COL, TRUE, -1);
+ doBuild (store);
+
+ selectFirstItem();
+ unblock();
+
+ gtk_container_add (GTK_CONTAINER (m_scroll), m_view);
+ gtk_widget_show (m_view);
+ if (!tree_mode)
+ ensure_view_visible_hook (m_view);
+ }
+
+ void block()
+ {
+ GtkTreeView *view = GTK_TREE_VIEW (m_view);
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (view);
+ g_signal_handlers_block_by_func (selection, (gpointer) selection_cb, this);
+ }
+ void unblock()
+ {
+ GtkTreeView *view = GTK_TREE_VIEW (m_view);
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (view);
+ g_signal_handlers_unblock_by_func (selection, (gpointer) selection_cb, this);
+ }
+
+ void selectFirstItem()
+ {
+ /* we use gtk_tree_view_set_cursor(), rather than gtk_tree_selection_select_iter()
+ because that one is buggy in that when the user first interacts with the
+ treeview, a change signal is sent, even if he was just expanding one node... */
+ block();
+ GtkTreePath *path = gtk_tree_path_new_first();
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (m_view), path, NULL, FALSE);
+ gtk_tree_path_free (path);
+ unblock();
+ }
+
+ static void selection_cb (GtkTreeSelection *selection, StoreView *pThis)
+ {
+ pThis->signalChanged();
+ // if item unselected, make sure "All" is
+ if (gtk_tree_selection_count_selected_rows (selection) == 0)
+ pThis->selectFirstItem();
+ }
+
+ static gboolean can_select_cb (GtkTreeSelection *selection, GtkTreeModel *model,
+ GtkTreePath *path, gboolean currently_selected,
+ gpointer pData)
+ {
+ gboolean ret;
+ GtkTreeIter iter;
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter, ENABLED_COL, &ret, -1);
+ return ret;
+ }
+
+ virtual void writeQuery (Ypp::QueryPool::Query *query)
+ {
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (m_view));
+ GtkTreeModel *model;
+ GList *selected = gtk_tree_selection_get_selected_rows (selection, &model);
+ std::list <gpointer> ptrs;
+ for (GList *i = selected; i; i = i->next) {
+ GtkTreePath *path = (GtkTreePath *) i->data;
+ GtkTreeIter iter;
+ gtk_tree_model_get_iter (model, &iter, path);
+ gpointer ptr;
+ gtk_tree_model_get (model, &iter, PTR_COL, &ptr, -1);
+ if (ptr)
+ ptrs.push_back (ptr);
+ gtk_tree_path_free (path);
+ }
+ g_list_free (selected);
+ writeQuery (query, ptrs);
+ }
+ };
+
+ struct Categories : public StoreView
+ {
+ bool m_rpmGroups;
+ public:
+ Categories (Collections::Listener *listener)
+ : StoreView (listener), m_rpmGroups (false)
+ {
+ if (!pkg_selector->onlineUpdateMode()) {
+ GtkWidget *check = gtk_check_button_new_with_label (_("Detailed"));
+ YGUtils::setWidgetFont (GTK_BIN (check)->child,
+ PANGO_STYLE_NORMAL, PANGO_WEIGHT_NORMAL, PANGO_SCALE_SMALL);
+ gtk_widget_set_tooltip_text (check,
+ _("Group by the PackageKit-based filter or straight from the actual "
+ "RPM information."));
+ g_signal_connect (G_OBJECT (check), "toggled",
+ G_CALLBACK (rpm_groups_toggled_cb), this);
+ gtk_box_pack_start (GTK_BOX (m_box), check, FALSE, TRUE, 0);
+ }
+ build (m_rpmGroups, !m_rpmGroups, false, false);
+ }
+
+ virtual void doBuild (GtkTreeStore *store)
+ {
+ struct inner {
+ static void populate (GtkTreeStore *store, GtkTreeIter *parent,
+ Ypp::Node *category, Categories *pThis)
+ {
+ if (!category)
+ return;
+ GtkTreeIter iter;
+ gtk_tree_store_append (store, &iter, parent);
+ gtk_tree_store_set (store, &iter, TEXT_COL, category->name.c_str(),
+ ICON_COL, category->icon, PTR_COL, category, ENABLED_COL, TRUE, -1);
+ populate (store, &iter, category->child(), pThis);
+ populate (store, parent, category->next(), pThis);
+ }
+ };
+
+ Ypp::Node *first_category;
+ Ypp::Package::Type type = pkg_selector->onlineUpdateMode() ?
+ Ypp::Package::PATCH_TYPE : Ypp::Package::PACKAGE_TYPE;
+ if (!m_rpmGroups && !pkg_selector->onlineUpdateMode())
+ first_category = Ypp::get()->getFirstCategory2 (type);
+ else
+ first_category = Ypp::get()->getFirstCategory (type);
+ inner::populate (store, NULL, first_category, this);
+ if (!m_rpmGroups && !pkg_selector->onlineUpdateMode()) {
+ GtkTreeView *view = GTK_TREE_VIEW (m_view);
+ GtkTreeIter iter;
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_view_set_row_separator_func (view,
+ is_tree_model_iter_separator_cb, NULL, NULL);
+
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter, TEXT_COL, _("Recommended"),
+ ICON_COL, GTK_STOCK_ABOUT, PTR_COL, GINT_TO_POINTER (1),
+ ENABLED_COL, TRUE, -1);
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter, TEXT_COL, _("Suggested"),
+ ICON_COL, GTK_STOCK_ABOUT, PTR_COL, GINT_TO_POINTER (2),
+ ENABLED_COL, TRUE, -1);
+ }
+ }
+
+ virtual void writeQuery (Ypp::QueryPool::Query *query,
+ const std::list <gpointer> &ptrs)
+ {
+ gpointer ptr = ptrs.empty() ? NULL : ptrs.front();
+ int nptr = GPOINTER_TO_INT (ptr);
+ if (nptr == 1)
+ query->setIsRecommended (true);
+ else if (nptr == 2)
+ query->setIsSuggested (true);
+ else if (ptr) {
+ Ypp::Node *node = (Ypp::Node *) ptr;
+ if (m_rpmGroups || pkg_selector->onlineUpdateMode())
+ query->addCategory (node);
+ else
+ query->addCategory2 (node);
+ }
+ }
+
+ static void rpm_groups_toggled_cb (GtkToggleButton *button, Categories *pThis)
+ {
+ pThis->m_rpmGroups = gtk_toggle_button_get_active (button);
+ pThis->build (pThis->m_rpmGroups, !pThis->m_rpmGroups, false, false);
+ pThis->signalChanged();
+ }
+ };
+
+ struct Repositories : public StoreView
+ {
+ public:
+ Repositories (Collections::Listener *listener)
+ : StoreView (listener)
+ {
+ if (pkg_selector->repoMgrEnabled()) {
+ GtkWidget *align, *button, *box, *image, *label;
+ image = gtk_image_new_from_stock (GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU);
+ label = gtk_label_new (_("Edit..."));
+ YGUtils::setWidgetFont (label, PANGO_STYLE_NORMAL, PANGO_WEIGHT_NORMAL, PANGO_SCALE_SMALL);
+ box = gtk_hbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (box), image, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
+ button = gtk_button_new();
+ gtk_container_add (GTK_CONTAINER (button), box);
+ gtk_widget_set_tooltip_text (button, _("Access the repositories manager tool."));
+ align = gtk_alignment_new (0, 0, 0, 1);
+ gtk_container_add (GTK_CONTAINER (align), button);
+ g_signal_connect (G_OBJECT (button), "clicked",
+ G_CALLBACK (setup_button_clicked_cb), this);
+ gtk_box_pack_start (GTK_BOX (m_box), align, FALSE, TRUE, 0);
+ }
+ build (false, true, true, true);
+ }
+
+ virtual ~Repositories()
+ {
+ Ypp::get()->setFavoriteRepository (NULL);
+ }
+
+ virtual void doBuild (GtkTreeStore *store)
+ {
+ GtkTreeIter iter;
+ for (int i = 0; Ypp::get()->getRepository (i); i++) {
+ const Ypp::Repository *repo = Ypp::get()->getRepository (i);
+ gtk_tree_store_append (store, &iter, NULL);
+ std::string text = repo->name, url (repo->url);
+ YGUtils::escapeMarkup (url);
+ text += "\n<small>" + url + "</small>";
+ const gchar *icon;
+ if (repo->url.empty())
+ icon = GTK_STOCK_MISSING_IMAGE;
+ else if (repo->url.compare (0, 2, "cd", 2) == 0 ||
+ repo->url.compare (0, 3, "dvd", 3) == 0)
+ icon = GTK_STOCK_CDROM;
+ else if (repo->url.compare (0, 3, "iso", 3) == 0)
+ icon = GTK_STOCK_FILE;
+ else
+ icon = GTK_STOCK_NETWORK;
+ gtk_tree_store_set (store, &iter, TEXT_COL, text.c_str(),
+ ICON_COL, icon, ENABLED_COL, repo->enabled, PTR_COL, repo, -1);
+ }
+ }
+
+ virtual void writeQuery (Ypp::QueryPool::Query *query,
+ const std::list <gpointer> &ptrs)
+ {
+ for (std::list <gpointer>::const_iterator it = ptrs.begin();
+ it != ptrs.end(); it++) {
+ Ypp::Repository *repo = (Ypp::Repository *) *it;
+ query->addRepository (repo);
+ }
+ gpointer ptr = ptrs.size() == 1 ? ptrs.front() : NULL;
+ Ypp::get()->setFavoriteRepository ((Ypp::Repository *) ptr);
+ }
+
+ static void setup_button_clicked_cb (GtkButton *button, Repositories *pThis)
+ {
+ YGUI::ui()->sendEvent (new YMenuEvent ("repo_mgr"));
+ }
+ };
+
+ struct Pool : public View, public PackagesView::Listener
+ {
+ private:
+ PackagesView * m_view;
+ GtkWidget *m_buttons_box;
+
+ public:
+ Pool (Collections::Listener *listener, Ypp::Package::Type type)
+ : View (listener)
+ {
+ m_view = new PackagesView (true, true, true, false, true);
+ m_view->setPool (new Ypp::TreePool (type));
+ m_view->setListener (this);
+
+ // control buttons
+ m_buttons_box = gtk_alignment_new (0, 0, 0, 0);
+ GtkWidget *image, *button;
+ button = gtk_button_new_with_label (_("Install All"));
+ image = gtk_image_new_from_stock (GTK_STOCK_SAVE, GTK_ICON_SIZE_BUTTON);
+ gtk_button_set_image (GTK_BUTTON (button), image);
+ g_signal_connect (G_OBJECT (button), "clicked",
+ G_CALLBACK (install_cb), this);
+ gtk_container_add (GTK_CONTAINER (m_buttons_box), button);
+ gtk_widget_set_sensitive (m_buttons_box, FALSE);
+
+ // layout
+ gtk_box_pack_start (GTK_BOX (m_box), m_view->getWidget(), TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (m_box), m_buttons_box, FALSE, TRUE, 0);
+ }
+
+ virtual ~Pool()
+ {
+ delete m_view;
+ }
+
+ virtual void packagesSelected (const PkgList &selection)
+ {
+ gtk_widget_set_sensitive (m_buttons_box, selection.notInstalled());
+ signalChanged();
+ }
+
+ virtual void writeQuery (Ypp::QueryPool::Query *query)
+ {
+ PkgList selected = m_view->getSelected();
+ for (PkgList::const_iterator it = selected.begin();
+ it != selected.end(); it++)
+ query->addCollection (*it);
+ if (selected.empty())
+ query->setClear();
+ }
+
+ void doAll (bool install /*or remove*/)
+ {
+ // we just need to mark the collections themselves
+ PkgList selected = m_view->getSelected();
+ install ? selected.install() : selected.remove();
+ }
+
+ static void install_cb (GtkButton *button, Pool *pThis)
+ { pThis->doAll (true); }
+ static void remove_cb (GtkButton *button, Pool *pThis)
+ { pThis->doAll (false); }
+ };
+
+ View *m_view;
+ GtkWidget *m_bin;
+ Collections::Listener *m_listener;
+
+public:
+ enum Type { GROUPS_TYPE, PATTERNS_TYPE, LANGUAGES_TYPE, REPOS_TYPE };
+
+ Collections (Collections::Listener *listener)
+ : m_view (NULL), m_listener (listener)
+ {
+ m_bin = gtk_event_box_new();
+ }
+
+ ~Collections()
+ {
+ delete m_view;
+ }
+
+ GtkWidget *getWidget()
+ { return m_bin; }
+
+ void setType (Type type)
+ {
+ if (m_view)
+ gtk_container_remove (GTK_CONTAINER (m_bin), m_view->getWidget());
+ delete m_view;
+
+ switch (type)
+ {
+ case GROUPS_TYPE:
+ m_view = new Categories (m_listener);
+ break;
+ case PATTERNS_TYPE:
+ m_view = new Pool (m_listener, Ypp::Package::PATTERN_TYPE);
+ break;
+ case LANGUAGES_TYPE:
+ m_view = new Pool (m_listener, Ypp::Package::LANGUAGE_TYPE);
+ break;
+ default:
+ m_view = new Repositories (m_listener);
+ break;
+ }
+
+ if (m_view) {
+ gtk_widget_show_all (m_view->getWidget());
+ gtk_container_add (GTK_CONTAINER (m_bin), m_view->getWidget());
+ }
+ }
+
+ void writeQuery (Ypp::QueryPool::Query *query)
+ {
+ if (m_view)
+ m_view->writeQuery (query);
+ }
+};
+
+class Filters : public Collections::Listener
+{
+ class StatusButtons
+ {
+ public:
+ enum Status { AVAILABLE, UPGRADE, INSTALLED, ALL };
+
+ private:
+ GtkWidget *m_box;
+ Filters *m_filters;
+ Status m_selected;
+
+ public:
+ GtkWidget *getWidget()
+ { return m_box; }
+
+ StatusButtons (Filters *filters)
+ : m_filters (filters), m_selected (AVAILABLE)
+ {
+ m_box = gtk_hbox_new (FALSE, 6);
+
+ GtkWidget *button;
+ GSList *group;
+ button = createButton (_("_Available"), "pkg-available.png", NULL);
+ group = ygtk_toggle_button_get_group (YGTK_TOGGLE_BUTTON (button));
+ gtk_box_pack_start (GTK_BOX (m_box), button, TRUE, TRUE, 0);
+ if (!pkg_selector->onlineUpdateMode()) {
+ button = createButton (_("_Upgrades"), "pkg-installed-upgradable.png", group);
+ gtk_box_pack_start (GTK_BOX (m_box), button, TRUE, TRUE, 0);
+ }
+ button = createButton (_("_Installed"), "pkg-installed.png", group);
+ gtk_box_pack_start (GTK_BOX (m_box), button, TRUE, TRUE, 0);
+ button = createButton (_("A_ll"), 0, group);
+ gtk_box_pack_start (GTK_BOX (m_box), button, FALSE, TRUE, 0);
+ }
+
+ Status getActive()
+ {
+ return m_selected;
+ }
+
+ GtkWidget *getSpecificWidget (Status status)
+ {
+ GtkWidget *button;
+ GList *children = gtk_container_get_children (GTK_CONTAINER (m_box));
+ button = (GtkWidget *) g_list_nth_data (children, (int) status);
+ g_list_free (children);
+ return button;
+ }
+
+ GtkWidget *createButton (const char *label, const char *icon, GSList *group)
+ {
+ GtkWidget *button = ygtk_toggle_button_new (group);
+#if 0
+ gtk_button_set_label (GTK_BUTTON (button), label);
+ gtk_button_set_use_underline (GTK_BUTTON (button), TRUE);
+ if (icon)
+ gtk_button_set_image (GTK_BUTTON (button), image_new_from_file (icon));
+#else
+ GtkWidget *box = gtk_hbox_new (FALSE, 6);
+ if (icon)
+ gtk_box_pack_start (GTK_BOX (box), image_new_from_file (icon),
+ FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (box), gtk_label_new_with_mnemonic (label),
+ TRUE, TRUE, 0);
+ gtk_container_add (GTK_CONTAINER (button), box);
+#endif
+ if (!group)
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
+ gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
+ g_signal_connect (G_OBJECT (button), "toggle-changed",
+ G_CALLBACK (status_toggled_cb), this);
+ return button;
+ }
+
+ static void status_toggled_cb (GtkToggleButton *toggle, gint nb, StatusButtons *pThis)
+ {
+ pThis->m_selected = (Status) nb;
+ if (pkg_selector->onlineUpdateMode() && nb >= 1)
+ pThis->m_selected = (Status) (nb+1);
+ pThis->m_filters->signalChanged();
+ }
+ };
+
+public:
+ struct Listener {
+ virtual void doQuery (Ypp::QueryPool::Query *query) = 0;
+ };
+ void setListener (Listener *listener)
+ { m_listener = listener; signalChanged(); }
+
+private:
+ Collections *m_collection;
+ StatusButtons *m_statuses;
+ GtkWidget *m_name, *m_type;
+ Listener *m_listener;
+ guint timeout_id;
+ bool m_nameChanged; // clear name field if some other changes
+
+public:
+ GtkWidget *getCollectionWidget() { return m_collection->getWidget(); }
+ GtkWidget *getStatusesWidget() { return m_statuses->getWidget(); }
+ GtkWidget *getNameWidget() { return m_name; }
+ GtkWidget *getTypeWidget() { return m_type; }
+
+ Filters()
+ : m_listener (NULL), timeout_id (0), m_nameChanged (false)
+ {
+ m_statuses = new StatusButtons (this);
+
+ m_name = ygtk_find_entry_new();
+ gtk_widget_set_tooltip_markup (m_name,
+ _("<b>Package search:</b> Use spaces to separate your keywords. They "
+ "will be matched against RPM <i>name</i> and <i>summary</i> attributes. "
+ "Other criteria attributes are available by pressing the search icon.\n"
+ "(usage example: \"yast dhcp\" will return yast's dhcpd tool)"));
+ ygtk_find_entry_insert_item (YGTK_FIND_ENTRY (m_name), _("Filter by name & summary"),
+ GTK_STOCK_FIND, NULL);
+ ygtk_find_entry_insert_item (YGTK_FIND_ENTRY (m_name), _("Filter by description"),
+ GTK_STOCK_EDIT, NULL);
+ ygtk_find_entry_insert_item (YGTK_FIND_ENTRY (m_name), _("Filter by file"),
+ GTK_STOCK_OPEN, NULL);
+ ygtk_find_entry_insert_item (YGTK_FIND_ENTRY (m_name), _("Filter by author"),
+ GTK_STOCK_ABOUT, NULL);
+ ygtk_find_entry_insert_item (YGTK_FIND_ENTRY (m_name), _("Filter by novelty (in days)"),
+ GTK_STOCK_NEW, _("Number of days since the package was built by the repository."));
+ g_signal_connect (G_OBJECT (m_name), "changed",
+ G_CALLBACK (name_changed_cb), this);
+ g_signal_connect (G_OBJECT (m_name), "menu-item-selected",
+ G_CALLBACK (name_item_changed_cb), this);
+
+ m_type = gtk_combo_box_new_text();
+ if (pkg_selector->onlineUpdateMode())
+ gtk_combo_box_append_text (GTK_COMBO_BOX (m_type), _("Severity"));
+ else {
+ gtk_combo_box_append_text (GTK_COMBO_BOX (m_type), _("Groups"));
+ gtk_combo_box_append_text (GTK_COMBO_BOX (m_type), _("Patterns"));
+ gtk_combo_box_append_text (GTK_COMBO_BOX (m_type), _("Languages"));
+ gtk_widget_set_tooltip_markup (m_type,
+ _("Packages can be organized in:\n"
+ "<b>Groups:</b> simple categorization of packages by purpose.\n"
+ "<b>Patterns:</b> assists in installing all packages necessary "
+ "for several working environments.\n"
+ "<b>Languages:</b> adds another language to the system.\n"
+ "<b>Repositories:</b> catalogues what the several configured "
+ "repositories have available."));
+ }
+ gtk_combo_box_append_text (GTK_COMBO_BOX (m_type), _("Repositories"));
+ gtk_combo_box_set_active (GTK_COMBO_BOX (m_type), 0);
+ g_signal_connect (G_OBJECT (m_type), "changed",
+ G_CALLBACK (type_changed_cb), this);
+
+ m_collection = new Collections (this);
+ m_collection->setType (Collections::GROUPS_TYPE);
+ }
+
+ ~Filters()
+ {
+ if (timeout_id)
+ g_source_remove (timeout_id);
+ }
+
+private:
+ void clearNameEntry()
+ {
+ g_signal_handlers_block_by_func (m_name, (gpointer) name_changed_cb, this);
+ g_signal_handlers_block_by_func (m_name, (gpointer) name_item_changed_cb, this);
+ gtk_entry_set_text (GTK_ENTRY (m_name), "");
+ ygtk_find_entry_select_item (YGTK_FIND_ENTRY (m_name), 0);
+ g_signal_handlers_unblock_by_func (m_name, (gpointer) name_changed_cb, this);
+ g_signal_handlers_unblock_by_func (m_name, (gpointer) name_item_changed_cb, this);
+ }
+
+ static void type_changed_cb (GtkComboBox *combo, Filters *pThis)
+ {
+ busyCursor();
+ pThis->clearNameEntry();
+ int type = gtk_combo_box_get_active (combo);
+ if (pkg_selector->onlineUpdateMode() && type == 1)
+ type = Collections::REPOS_TYPE;
+ pThis->m_collection->setType ((Collections::Type) type);
+ pThis->signalChanged();
+ normalCursor();
+ }
+
+ static void name_changed_cb (YGtkFindEntry *entry, Filters *pThis)
+ {
+ gint nb = ygtk_find_entry_get_selected_item (entry);
+ if (nb == 4) { // novelty only allows numbers
+ const gchar *text = gtk_entry_get_text (GTK_ENTRY (entry));
+ gboolean correct = TRUE;
+ for (const gchar *i = text; *i; i++)
+ if (!g_ascii_isdigit (*i)) {
+ correct = FALSE;
+ break;
+ }
+ ygtk_find_entry_set_state (entry, correct);
+ }
+ pThis->signalChangedDelay();
+ }
+ static void name_item_changed_cb (YGtkFindEntry *entry, gint nb, Filters *pThis)
+ {
+ const gchar *text = "";
+ if (nb == 4) text = "7"; // novelty is weird; show usage case
+ g_signal_handlers_block_by_func (entry, (gpointer) name_changed_cb, pThis);
+ gtk_entry_set_text (GTK_ENTRY (entry), text);
+ g_signal_handlers_unblock_by_func (entry, (gpointer) name_changed_cb, pThis);
+ gtk_editable_set_position (GTK_EDITABLE (entry), -1);
+ ygtk_find_entry_set_state (entry, TRUE);
+
+ pThis->signalChanged();
+ }
+ static void field_changed_cb (gpointer widget, Filters *pThis)
+ { pThis->signalChangedDelay(); }
+
+ virtual void collectionChanged (bool immediate)
+ { immediate ? signalChanged() : signalChangedDelay(); }
+
+ void signalChanged()
+ {
+ if (!m_listener) return;
+ busyCursor();
+
+ // create query
+ Ypp::QueryPool::Query *query = new Ypp::QueryPool::Query();
+ if (pkg_selector->onlineUpdateMode())
+ query->addType (Ypp::Package::PATCH_TYPE);
+ else
+ query->addType (Ypp::Package::PACKAGE_TYPE);
+
+ const char *name = gtk_entry_get_text (GTK_ENTRY (m_name));
+ if (*name) {
+ gint item = ygtk_find_entry_get_selected_item (YGTK_FIND_ENTRY (m_name));
+ if (item == 4) { // novelty
+ int days = atoi (name);
+ query->setBuildAge (days);
+ }
+ else {
+ bool use_name, use_summary, use_description, use_filelist, use_authors;
+ use_name = use_summary = use_description = use_filelist = use_authors = false;
+ switch (item) {
+ case 0: // name & summary
+ default:
+ use_name = use_summary = true;
+ break;
+ case 1: // description
+ use_name = use_summary = use_description = true;
+ break;
+ case 2: // file
+ use_filelist = true;
+ break;
+ case 3: // author
+ use_authors = true;
+ break;
+ }
+ query->addNames (name, ' ', use_name, use_summary, use_description,
+ use_filelist, use_authors);
+ }
+
+ if (item == 0) { // tip: the user may be searching for patterns
+ static bool shown_pattern_tip = false;
+ if (!pkg_selector->onlineUpdateMode() && !shown_pattern_tip &&
+ gtk_combo_box_get_active (GTK_COMBO_BOX (m_type)) == 0 &&
+ (m_statuses->getActive() == StatusButtons::AVAILABLE ||
+ m_statuses->getActive() == StatusButtons::ALL)) {
+ Ypp::QueryPool::Query *query = new Ypp::QueryPool::Query();
+ query->addType (Ypp::Package::PATTERN_TYPE);
+ query->addNames (name, ' ', true, false, false, false, false, true);
+ query->setIsInstalled (false);
+ Ypp::QueryPool pool (query);
+ if (!pool.empty()) {
+ shown_pattern_tip = true;
+ //std::string first = pool.getName (pool.getFirst());
+ std::string text =
+ _("Patterns are available that can\n"
+ "assist you in the installment\nof");
+ text += " <i>" + std::string (name) + "</i> ";
+ text += _("related packages.");
+ ygtk_tooltip_show_at_widget (m_type, YGTK_POINTER_UP_LEFT,
+ text.c_str(), GTK_STOCK_DIALOG_INFO);
+ }
+ }
+ }
+ else if (item == 2) {
+ if (m_statuses->getActive() == StatusButtons::AVAILABLE) {
+ const char *text =
+ _("The file filter is only\n"
+ "applicable to <b>installed</b> packages.");
+ ygtk_tooltip_show_at_widget (
+ m_statuses->getSpecificWidget (StatusButtons::INSTALLED),
+ YGTK_POINTER_DOWN_RIGHT, text, GTK_STOCK_DIALOG_ERROR);
+ }
+ }
+ }
+
+ switch (m_statuses->getActive())
+ {
+ case StatusButtons::AVAILABLE:
+ if (pkg_selector->onlineUpdateMode())
+ // special pane for patches upgrades makes little sense, so
+ // we instead list them together with availables
+ query->setHasUpgrade (true);
+ query->setIsInstalled (false);
+ break;
+ case StatusButtons::UPGRADE:
+ query->setHasUpgrade (true);
+ break;
+ case StatusButtons::INSTALLED:
+ query->setIsInstalled (true);
+ break;
+ case StatusButtons::ALL:
+ break;
+ }
+
+ m_collection->writeQuery (query);
+ m_listener->doQuery (query);
+ normalCursor();
+ }
+
+ void signalChangedDelay()
+ {
+ struct inner {
+ static gboolean timeout_cb (gpointer data)
+ {
+ Filters *pThis = (Filters *) data;
+ pThis->timeout_id = 0;
+ pThis->signalChanged();
+ return FALSE;
+ }
+ };
+ if (timeout_id) g_source_remove (timeout_id);
+ timeout_id = g_timeout_add (250, inner::timeout_cb, this);
+ }
+};
+
+class PackageControl
+{
+GtkWidget *m_widget, *m_install_button, *m_remove_button, *m_installed_version,
+ *m_available_versions, *m_installed_box, *m_available_box;
+//#define SHOW_LOCK_UNDO_BUTTONS // to specific -- show them only as popups
+#ifdef SHOW_LOCK_UNDO_BUTTON
+GtkWidget *m_undo_button, *m_lock_button, *m_locked_image, *m_unlocked_image;
+#endif
+
+public:
+PkgList m_packages; // we keep a copy to test against modified...
+Filters *m_filters; // used to filter repo versions...
+
+ GtkWidget *getWidget()
+ { return m_widget; }
+
+ PackageControl (Filters *filters)
+ : m_filters (filters)
+ {
+ // installed
+ m_remove_button = createButton (_("_Remove"), GTK_STOCK_DELETE);
+ gtk_button_set_focus_on_click (GTK_BUTTON (m_remove_button), FALSE);
+ g_signal_connect (G_OBJECT (m_remove_button), "clicked",
+ G_CALLBACK (remove_clicked_cb), this);
+
+ m_installed_version = gtk_label_new ("");
+ gtk_label_set_selectable (GTK_LABEL (m_installed_version), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (m_installed_version), 0, 0.5);
+
+ m_installed_box = gtk_vbox_new (FALSE, 2);
+ gtk_box_pack_start (GTK_BOX (m_installed_box), createBoldLabel (_("Installed:")),
+ FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (m_installed_box), m_installed_version, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (m_installed_box), m_remove_button, FALSE, TRUE, 0);
+
+ // available
+ m_install_button = createButton ("", GTK_STOCK_SAVE);
+ gtk_button_set_focus_on_click (GTK_BUTTON (m_install_button), FALSE);
+ g_signal_connect (G_OBJECT (m_install_button), "clicked",
+ G_CALLBACK (install_clicked_cb), this);
+
+ m_available_versions = gtk_combo_box_new();
+ GtkListStore *store = gtk_list_store_new (1, G_TYPE_STRING);
+ gtk_combo_box_set_model (GTK_COMBO_BOX (m_available_versions),
+ GTK_TREE_MODEL (store));
+ g_object_unref (G_OBJECT (store));
+ GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (m_available_versions), renderer, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (m_available_versions), renderer,
+ "markup", 0, NULL);
+ g_signal_connect (G_OBJECT (m_available_versions), "changed",
+ G_CALLBACK (version_changed_cb), this);
+
+ m_available_box = gtk_vbox_new (FALSE, 2);
+ gtk_box_pack_start (GTK_BOX (m_available_box), createBoldLabel (_("Available:")),
+ FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (m_available_box), m_available_versions, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (m_available_box), m_install_button, FALSE, TRUE, 0);
+
+ m_widget = gtk_vbox_new (FALSE, 12);
+ gtk_box_pack_start (GTK_BOX (m_widget), m_installed_box, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (m_widget), m_available_box, FALSE, TRUE, 0);
+
+#ifdef SHOW_LOCK_UNDO_BUTTON
+ m_lock_button = gtk_toggle_button_new();
+ gtk_widget_set_tooltip_markup (m_lock_button, lock_tooltip);
+ g_signal_connect (G_OBJECT (m_lock_button), "toggled",
+ G_CALLBACK (locked_toggled_cb), this);
+ m_locked_image = image_new_from_file ("pkg-locked.png");
+ m_unlocked_image = image_new_from_file ("pkg-unlocked.png");
+ g_object_ref_sink (G_OBJECT (m_locked_image));
+ g_object_ref_sink (G_OBJECT (m_unlocked_image));
+
+ m_undo_button = gtk_button_new_from_stock (GTK_STOCK_UNDO);
+ g_signal_connect (G_OBJECT (m_undo_button), "clicked",
+ G_CALLBACK (undo_clicked_cb), this);
+
+ GtkWidget *lock_align = gtk_alignment_new (1.0, 0.5, 0, 0);
+ gtk_container_add (GTK_CONTAINER (lock_align), m_lock_button);
+ gtk_box_pack_start (GTK_BOX (m_widget), lock_align, FALSE, TRUE, 0);
+
+ GtkWidget *undo_align = gtk_alignment_new (0.5, 0.5, 0, 0);
+ gtk_container_add (GTK_CONTAINER (undo_align), m_undo_button);
+ gtk_box_pack_start (GTK_BOX (m_widget), undo_align, FALSE, TRUE, 0);
+#endif
+ }
+
+#ifdef SHOW_LOCK_UNDO_BUTTON
+ ~PackageControl()
+ {
+ gtk_widget_destroy (m_locked_image);
+ g_object_unref (G_OBJECT (m_locked_image));
+ gtk_widget_destroy (m_unlocked_image);
+ g_object_unref (G_OBJECT (m_unlocked_image));
+ }
+#endif
+
+ void setPackages (const PkgList &packages)
+ {
+ m_packages = packages;
+
+ Ypp::Package *single_package = packages.single() ? packages.front() : NULL;
+ if (packages.installed()) {
+ gtk_widget_show (m_installed_box);
+ if (single_package) {
+ std::string text;
+ const Ypp::Package::Version *version = single_package->getInstalledVersion();
+ if (version) {
+ text = version->number;
+ text += " <small>(" + version->arch + ")</small>";
+ }
+ gtk_label_set_markup (GTK_LABEL (m_installed_version), text.c_str());
+ }
+ else
+ gtk_label_set_text (GTK_LABEL (m_installed_version), "(several)");
+ }
+ else {
+ gtk_widget_hide (m_installed_box);
+ }
+
+ GtkTreeModel *model = gtk_combo_box_get_model (
+ GTK_COMBO_BOX (m_available_versions));
+ gtk_list_store_clear (GTK_LIST_STORE (model));
+ gtk_widget_set_sensitive (m_available_versions, FALSE);
+ gtk_widget_show (m_available_box);
+ if (single_package) {
+ if (single_package->getAvailableVersion (0)) {
+ gtk_widget_set_sensitive (m_available_versions, TRUE);
+ gtk_widget_show (m_available_box);
+ const Ypp::Repository *favoriteRepo = Ypp::get()->favoriteRepository();
+ for (int i = 0; single_package->getAvailableVersion (i); i++) {
+ const Ypp::Package::Version *version = single_package->getAvailableVersion (i);
+ string text = version->number + " <small>(" + version->arch + ")</small>\n";
+ string repo;
+ if (version->repo)
+ repo = YGUtils::truncate (version->repo->name,
+ MAX (20, version->number.length() + version->arch.length() + 4), 0);
+ else
+ yuiError() << "Repository of package '" << single_package->name()
+ << "' unknown\n";
+ text += "<small>" + repo + "</small>";
+ GtkTreeIter iter;
+ gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, text.c_str(), -1);
+ if (version->repo == favoriteRepo) {
+ gtk_combo_box_set_active (GTK_COMBO_BOX (m_available_versions), i);
+ favoriteRepo = 0; // select only the 1st hit
+ }
+ else if (i == 0)
+ gtk_combo_box_set_active (GTK_COMBO_BOX (m_available_versions), 0);
+ }
+ }
+ else
+ gtk_widget_hide (m_available_box);
+ }
+ else {
+ if (packages.upgradable()) {
+ gtk_combo_box_append_text (GTK_COMBO_BOX (m_available_versions), "(upgrades)");
+ gtk_combo_box_set_active (GTK_COMBO_BOX (m_available_versions), 0);
+ }
+ else if (packages.notInstalled()) {
+ gtk_combo_box_append_text (GTK_COMBO_BOX (m_available_versions), "(several)");
+ gtk_combo_box_set_active (GTK_COMBO_BOX (m_available_versions), 0);
+ }
+ else
+ gtk_widget_hide (m_available_box);
+ }
+
+ // is locked
+ if (packages.locked() || packages.unlocked()) {
+#ifdef SHOW_LOCK_UNDO_BUTTON
+ gtk_widget_show (m_lock_button);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (m_lock_button), packages.locked());
+ gtk_button_set_image (GTK_BUTTON (m_lock_button),
+ packages.locked() ? m_locked_image : m_unlocked_image);
+#endif
+ gtk_widget_set_sensitive (m_install_button, !packages.locked());
+ gtk_widget_set_sensitive (m_remove_button, !packages.locked());
+ }
+ else {
+#ifdef SHOW_LOCK_UNDO_BUTTON
+ gtk_widget_hide (m_lock_button);
+#endif
+ gtk_widget_set_sensitive (m_install_button, TRUE);
+ gtk_widget_set_sensitive (m_remove_button, TRUE);
+ }
+
+#ifdef SHOW_LOCK_UNDO_BUTTON
+ if (packages.modified())
+ gtk_widget_show (m_undo_button);
+ else
+ gtk_widget_hide (m_undo_button);
+#endif
+ }
+
+ void packageModified (Ypp::Package *package)
+ {
+ // GTK+ doesn't fire selection change when a selected row changes, so we need
+ // to re-load PackageControl in that occasions.
+ if (m_packages.contains (package)) {
+ m_packages.clearCache();
+ setPackages (m_packages);
+ }
+ }
+
+private:
+ static void install_clicked_cb (GtkButton *button, PackageControl *pThis)
+ {
+ if (pThis->m_packages.single()) {
+ busyCursor();
+ Ypp::Package *package = pThis->m_packages.front();
+ int version = gtk_combo_box_get_active (GTK_COMBO_BOX (
+ pThis->m_available_versions));
+ package->install (package->getAvailableVersion (version));
+ normalCursor();
+ }
+ else
+ pThis->m_packages.install();
+ }
+
+ static void remove_clicked_cb (GtkButton *button, PackageControl *pThis)
+ {
+ pThis->m_packages.remove();
+ }
+
+#ifdef SHOW_LOCK_UNDO_BUTTON
+ static void locked_toggled_cb (GtkToggleButton *button, PackageControl *pThis)
+ {
+ bool lock = gtk_toggle_button_get_active (button);
+ pThis->m_packages.lock (lock);
+ }
+
+ static void undo_clicked_cb (GtkButton *button, PackageControl *pThis)
+ {
+ pThis->m_packages.undo();
+ }
+#endif
+
+ static void version_changed_cb (GtkComboBox *combo, PackageControl *pThis)
+ {
+ if (pThis->m_packages.single()) {
+ Ypp::Package *package = pThis->m_packages.front();
+ int nb = gtk_combo_box_get_active (combo);
+ if (nb == -1) return;
+
+ const Ypp::Package::Version *version;
+ version = package->getAvailableVersion (nb);
+ assert (version != NULL);
+
+ const char *installLabel = _("Ins_tall");
+ if (package->isInstalled()) {
+ if (version->cmp > 0)
+ installLabel = _("Up_grade");
+ else if (version->cmp == 0)
+ installLabel = _("Re-ins_tall");
+ else //if (version->cmp < 0)
+ installLabel = _("Down_grade");
+ }
+ gtk_button_set_label (GTK_BUTTON (pThis->m_install_button), installLabel);
+
+ gchar *tooltip = g_strdup_printf ("%s <small>(%s)\n%s</small>",
+ version->number.c_str(), version->arch.c_str(),
+ version->repo ? version->repo->name.c_str() : "-repo error-");
+ gtk_widget_set_tooltip_markup (GTK_WIDGET (combo), tooltip);
+ g_free (tooltip);
+ }
+ }
+
+ // utility
+ static GtkWidget *createButton (const char *label_str, const gchar *stock_id)
+ {
+ GtkWidget *button, *image;
+ if (label_str)
+ button = gtk_button_new_with_mnemonic (label_str);
+ else
+ button = gtk_button_new();
+ if (stock_id) {
+ image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
+ gtk_button_set_image (GTK_BUTTON (button), image);
+ }
+ return button;
+ }
+ static GtkWidget *createBoldLabel (const char *text)
+ {
+ GtkWidget *label = gtk_label_new (text);
+ YGUtils::setWidgetFont (label, PANGO_STYLE_NORMAL, PANGO_WEIGHT_BOLD, PANGO_SCALE_MEDIUM);
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+ return label;
+ }
+};
+
+class PackageDetails
+{
+public:
+ struct Listener {
+ virtual void goToPackage (Ypp::Package *package) = 0;
+ };
+
+private:
+ struct TextExpander {
+ GtkWidget *expander, *text;
+
+ GtkWidget *getWidget() { return expander ? expander : text; }
+
+ TextExpander (const char *name)
+ {
+ text = ygtk_rich_text_new();
+ if (name) {
+ string str = string ("<b>") + name + "</b>";
+ expander = gtk_expander_new (str.c_str());
+ gtk_expander_set_use_markup (GTK_EXPANDER (expander), TRUE);
+ gtk_container_add (GTK_CONTAINER (expander), text);
+ }
+ else
+ expander = NULL;
+ }
+
+ void setText (const std::string &str)
+ {
+ ygtk_rich_text_set_text (YGTK_RICH_TEXT (text), str.c_str(), FALSE);
+ if (expander)
+ str.empty() ? gtk_widget_hide (expander) : gtk_widget_show (expander);
+ }
+ };
+
+ struct DepExpander {
+ GtkWidget *expander, *table, *requires, *provides;
+
+ GtkWidget *getWidget() { return expander; }
+
+ DepExpander (const char *name)
+ {
+ requires = ygtk_rich_text_new();
+ provides = ygtk_rich_text_new();
+
+ table = gtk_hbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (table), requires, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (table), provides, TRUE, TRUE, 0);
+
+ string str = string ("<b>") + name + "</b>";
+ expander = gtk_expander_new (str.c_str());
+ gtk_expander_set_use_markup (GTK_EXPANDER (expander), TRUE);
+ gtk_container_add (GTK_CONTAINER (expander), table);
+ }
+
+ void setPackage (const Ypp::Package *package)
+ {
+ if (package) {
+ std::string requires_str = _("Requires:");
+ std::string provides_str = _("Provides:");
+ requires_str += "<br><blockquote>";
+ requires_str += package->requires (true);
+ YGUtils::replace (provides_str, "\n", 1, "<br>");
+ requires_str += "</blockquote>";
+ provides_str += "<br><blockquote>";
+ provides_str += package->provides (true);
+ YGUtils::replace (requires_str, "\n", 1, "<br>");
+ provides_str += "</blockquote>";
+ ygtk_rich_text_set_text (YGTK_RICH_TEXT (requires), requires_str.c_str(), FALSE);
+ ygtk_rich_text_set_text (YGTK_RICH_TEXT (provides), provides_str.c_str(), FALSE);
+ gtk_widget_show (expander);
+ }
+ else
+ gtk_widget_hide (expander);
+ }
+ };
+
+GtkWidget *m_widget, *m_icon, *m_icon_frame;
+TextExpander *m_description, *m_filelist, *m_changelog, *m_authors, *m_support;
+DepExpander *m_dependencies;
+GtkWidget *m_contents_expander;
+PackagesView *m_contents;
+Listener *m_listener;
+
+public:
+ void setListener (Listener *listener)
+ { m_listener = listener; }
+
+ GtkWidget *getWidget()
+ { return m_widget; }
+
+ PackageDetails()
+ : m_listener (NULL)
+ {
+ GtkWidget *vbox;
+ m_widget = createWhiteViewPort (&vbox);
+
+ GtkWidget *hbox = gtk_hbox_new (FALSE, 6);
+ m_description = new TextExpander (NULL);
+ g_signal_connect (G_OBJECT (m_description->text), "link-clicked",
+ G_CALLBACK (link_pressed_cb), this);
+ gtk_box_pack_start (GTK_BOX (hbox), m_description->getWidget(), TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), createIconWidget (&m_icon, &m_icon_frame),
+ FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
+
+ if (!pkg_selector->onlineUpdateMode()) {
+ m_filelist = new TextExpander (_("File List"));
+ m_changelog = new TextExpander (_("Changelog"));
+ m_authors = new TextExpander (_("Authors"));
+ m_support = new TextExpander (_("Support"));
+ m_dependencies = new DepExpander (_("Dependencies"));
+ m_contents = NULL;
+ gtk_box_pack_start (GTK_BOX (vbox), m_filelist->getWidget(), FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), m_changelog->getWidget(), FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), m_authors->getWidget(), FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), m_dependencies->getWidget(), FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), m_support->getWidget(), FALSE, TRUE, 0);
+ if (CAN_OPEN_URIS())
+ g_signal_connect (G_OBJECT (m_filelist->text), "link-clicked",
+ G_CALLBACK (link_pressed_cb), this);
+ }
+ else {
+ m_filelist = m_changelog = m_authors = m_support = NULL;
+ m_dependencies = NULL;
+ m_contents = new PackagesView (false, false, true, false, true);
+ m_contents_expander = gtk_expander_new (_("<b>Applies to</b>"));
+ gtk_expander_set_use_markup (GTK_EXPANDER (m_contents_expander), TRUE);
+ gtk_container_add (GTK_CONTAINER (m_contents_expander), m_contents->getWidget());
+ gtk_box_pack_start (GTK_BOX (vbox), m_contents_expander, FALSE, TRUE, 0);
+ }
+ }
+
+ ~PackageDetails()
+ {
+ delete m_filelist;
+ delete m_changelog;
+ delete m_authors;
+ delete m_support;
+ delete m_dependencies;
+ delete m_contents;
+ }
+
+ void setPackages (const PkgList &packages)
+ {
+ Ypp::Package *package = packages.front();
+
+ gtk_widget_hide (m_icon_frame);
+ if (packages.single()) {
+ string description = "<b>" + package->name() + "</b><br>";
+ description += package->description (HTML_MARKUP);
+ m_description->setText (description);
+
+ if (m_filelist) m_filelist->setText (package->filelist (true));
+ if (m_changelog) m_changelog->setText (package->changelog());
+ if (m_authors) m_authors->setText (package->authors (true));
+ if (m_support) m_support->setText (package->support (true));
+ if (m_dependencies) m_dependencies->setPackage (package);
+
+ if (m_contents) { // patches -- "apply to"
+ gtk_widget_show (m_contents_expander);
+ Ypp::QueryPool::Query *query = new Ypp::QueryPool::Query();
+ query->addType (Ypp::Package::PACKAGE_TYPE);
+ query->addCollection (package);
+ m_contents->setQuery (query);
+ }
+
+ gtk_image_clear (GTK_IMAGE (m_icon));
+ GtkIconTheme *icons = gtk_icon_theme_get_default();
+ GdkPixbuf *pixbuf = gtk_icon_theme_load_icon (icons,
+ package->name().c_str(), 32, GtkIconLookupFlags (0), NULL);
+ if (pixbuf) {
+ gtk_image_set_from_pixbuf (GTK_IMAGE (m_icon), pixbuf);
+ g_object_unref (G_OBJECT (pixbuf));
+ gtk_widget_show (m_icon_frame);
+ }
+
+ scrollTop();
+ }
+ else {
+ string description;
+ if (!packages.empty()) {
+ description = "Selected:";
+ description += "<ul>";
+ for (PkgList::const_iterator it = packages.begin(); it != packages.end(); it++)
+ description += "<li><b>" + (*it)->name() + "</b></li>";
+ description += "</ul>";
+ }
+ m_description->setText (description);
+ if (m_filelist) m_filelist->setText ("");
+ if (m_changelog) m_changelog->setText ("");
+ if (m_authors) m_authors->setText ("");
+ if (m_support) m_support->setText ("");
+ if (m_dependencies) m_dependencies->setPackage (NULL);
+ if (m_contents) gtk_widget_hide (m_contents_expander);
+ }
+ }
+
+private:
+ static void link_pressed_cb (GtkWidget *text, const gchar *link, PackageDetails *pThis)
+ {
+ if (!strncmp (link, "pkg://", 6)) {
+ const gchar *pkg_name = link + 6;
+ yuiMilestone() << "Hyperlinking to package \"" << pkg_name << "\"" << endl;
+ Ypp::Package *pkg = Ypp::get()->findPackage (Ypp::Package::PACKAGE_TYPE, pkg_name);
+ if (pThis->m_listener && pkg)
+ pThis->m_listener->goToPackage (pkg);
+ else {
+ GtkWidget *dialog = gtk_message_dialog_new (YGDialog::currentWindow(),
+ GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK, _("Package '%s' was not found."), pkg_name);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ }
+ }
+ else
+ OPEN_URI (link);
+ }
+
+ void scrollTop()
+ {
+ GtkScrolledWindow *scroll = GTK_SCROLLED_WINDOW (m_widget);
+ YGUtils::scrollWidget (gtk_scrolled_window_get_vadjustment (scroll), true);
+ }
+
+ // utilities:
+ static GtkWidget *createIconWidget (GtkWidget **icon_widget, GtkWidget **icon_frame)
+ {
+ *icon_widget = gtk_image_new();
+
+ GtkWidget *box, *align, *frame;
+ box = gtk_event_box_new();
+ gtk_container_add (GTK_CONTAINER (box), *icon_widget);
+ gtk_container_set_border_width (GTK_CONTAINER (box), 2);
+
+ frame = gtk_frame_new (NULL);
+ gtk_container_add (GTK_CONTAINER (frame), box);
+
+ align = gtk_alignment_new (0, 0, 0, 0);
+ gtk_container_add (GTK_CONTAINER (align), frame);
+ gtk_container_set_border_width (GTK_CONTAINER (align), 6);
+ *icon_frame = align;
+ return align;
+ }
+ static GtkWidget *createWhiteViewPort (GtkWidget **vbox)
+ {
+ struct inner {
+ static gboolean expose_cb (GtkWidget *widget, GdkEventExpose *event)
+ {
+ cairo_t *cr = gdk_cairo_create (widget->window);
+ GdkColor color = { 0, 255 << 8, 255 << 8, 255 << 8 };
+ gdk_cairo_set_source_color (cr, &color);
+ cairo_rectangle (cr, event->area.x, event->area.y,
+ event->area.width, event->area.height);
+ cairo_fill (cr);
+ cairo_destroy (cr);
+ return FALSE;
+ }
+ };
+
+ *vbox = gtk_vbox_new (FALSE, 0);
+ g_signal_connect (G_OBJECT (*vbox), "expose-event",
+ G_CALLBACK (inner::expose_cb), NULL);
+
+ GtkWidget *scroll = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scroll), *vbox);
+ return scroll;
+ }
+};
+
+// either use YGtkBarGraph or GtkTreeView (w/ GtkCellRendererProgress)
+//#define USE_BARGRAPH
+#include "ygtkbargraph.h"
+
+class DiskView : public Ypp::Disk::Listener
+{
+#ifdef USE_BARGRAPH
+ static GtkWidget *DiskList_new (bool framed)
+ {
+ GtkWidget *widget = gtk_table_new (0, 0, FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER (widget), 2);
+ gtk_table_set_col_spacings (GTK_TABLE (widget), 4);
+ return widget;
+ }
+
+ static void DiskList_setup (GtkWidget *widget, int i, const std::string &path,
+ int usage_percent, int delta_percent, const std::string &description,
+ const std::string &changed, bool is_full)
+ {
+ if (i == 0) {
+ GList *children = gtk_container_get_children (GTK_CONTAINER (widget));
+ for (GList *i = children; i; i = i->next)
+ gtk_container_remove (GTK_CONTAINER (widget), (GtkWidget *) i->data);
+ g_list_free (children);
+ }
+ gtk_table_resize (GTK_TABLE (widget), 2, (i+1)*2);
+
+ GtkWidget *path_label, *usage_label, *graph;
+ path_label = gtk_label_new (path.c_str());
+ gtk_misc_set_alignment (GTK_MISC (path_label), 0, 0.5);
+ gtk_label_set_ellipsize (GTK_LABEL (path_label), PANGO_ELLIPSIZE_END);
+ gtk_widget_set_tooltip_text (path_label, path.c_str());
+ gtk_widget_set_size_request (path_label, 40, -1);
+ usage_label = gtk_label_new (("used: " + description).c_str());
+ gtk_misc_set_alignment (GTK_MISC (usage_label), 1, 0.5);
+ YGUtils::setWidgetFont (usage_label, PANGO_STYLE_ITALIC, PANGO_WEIGHT_NORMAL, PANGO_SCALE_SMALL);
+ graph = ygtk_bar_graph_new();
+ gtk_widget_set_size_request (graph, 150, -1);
+
+ YGtkBarGraph *ygraph = YGTK_BAR_GRAPH (graph);
+ ygtk_bar_graph_set_style (ygraph, TRUE);
+ bool show_delta = delta_percent > 0;
+ int entries = show_delta ? 3 : 2;
+ ygtk_bar_graph_create_entries (ygraph, entries);
+ ygtk_bar_graph_setup_entry (ygraph, 0, "", usage_percent);
+ if (show_delta)
+ ygtk_bar_graph_setup_entry (ygraph, 1, "+", delta_percent);
+ ygtk_bar_graph_setup_entry (ygraph, entries-1, "", 100 - (delta_percent+usage_percent));
+
+// TODO: set some nice colors (do gradient for space)
+ if (is_full) {
+ GdkColor red = { 0, 0xffff, 0xffff, 0xffff };
+ ygtk_bar_graph_customize_bg (ygraph, 0, &red);
+ }
+
+ GtkAttachOptions regularOpt = GtkAttachOptions (GTK_FILL);
+ GtkAttachOptions expandOpt = GtkAttachOptions (GTK_EXPAND|GTK_FILL);
+ int row = i*2;
+ gtk_table_attach (GTK_TABLE (widget), path_label, 0, 1, row, row+1,
+ regularOpt, regularOpt, 0, 0);
+ gtk_table_attach (GTK_TABLE (widget), graph, 1, 2, row, row+1,
+ expandOpt, regularOpt, 0, 0);
+ gtk_table_attach (GTK_TABLE (widget), usage_label, 1, 2, row+1, row+2,
+ regularOpt, regularOpt, 0, 6);
+ gtk_widget_show_all (widget);
+ }
+
+#else // GtkTreeView
+ static GtkWidget *DiskList_new (GtkTreeModel *model, bool framed)
+ {
+ bool foreign_model = model == NULL;
+ if (model == NULL) {
+ GtkListStore *store = gtk_list_store_new (6,
+ // 0 - mount point, 1 - usage percent, 2 - usage string,
+ // (highlight warns) 3 - font weight, 4 - font color string,
+ // 5 - delta description
+ G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING,
+ G_TYPE_STRING);
+ model = GTK_TREE_MODEL (store);
+ }
+
+ GtkWidget *view = gtk_tree_view_new_with_model (model), *scroll = view;
+ if (foreign_model)
+ g_object_unref (G_OBJECT (model));
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE);
+ gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (view)),
+ GTK_SELECTION_NONE);
+
+ GtkTreeViewColumn *column;
+ column = gtk_tree_view_column_new_with_attributes (_("Mount Point"),
+ gtk_cell_renderer_text_new(), "text", 0, "weight", 3, "foreground", 4, NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
+ column = gtk_tree_view_column_new_with_attributes (_("Usage"),
+ gtk_cell_renderer_progress_new(), "value", 1, "text", 2, NULL);
+ gtk_tree_view_column_set_min_width (column, 180); // SIZE_REQUEST
+ gtk_tree_view_column_set_expand (column, TRUE);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
+ GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
+ g_object_set (G_OBJECT (renderer), "alignment", PANGO_ALIGN_RIGHT,
+ "style", PANGO_STYLE_ITALIC, NULL);
+ column = gtk_tree_view_column_new_with_attributes ("Delta",
+ renderer, "text", 5, NULL);
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
+
+ if (framed) {
+ scroll = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll),
+ GTK_SHADOW_IN);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
+ GTK_POLICY_NEVER, GTK_POLICY_NEVER);
+ gtk_container_add (GTK_CONTAINER (scroll), view);
+ }
+ else
+ g_object_set (view, "can-focus", FALSE, NULL);
+ gtk_widget_show_all (scroll);
+ return scroll;
+ }
+
+ static void DiskList_setup (GtkWidget *widget, int i, const std::string &path,
+ int usage_percent, int delta_percent, const std::string &description,
+ const std::string &changed, bool is_full)
+ {
+ GtkTreeView *view = GTK_TREE_VIEW (widget);
+ GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
+ if (i == 0)
+ gtk_list_store_clear (store);
+ GtkTreeIter iter;
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, 0, path.c_str(), 1, usage_percent,
+ 2, description.c_str(), 3, PANGO_WEIGHT_NORMAL, 4, NULL,
+ 5, changed.c_str(), -1);
+ if (is_full)
+ gtk_list_store_set (store, &iter, 3, PANGO_WEIGHT_BOLD, 4, "red", -1);
+ }
+#endif
+
+GdkPixbuf *m_diskPixbuf, *m_diskFullPixbuf;
+bool m_hasWarn;
+GtkWidget *m_button, *m_view;
+
+public:
+ GtkWidget *getWidget()
+ { return m_button; }
+
+ DiskView ()
+ : m_hasWarn (false)
+ {
+ m_button = ygtk_menu_button_new();
+ gtk_widget_set_tooltip_text (m_button, _("Disk usage"));
+ gtk_container_add (GTK_CONTAINER (m_button), gtk_image_new_from_pixbuf (NULL));
+
+ m_view = DiskList_new (NULL, false);
+ ygtk_menu_button_set_popup_align (YGTK_MENU_BUTTON (m_button), m_view, 0.0, 1.0);
+
+ m_diskPixbuf = YGUtils::loadPixbuf (std::string (DATADIR) + "/harddisk.png");
+ m_diskFullPixbuf = YGUtils::loadPixbuf (std::string (DATADIR) + "/harddisk-full.png");
+
+ Ypp::get()->getDisk()->setListener (this);
+ update();
+ }
+
+ ~DiskView()
+ {
+ g_object_unref (m_diskPixbuf);
+ g_object_unref (m_diskFullPixbuf);
+ }
+
+private:
+ virtual void update()
+ {
+ #define MIN_PERCENT_WARN 90
+ #define MIN_FREE_MB_WARN (500*1024)
+ bool warn = false;
+ Ypp::Disk *disk = Ypp::get()->getDisk();
+ for (int i = 0; disk->getPartition (i); i++) {
+ const Ypp::Disk::Partition *part = disk->getPartition (i);
+
+ int usage_percent = (part->used * 100) / (part->total + 1);
+ int delta_percent = (part->delta * 100) / (part->total + 1);
+
+ bool full = usage_percent > MIN_PERCENT_WARN &&
+ (part->total - part->used) < MIN_FREE_MB_WARN;
+ if (full) warn = true;
+ std::string description (part->used_str + _(" of ") + part->total_str);
+ std::string delta_str;
+ if (part->delta) {
+ delta_str = (part->delta > 0 ? "(+" : "(");
+ delta_str += part->delta_str + ")";
+ }
+ DiskList_setup (m_view, i, part->path, usage_percent, delta_percent,
+ description, delta_str, full);
+ }
+ GdkPixbuf *pixbuf = m_diskPixbuf;
+ if (warn) {
+ pixbuf = m_diskFullPixbuf;
+ popupWarning();
+ }
+ gtk_image_set_from_pixbuf (GTK_IMAGE (GTK_BIN (m_button)->child), pixbuf);
+ }
+
+ void popupWarning()
+ {
+ if (m_hasWarn) return;
+ m_hasWarn = true;
+ if (!GTK_WIDGET_REALIZED (getWidget())) return;
+
+ GtkWidget *dialog, *view;
+ dialog = gtk_message_dialog_new (YGDialog::currentWindow(),
+ GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_OK, "%s", _("Disk Almost Full !"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s",
+ _("One of the partitions is reaching its limit of capacity. You may "
+ "have to remove packages if you wish to install some."));
+
+ GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (m_view));
+ view = DiskList_new (model, true);
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), view);
+ g_signal_connect (G_OBJECT (dialog), "response",
+ G_CALLBACK (gtk_widget_destroy), this);
+ gtk_widget_show (dialog);
+ }
+};
+
+// mockup experiments
+#define PKG_SELECTOR_FACE 0
+
+class PackageSelector : public Filters::Listener, public PackagesView::Listener,
+ public PackageDetails::Listener
+{
+friend class YGPackageSelector;
+PackagesView *m_packages;
+Filters *m_filters;
+PackageControl *m_control;
+PackageDetails *m_details;
+DiskView *m_disk;
+GtkWidget *m_box, *m_details_box;
+ChangesPane *m_changes;
+
+public:
+ GtkWidget *getWidget()
+ { return m_box; }
+
+ PackageSelector()
+ {
+ m_packages = new PackagesView (true, false, false, true, true);
+ m_filters = new Filters();
+ m_control = new PackageControl (m_filters);
+ m_details = new PackageDetails();
+ m_disk = new DiskView();
+ m_changes = new ChangesPane();
+ m_packages->setListener (this);
+ m_filters->setListener (this);
+ m_details->setListener (this);
+
+#if (PKG_SELECTOR_FACE == 0)
+ GtkWidget *categories_box = gtk_vbox_new (FALSE, 4);
+ gtk_box_pack_start (GTK_BOX (categories_box), m_filters->getTypeWidget(), FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (categories_box), m_filters->getCollectionWidget(),
+ TRUE, TRUE, 0);
+
+ GtkWidget *packages_label = gtk_label_new_with_mnemonic (_("Packages _listing:"));
+ gtk_label_set_mnemonic_widget (GTK_LABEL (packages_label),
+ GTK_BIN (m_packages->getWidget())->child);
+ gtk_misc_set_alignment (GTK_MISC (packages_label), 0, 0.5);
+
+ GtkWidget *packages_bar = gtk_hbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (packages_bar), packages_label, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (packages_bar), m_filters->getNameWidget(), FALSE, TRUE, 0);
+
+ GtkWidget *packages_box = gtk_vbox_new (FALSE, 4);
+ gtk_box_pack_start (GTK_BOX (packages_box), packages_bar, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (packages_box), m_packages->getWidget(), TRUE, TRUE, 0);
+
+ m_details_box = gtk_hbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (m_details_box), m_details->getWidget(), TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (m_details_box), m_control->getWidget(), FALSE, TRUE, 0);
+
+ GtkWidget *categories_pane = gtk_hpaned_new();
+ gtk_paned_pack1 (GTK_PANED (categories_pane), categories_box, FALSE, TRUE);
+ gtk_paned_pack2 (GTK_PANED (categories_pane), packages_box, TRUE, FALSE);
+ gtk_paned_set_position (GTK_PANED (categories_pane), 180);
+
+ GtkWidget *details_pane = gtk_vpaned_new();
+ gtk_paned_pack1 (GTK_PANED (details_pane), categories_pane, TRUE, FALSE);
+ gtk_paned_pack2 (GTK_PANED (details_pane), m_details_box, FALSE, FALSE);
+ gtk_paned_set_position (GTK_PANED (details_pane), 30000 /* minimal size */);
+
+ m_box = gtk_vbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (m_box), m_filters->getStatusesWidget(),
+ FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (m_box), details_pane, TRUE, TRUE, 0);
+#endif
+#if (PKG_SELECTOR_FACE == 1)
+ // based on KPorts: http://kde-apps.org/content/show.php/KPorts?content=24579
+ GtkWidget *type_combo = gtk_combo_box_new_text();
+ gtk_combo_box_append_text (GTK_COMBO_BOX (type_combo), "Search");
+ gtk_combo_box_append_text (GTK_COMBO_BOX (type_combo), "Groups");
+ gtk_combo_box_append_text (GTK_COMBO_BOX (type_combo), "Changed");
+ gtk_combo_box_set_active (GTK_COMBO_BOX (type_combo), 0);
+
+ GtkWidget *pkg_box = gtk_vbox_new (FALSE, 6);
+ //gtk_box_pack_start (GTK_BOX (pkg_box), m_filters->getTypeWidget(), FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (pkg_box), type_combo, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (pkg_box), m_filters->getNameWidget(), FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (pkg_box), m_packages->getWidget(), TRUE, TRUE, 0);
+ m_packages->setMode (PackagesView::CHECK_MODE, true);
+
+ GtkWidget *control_align = gtk_alignment_new (0, 0, 0, 1);
+ gtk_container_add (GTK_CONTAINER (control_align), m_control->getWidget());
+
+ m_details_box = gtk_vbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (m_details_box), m_details->getWidget(), TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (m_details_box), control_align, FALSE, TRUE, 0);
+
+ m_box = gtk_hpaned_new();
+ gtk_paned_pack1 (GTK_PANED (m_box), pkg_box, TRUE, FALSE);
+ gtk_paned_pack2 (GTK_PANED (m_box), m_details_box, TRUE, FALSE);
+ gtk_paned_set_position (GTK_PANED (m_box), 250);
+#endif
+#if (PKG_SELECTOR_FACE == 2)
+ struct inner {
+ static void install_button_clicked_cb (GtkButton *button, PackagesView *view)
+ {
+ PkgList pkgs = view->getSelected();
+ pkgs.install();
+ }
+ static void remove_button_clicked_cb (GtkButton *button, PackagesView *view)
+ {
+ PkgList pkgs = view->getSelected();
+ pkgs.remove();
+ }
+ static void undo_button_clicked_cb (GtkButton *button, PackagesView *view)
+ {
+ PkgList pkgs = view->getSelected();
+ pkgs.undo();
+ }
+ };
+
+ Ypp::QueryPool::Query *query = new Ypp::QueryPool::Query();
+ query->setToModify (true);
+ PackagesView *changes = new PackagesView (true, false, false, true, true);
+ changes->setQuery (query);
+
+ GtkWidget *install_btn = gtk_button_new_with_label (" install > ");
+ GtkWidget *undo_btn = gtk_button_new_with_label (" < undo ");
+ g_signal_connect (G_OBJECT (install_btn), "clicked",
+ G_CALLBACK (inner::install_button_clicked_cb), m_packages);
+ g_signal_connect (G_OBJECT (undo_btn), "clicked",
+ G_CALLBACK (inner::undo_button_clicked_cb), changes);
+ //gtk_widget_set_sensitive (undo_btn, FALSE);
+
+ m_details_box = gtk_vbox_new (FALSE, 18);
+ //gtk_box_pack_start (GTK_BOX (m_details_box), m_control->getWidget(), FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (m_details_box), gtk_label_new (""), TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (m_details_box), install_btn, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (m_details_box), undo_btn, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (m_details_box), gtk_label_new (""), TRUE, TRUE, 0);
+
+ GtkWidget *type_combo = gtk_combo_box_new_text();
+ gtk_combo_box_append_text (GTK_COMBO_BOX (type_combo), "Available");
+ gtk_combo_box_append_text (GTK_COMBO_BOX (type_combo), "Upgrades");
+ gtk_combo_box_append_text (GTK_COMBO_BOX (type_combo), "Installed");
+ gtk_combo_box_set_active (GTK_COMBO_BOX (type_combo), 0);
+
+ GtkWidget *find_align = gtk_alignment_new (0, 0, 0, 1);
+ gtk_container_add (GTK_CONTAINER (find_align), m_filters->getNameWidget());
+
+ GtkWidget *packages_box = gtk_vbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (packages_box), type_combo, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (packages_box), m_packages->getWidget(), TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (packages_box), find_align, FALSE, TRUE, 0);
+
+ GtkWidget *changes_label = gtk_label_new ("Changes:");
+ gtk_misc_set_alignment (GTK_MISC (changes_label), 0, 0.5);
+ GtkWidget *changes_box = gtk_vbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (changes_box), changes_label, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (changes_box), changes->getWidget(), TRUE, TRUE, 0);
+
+ GtkSizeGroup *labels_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
+ gtk_size_group_add_widget (labels_group, type_combo); // type_combo is acting as a label
+ gtk_size_group_add_widget (labels_group, changes_label);
+ g_object_unref (G_OBJECT (labels_group));
+
+ m_box = gtk_hbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (m_box), packages_box, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (m_box), m_details_box, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (m_box), changes_box, TRUE, TRUE, 0);
+#endif
+
+ gtk_widget_show_all (m_box);
+ m_changes->startHack();
+ packagesSelected (PkgList());
+ gtk_widget_hide (m_details_box);
+ }
+
+ ~PackageSelector()
+ {
+ delete m_packages;
+ delete m_filters;
+ delete m_details;
+ delete m_disk;
+ delete m_changes;
+ }
+
+ virtual void doQuery (Ypp::QueryPool::Query *query)
+ {
+#if (PKG_SELECTOR_FACE == 1)
+query = new Ypp::QueryPool::Query();
+query->addType (Ypp::Package::PACKAGE_TYPE);
+#endif
+ m_packages->setQuery (query);
+ }
+
+ virtual void packagesSelected (const PkgList &packages)
+ {
+ m_details->setPackages (packages);
+ m_control->setPackages (packages);
+ if (!packages.empty())
+ gtk_widget_show (m_details_box);
+ }
+
+ virtual void goToPackage (Ypp::Package *package)
+ {
+ m_packages->unselectAll();
+ PkgList list;
+ list.push (package);
+ m_details->setPackages (list);
+ m_control->setPackages (list);
+ }
+
+ void packageModified (Ypp::Package *package)
+ {
+ m_control->packageModified (package);
+
+ YGtkWizard *wizard = YGTK_WIZARD (YGWidget::get (pkg_selector)->getWidget());
+ ygtk_wizard_enable_button (wizard, wizard->next_button, TRUE);
+ }
+};
+
+#include "pkg-selector-help.h"
+
+YGPackageSelector::YGPackageSelector (YWidget *parent, long mode)
+ : YPackageSelector (NULL, mode),
+ YGWidget (this, parent, YGTK_TYPE_WIZARD, NULL)
+{
+ pkg_selector = this;
+ setBorder (0);
+ YGDialog::currentDialog()->setMinSize (650, 750); // enlarge
+
+ YGtkWizard *wizard = YGTK_WIZARD (getWidget());
+ ygtk_wizard_set_header_icon (wizard,
+ THEMEDIR "/icons/22x22/apps/yast-software.png");
+ const char *title = onlineUpdateMode() ? _("Online Update") : _("Software Manager");
+ ygtk_wizard_set_header_text (wizard, title);
+ YGDialog::currentDialog()->setTitle (title);
+ ygtk_wizard_set_help_text (wizard, _("Please wait..."));
+
+ ygtk_wizard_set_button_label (wizard, wizard->abort_button,
+ _("_Cancel"), GTK_STOCK_CANCEL);
+ ygtk_wizard_set_button_str_id (wizard, wizard->abort_button, "cancel");
+ ygtk_wizard_set_button_label (wizard, wizard->back_button, NULL, NULL);
+ ygtk_wizard_set_button_label (wizard, wizard->next_button,
+ _("A_pply"), GTK_STOCK_APPLY);
+ ygtk_wizard_set_button_str_id (wizard, wizard->next_button, "accept");
+ ygtk_wizard_enable_button (wizard, wizard->next_button, FALSE);
+ g_signal_connect (G_OBJECT (wizard), "action-triggered",
+ G_CALLBACK (wizard_action_cb), this);
+
+ YGDialog *dialog = YGDialog::currentDialog();
+ dialog->setCloseCallback (confirm_cb, this);
+
+ busyCursor();
+ m_package_selector = new PackageSelector();
+ ygtk_wizard_enable_button (wizard, wizard->next_button,
+ modifiedPackagesExist() ? TRUE : FALSE);
+ ygtk_wizard_set_child (YGTK_WIZARD (wizard), m_package_selector->getWidget());
+
+ createToolsButton();
+#if (PKG_SELECTOR_FACE == 0)
+ ygtk_wizard_set_information_widget (YGTK_WIZARD (wizard),
+ m_package_selector->m_changes->getWidget(), FALSE);
+#endif
+
+ Ypp::get()->setInterface (this);
+ Ypp::get()->addPkgListener (this);
+ ygtk_wizard_set_help_text (wizard, onlineUpdateMode() ? _(patch_help) : _(pkg_help));
+ normalCursor();
+}
+
+YGPackageSelector::~YGPackageSelector()
+{
+ delete m_package_selector;
+ ygtk_zypp_model_finish();
+ pkg_selector = 0;
+}
+bool YGPackageSelector::modifiedPackagesExist()
+{
+ Ypp::QueryPool::Query *query = new Ypp::QueryPool::Query();
+ query->setToModify (true);
+ if (pkg_selector->onlineUpdateMode())
+ query->addType (Ypp::Package::PATCH_TYPE);
+ Ypp::QueryPool * tmp_pool = new Ypp::QueryPool (query);
+ bool m_p_exist = tmp_pool->getFirst() != NULL;
+ delete tmp_pool;
+ return m_p_exist;
+}
+
+void YGPackageSelector::wizard_action_cb (YGtkWizard *wizard, gpointer id,
+ gint id_type, YGPackageSelector *pThis)
+{
+ IMPL
+ const gchar *action = (gchar *) id;
+
+ if (!strcmp (action, "accept")) {
+ yuiMilestone() << "Closing PackageSelector with 'accept'" << endl;
+#if YAST2_VERSION >= 2017013
+ if (pThis->confirmUnsupported())
+ if (!pThis->askConfirmUnsupported())
+ return;
+#endif
+ YGUI::ui()->sendEvent (new YMenuEvent ("accept"));
+ }
+ else if (!strcmp (action, "cancel")) {
+ yuiMilestone() << "Closing PackageSelector with 'cancel'" << endl;
+ if (pThis->confirmExit())
+ YGUI::ui()->sendEvent (new YCancelEvent());
+ }
+}
+
+bool YGPackageSelector::confirmExit()
+{
+ if (!Ypp::get()->isModified())
+ return true;
+
+ GtkWidget *dialog;
+ dialog = gtk_message_dialog_new(
+ YGDialog::currentWindow(),
+ GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_NONE, "%s", _("Changes not saved!"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s",
+ _("Quit anyway?"));
+ gtk_dialog_add_buttons (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_NO,
+ GTK_STOCK_QUIT, GTK_RESPONSE_YES, NULL);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES);
+
+ bool ok = gtk_dialog_run (GTK_DIALOG (dialog)) ==
+ GTK_RESPONSE_YES;
+ gtk_widget_destroy (dialog);
+ return ok;
+}
+
+bool YGPackageSelector::confirm_cb (void *pThis)
+{ return ((YGPackageSelector *)pThis)->confirmExit(); }
+
+bool YGPackageSelector::askConfirmUnsupported()
+{
+ Ypp::QueryPool::Query *query = new Ypp::QueryPool::Query();
+ query->addType (Ypp::Package::PACKAGE_TYPE);
+ query->setIsInstalled (false);
+ query->setToModify (true);
+ query->setIsUnsupported (true);
+
+ Ypp::QueryPool *pool = new Ypp::QueryPool (query);
+ if (!pool->empty()) {
+ // show which packages are unsupported
+ GtkWidget *dialog;
+ dialog = gtk_message_dialog_new (
+ YGDialog::currentWindow(),
+ GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_NONE, "%s", _("Unsupported Packages"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s",
+ _("Please realize that the following software is either unsupported or "
+ "requires an additional customer contract for support."));
+ gtk_dialog_add_buttons (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_NO,
+ GTK_STOCK_OK, GTK_RESPONSE_YES, NULL);
+
+ PackagesView *view = new PackagesView (true, false, false, false, true);
+ view->setPool (pool);
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), view->getWidget());
+
+ bool ok = gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES;
+ gtk_widget_destroy (dialog);
+ return ok;
+ }
+ else {
+ delete pool;
+ return true;
+ }
+}
+
+bool YGPackageSelector::acceptText (Ypp::Package *package, const std::string &title,
+ const std::string &open, const std::string &text,
+ bool question)
+{
+ GtkWidget *dialog = gtk_message_dialog_new (
+ YGDialog::currentWindow(),
+ (GtkDialogFlags) 0,
+ question ? GTK_MESSAGE_QUESTION : GTK_MESSAGE_INFO,
+ question ? GTK_BUTTONS_YES_NO : GTK_BUTTONS_OK,
+ "%s %s", package->name().c_str(), title.c_str());
+ if (!open.empty())
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ "%s", open.c_str());
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES);
+
+ GtkWidget *view = ygtk_html_wrap_new(), *scroll;
+ ygtk_html_wrap_set_text (view, text.c_str(), FALSE);
+
+ scroll = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type ( GTK_SCROLLED_WINDOW (scroll),
+ GTK_SHADOW_IN);
+ gtk_container_add (GTK_CONTAINER (scroll), view);
+
+ GtkBox *vbox = GTK_BOX (GTK_DIALOG(dialog)->vbox);
+ gtk_box_pack_start (vbox, scroll, TRUE, TRUE, 6);
+
+ gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE);
+ gtk_window_set_default_size (GTK_WINDOW (dialog), 550, 450);
+ gtk_widget_show_all (dialog);
+
+ gint ret = gtk_dialog_run (GTK_DIALOG (dialog));
+ bool confirmed = (ret == GTK_RESPONSE_YES);
+ gtk_widget_destroy (dialog);
+ return confirmed;
+}
+
+bool YGPackageSelector::acceptLicense (Ypp::Package *package, const std::string &license)
+{
+ return acceptText (package, _("License Agreement"),
+ _("Do you accept the terms of this license?"), license, true);
+}
+
+void YGPackageSelector::notifyMessage (Ypp::Package *package, const std::string &msg)
+{
+ acceptText (package, _("Notification"), "", msg, false);
+}
+
+bool YGPackageSelector::resolveProblems (const std::list &problems)
+{
+ // we can't use ordinary radio buttons, as gtk+ enforces that in a group
+ // one must be selected...
+
+ #define DETAILS_PAD 25
+ enum ColumnAlias {
+ SHOW_TOGGLE_COL, ACTIVE_TOGGLE_COL, TEXT_COL, WEIGHT_TEXT_COL,
+ TEXT_PAD_COL, APPLY_PTR_COL, TOTAL_COLS
+ };
+
+ struct inner {
+ static void solution_toggled (GtkTreeModel *model, GtkTreePath *path)
+ {
+ GtkTreeStore *store = GTK_TREE_STORE (model);
+ GtkTreeIter iter, parent;
+
+ gboolean enabled;
+ bool *apply;
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter, ACTIVE_TOGGLE_COL, &enabled,
+ APPLY_PTR_COL, &apply, -1);
+ if (!apply)
+ return;
+
+ // disable all the other radios on the group, setting current
+ gtk_tree_model_get_iter (model, &iter, path);
+ if (gtk_tree_model_iter_parent (model, &parent, &iter)) {
+ gtk_tree_model_iter_children (model, &iter, &parent);
+ do {
+ gtk_tree_store_set (store, &iter, ACTIVE_TOGGLE_COL, FALSE, -1);
+ bool *apply;
+ gtk_tree_model_get (model, &iter, APPLY_PTR_COL, &apply, -1);
+ if (apply) *apply = false;
+ } while (gtk_tree_model_iter_next (model, &iter));
+ }
+
+ enabled = !enabled;
+ *apply = enabled;
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_store_set (store, &iter, ACTIVE_TOGGLE_COL, enabled, -1);
+ }
+ static void cursor_changed_cb (GtkTreeView *view, GtkTreeModel *model)
+ {
+ GtkTreePath *path;
+ gtk_tree_view_get_cursor (view, &path, NULL);
+ solution_toggled (model, path);
+ gtk_tree_path_free (path);
+ }
+ };
+
+ // model
+ GtkTreeStore *store = gtk_tree_store_new (TOTAL_COLS,
+ G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_INT,
+ G_TYPE_INT, G_TYPE_POINTER);
+ for (std::list ::const_iterator it = problems.begin();
+ it != problems.end(); it++) {
+ GtkTreeIter problem_iter;
+ gtk_tree_store_append (store, &problem_iter, NULL);
+ gtk_tree_store_set (store, &problem_iter, SHOW_TOGGLE_COL, FALSE,
+ TEXT_COL, (*it)->description.c_str(), WEIGHT_TEXT_COL,
+ PANGO_WEIGHT_BOLD, -1);
+ if (!(*it)->details.empty()) {
+ GtkTreeIter details_iter;
+ gtk_tree_store_append (store, &details_iter, &problem_iter);
+ gtk_tree_store_set (store, &details_iter, SHOW_TOGGLE_COL, FALSE,
+ TEXT_COL, (*it)->details.c_str(), TEXT_PAD_COL,
+ DETAILS_PAD, -1);
+ }
+
+ for (int i = 0; (*it)->getSolution (i); i++) {
+ Ypp::Problem::Solution *solution = (*it)->getSolution (i);
+ GtkTreeIter solution_iter;
+ gtk_tree_store_append (store, &solution_iter, &problem_iter);
+ gtk_tree_store_set (store, &solution_iter,
+ SHOW_TOGGLE_COL, TRUE,
+ WEIGHT_TEXT_COL, PANGO_WEIGHT_NORMAL,
+ ACTIVE_TOGGLE_COL, FALSE,
+ TEXT_COL, solution->description.c_str(),
+ APPLY_PTR_COL, &solution->apply,
+ -1);
+ if (!solution->details.empty()) {
+ gtk_tree_store_append (store, &solution_iter, &problem_iter);
+ gtk_tree_store_set (store, &solution_iter,
+ SHOW_TOGGLE_COL, FALSE,
+ WEIGHT_TEXT_COL, PANGO_WEIGHT_NORMAL,
+ TEXT_COL, solution->details.c_str(),
+ TEXT_PAD_COL, DETAILS_PAD, -1);
+ }
+ }
+ }
+
+ // interface
+ GtkWidget *dialog = gtk_message_dialog_new (YGDialog::currentWindow(),
+ GtkDialogFlags (0), GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, "%s",
+ _("There are some conflicts on the transaction that must be "
+ "solved manually."));
+ gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_APPLY, GTK_RESPONSE_APPLY,
+ NULL);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_APPLY);
+
+ GtkWidget *view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
+ g_object_unref (G_OBJECT (store));
+ gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (view)),
+ GTK_SELECTION_NONE);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE);
+ gtk_tree_view_set_search_column (GTK_TREE_VIEW (view), TEXT_COL);
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+ renderer = gtk_cell_renderer_toggle_new();
+ gtk_cell_renderer_toggle_set_radio (
+ GTK_CELL_RENDERER_TOGGLE (renderer), TRUE);
+ // we should not connect the actual toggle button, as we toggle on row press
+ g_signal_connect (G_OBJECT (view), "cursor-changed",
+ G_CALLBACK (inner::cursor_changed_cb), store);
+ column = gtk_tree_view_column_new_with_attributes (
+ "", renderer,
+ "visible", SHOW_TOGGLE_COL,
+ "active", ACTIVE_TOGGLE_COL,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
+ renderer = gtk_cell_renderer_text_new();
+ g_object_set (G_OBJECT (renderer), "wrap-width", 400, NULL);
+ column = gtk_tree_view_column_new_with_attributes (
+ "", renderer,
+ "text", TEXT_COL,
+ "weight", WEIGHT_TEXT_COL,
+ "xpad", TEXT_PAD_COL,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
+ gtk_widget_set_has_tooltip (view, TRUE);
+
+ GtkWidget *scroll = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
+ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll),
+ GTK_SHADOW_IN);
+ gtk_container_add (GTK_CONTAINER (scroll), view);
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), scroll);
+
+ gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE);
+ gtk_window_set_default_size (GTK_WINDOW (dialog), -1, 480);
+ gtk_widget_show_all (dialog);
+
+ bool apply = (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_APPLY);
+ gtk_widget_destroy (dialog);
+ return apply;
+}
+
+bool YGPackageSelector::allowRestrictedRepo (
+ const std::list > &pkgs)
+{
+ std::string text;
+ std::list < std::pair >::const_iterator it;
+ for (it = pkgs.begin(); it != pkgs.end(); it++) {
+ const Ypp::Package *pkg = it->first;
+ const Ypp::Repository *repo = it->second;
+ if (!text.empty())
+ text += "\n\n";
+ text += pkg->name() + "\n<i>" + repo->name + "</i>";
+ }
+
+ // interface
+ GtkWidget *dialog = gtk_message_dialog_new (YGDialog::currentWindow(),
+ GtkDialogFlags (0), GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, "%s",
+ _("Dependencies from Filtered Repositories"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s",
+ _("The following packages have necessary dependencies that are not provided "
+ "by the filtered repository. Install them?"));
+ gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+ GTK_STOCK_NO, GTK_RESPONSE_NO,
+ GTK_STOCK_YES, GTK_RESPONSE_YES,
+ NULL);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES);
+
+ GtkWidget *label = gtk_label_new (text.c_str());
+ gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+ gtk_label_set_selectable (GTK_LABEL (label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
+
+ GtkWidget *scroll = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
+ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scroll), label);
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), scroll);
+
+ gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE);
+ gtk_window_set_default_size (GTK_WINDOW (dialog), -1, 480);
+ gtk_widget_show_all (dialog);
+
+ bool confirm = (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES);
+ gtk_widget_destroy (dialog);
+ return confirm;
+}
+
+void YGPackageSelector::packageModified (Ypp::Package *package)
+{
+ // FIXME: this is mostly a hack; the thing is that GtkTreeSelection doesn't
+ // signal when a selected row changes values. Anyway, to be done differently.
+ m_package_selector->packageModified (package);
+}
+
+// Utilities
+void YGPackageSelector::createToolsButton()
+{
+ struct inner {
+ static void errorMsg (const std::string &header, const std::string &message)
+ {
+ GtkWidget *dialog = gtk_message_dialog_new (YGDialog::currentWindow(),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ "%s", header.c_str());
+ gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog),
+ "%s", message.c_str());
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ }
+ static void import_file_cb (GtkMenuItem *item, YGPackageSelector *pThis)
+ {
+ GtkWidget *dialog;
+ dialog = gtk_file_chooser_dialog_new (_("Import Package List"),
+ YGDialog::currentWindow(),
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
+ GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+ NULL);
+
+ int ret = gtk_dialog_run (GTK_DIALOG (dialog));
+ if (ret == GTK_RESPONSE_ACCEPT) {
+ char *filename;
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+ if (!Ypp::get()->importList (filename)) {
+ std::string error = _("Couldn't load package list from: ");
+ error += filename;
+ errorMsg (_("Import Failed"), error);
+ }
+ g_free (filename);
+ }
+ gtk_widget_destroy (dialog);
+ }
+ static void export_file_cb (GtkMenuItem *item, YGPackageSelector *pThis)
+ {
+ GtkWidget *dialog;
+ dialog = gtk_file_chooser_dialog_new (_("Export Package List"),
+ YGDialog::currentWindow(),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
+ GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+ NULL);
+
+ int ret = gtk_dialog_run (GTK_DIALOG (dialog));
+ if (ret == GTK_RESPONSE_ACCEPT) {
+ char *filename;
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+ if (!Ypp::get()->exportList (filename)) {
+ std::string error = _("Couldn't save package list to: ");
+ error += filename;
+ errorMsg (_("Export Failed"), error);
+ }
+ g_free (filename);
+ }
+ gtk_widget_destroy (dialog);
+ }
+ static void create_solver_testcase_cb (GtkMenuItem *item)
+ {
+ const char *dirname = "/var/log/YaST2/solverTestcase";
+ std::string msg = _("Use this to generate extensive logs to help tracking down "
+ "bugs in the dependency resolver.\nThe logs will be stored in "
+ "directory: ");
+ msg += dirname;
+
+ GtkWidget *dialog = gtk_message_dialog_new (YGDialog::currentWindow(),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_OK_CANCEL,
+ "%s", _("Create Dependency Resolver Test Case"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ "%s", msg.c_str());
+ int ret = gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ if (ret == GTK_RESPONSE_OK) {
+ if (Ypp::get()->createSolverTestcase (dirname)) {
+ GtkWidget *dialog = gtk_message_dialog_new (YGDialog::currentWindow(),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_YES_NO,
+ "%s", _("Success"));
+ msg = _("Dependency resolver test case written to");
+ msg += " <tt>";
+ msg += dirname;
+ msg += "</tt>\n";
+ msg += _("Prepare <tt>y2logs.tgz tar</tt> archive to attach to Bugzilla?");
+ gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog),
+ "%s", msg.c_str());
+ ret = gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ if (ret == GTK_RESPONSE_YES)
+ YGUI::ui()->askSaveLogs();
+ }
+ else {
+ msg = _("Failed to create dependency resolver test case.\n"
+ "Please check disk space and permissions for");
+ msg += " <tt>";
+ msg += dirname;
+ msg += "</tt>";
+ errorMsg ("Error", msg.c_str());
+ }
+ }
+ }
+ };
+
+ GtkWidget *button, *popup, *item;
+ button = ygtk_menu_button_new_with_label (_("Tools"));
+ popup = gtk_menu_new();
+
+ item = gtk_menu_item_new_with_label (_("Import List..."));
+ gtk_menu_shell_append (GTK_MENU_SHELL (popup), item);
+ g_signal_connect (G_OBJECT (item), "activate",
+ G_CALLBACK (inner::import_file_cb), this);
+ item = gtk_menu_item_new_with_label (_("Export List..."));
+ gtk_menu_shell_append (GTK_MENU_SHELL (popup), item);
+ g_signal_connect (G_OBJECT (item), "activate",
+ G_CALLBACK (inner::export_file_cb), this);
+ gtk_menu_shell_append (GTK_MENU_SHELL (popup), gtk_separator_menu_item_new());
+ item = gtk_menu_item_new_with_label (_("Generate Dependency Testcase..."));
+ gtk_menu_shell_append (GTK_MENU_SHELL (popup), item);
+ g_signal_connect (G_OBJECT (item), "activate",
+ G_CALLBACK (inner::create_solver_testcase_cb), this);
+
+ ygtk_menu_button_set_popup (YGTK_MENU_BUTTON (button), popup);
+ gtk_widget_show_all (popup);
+
+ GtkWidget *box = gtk_hbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (box), button, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (box),
+ m_package_selector->m_disk->getWidget(), FALSE, TRUE, 0);
+ gtk_widget_show_all (box);
+ ygtk_wizard_set_extra_button (YGTK_WIZARD (getWidget()), box);
+}
+
+#endif
+
Added: trunk/gtk-pkg/src/YGPackageSelector.h
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/YGPackageSelector.h?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/src/YGPackageSelector.h (added)
+++ trunk/gtk-pkg/src/YGPackageSelector.h Thu Jun 4 12:11:35 2009
@@ -0,0 +1,77 @@
+/*---------------------------------------------------------------------\
+| |
+| __ __ ____ _____ ____ |
+| \ \ / /_ _/ ___|_ _|___ \ |
+| \ V / _` \___ \ | | __) | |
+| | | (_| |___) || | / __/ |
+| |_|\__,_|____/ |_| |_____| |
+| |
+| core system |
+| (c) SuSE Linux AG |
+\----------------------------------------------------------------------/
+
+ File: YGPackageSelector.h
+
+ Author: Ricardo Cruz
+ Martin Kudlvasr
+
+/-*/
+
+#ifndef YGPackageSelector_h
+#define YGPackageSelector_h
+
+#define YGPackageSelector_ENABLED 1 // set 0 to disable this gtk package selector widget
+
+#if YGPackageSelector_ENABLED
+#include "YPackageSelector.h"
+#include "ygtkzyppwrapper.h"
+#include "YGWidget.h"
+#include "ygtkwizard.h"
+#include "YWidget.h"
+
+class PackageSelector;
+
+class YGPackageSelector : public YPackageSelector, public YGWidget,
+ public Ypp::Interface, public Ypp::PkgListener
+{
+ PackageSelector *m_package_selector;
+public:
+ YGPackageSelector (YWidget *parent, long mode);
+ virtual ~YGPackageSelector();
+protected:
+ bool modifiedPackagesExist();
+ static void wizard_action_cb (YGtkWizard *wizard, gpointer id,
+ gint id_type, YGPackageSelector *pThis);
+ bool confirmExit();
+ static bool confirm_cb (void *pThis);
+ bool askConfirmUnsupported();
+ bool acceptText (Ypp::Package *package, const std::string &title,
+ const std::string &open, const std::string &text, bool question);
+ virtual bool acceptLicense (Ypp::Package *package, const std::string &license);
+ virtual void notifyMessage (Ypp::Package *package, const std::string &msg);
+ virtual bool resolveProblems (const std::list &problems);
+ virtual bool allowRestrictedRepo (const std::list > &pkgs);
+ virtual void packageModified (Ypp::Package *package);
+
+ YGWIDGET_IMPL_COMMON (YPackageSelector)
+
+ void createToolsButton();
+};
+
+#else
+class YGPackageSelector : public YPackageSelector, public YGWidget
+{
+public:
+ YGPackageSelector (YWidget *parent, long mode)
+ : YPackageSelector (NULL, mode),
+ YGWidget (this, parent, true, GTK_TYPE_EVENT_BOX, NULL)
+ {
+ }
+ YGWIDGET_IMPL_COMMON (YPackageSelector)
+};
+
+#endif /* enable gtk package selector widget */
+
+#endif /* YGPackageSelector_h */
+
Added: trunk/gtk-pkg/src/YGPackageSelectorPluginImpl.cc
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/YGPackageSelectorPluginImpl.cc?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/src/YGPackageSelectorPluginImpl.cc (added)
+++ trunk/gtk-pkg/src/YGPackageSelectorPluginImpl.cc Thu Jun 4 12:11:35 2009
@@ -0,0 +1,56 @@
+/*---------------------------------------------------------------------\
+| |
+| __ __ ____ _____ ____ |
+| \ \ / /_ _/ ___|_ _|___ \ |
+| \ V / _` \___ \ | | __) | |
+| | | (_| |___) || | / __/ |
+| |_|\__,_|____/ |_| |_____| |
+| |
+| core system |
+| (c) SuSE Linux AG |
+\----------------------------------------------------------------------/
+
+ File: YGPackageSelectorPluginImpl.cc
+
+ Author: Martin Kudlvasr
+
+/-*/
+
+#define YUILogComponent "gtk-pkg"
+#include "YGPackageSelectorPluginImpl.h"
+#include "YGPackageSelector.h"
+#include "YPackageSelector.h"
+
+#include
+extern "C"
+{
+ // Important to locate this symbol - see YQPackageSelectorPluginStub.cc in package yast2-qt
+ YGPackageSelectorPluginImpl PSP;
+}
+
+YPackageSelector * YGPackageSelectorPluginImpl::createPackageSelector( YWidget * parent,
+ long modeFlags )
+{
+ YGPackageSelector * packageSelector = 0;
+
+ try
+ {
+ packageSelector = new YGPackageSelector( parent, modeFlags );
+ }
+ catch (const std::exception & e)
+ {
+ yuiError() << "Caught std::exception: " << e.what() << endl;
+ yuiError() << "This is a libzypp problem. Do not file a bug against the UI!" << endl;
+ }
+ catch (...)
+ {
+ yuiError() << "Caught unspecified exception." << endl;
+ yuiError() << "This is a libzypp problem. Do not file a bug against the UI!" << endl;
+ }
+
+ YUI_CHECK_NEW( packageSelector );
+
+ yuiMilestone() << "Package selector created: " << packageSelector <http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/YGPackageSelectorPluginImpl.h?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/src/YGPackageSelectorPluginImpl.h (added)
+++ trunk/gtk-pkg/src/YGPackageSelectorPluginImpl.h Thu Jun 4 12:11:35 2009
@@ -0,0 +1,34 @@
+/*---------------------------------------------------------------------\
+| |
+| __ __ ____ _____ ____ |
+| \ \ / /_ _/ ___|_ _|___ \ |
+| \ V / _` \___ \ | | __) | |
+| | | (_| |___) || | / __/ |
+| |_|\__,_|____/ |_| |_____| |
+| |
+| core system |
+| (c) SuSE Linux AG |
+\----------------------------------------------------------------------/
+
+ File: YGPackageSelectorPluginImpl.h
+
+ Author: Martin Kudlvasr
+
+/-*/
+
+#ifndef YGPackageSelectorPluginImpl_h
+#define YGPackageSelectorPluginImpl_h
+
+#include "YGPackageSelectorPluginIf.h"
+
+class YGPackageSelectorPluginImpl : public YGPackageSelectorPluginIf
+{
+
+ public:
+
+ virtual ~YGPackageSelectorPluginImpl() {};
+
+ virtual YPackageSelector * createPackageSelector( YWidget * parent, long modeFlags);
+
+};
+#endif
Added: trunk/gtk-pkg/src/hr.xpm
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/hr.xpm?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/src/hr.xpm (added)
+++ trunk/gtk-pkg/src/hr.xpm Thu Jun 4 12:11:35 2009
@@ -0,0 +1,173 @@
+/* XPM */
+static const char * hr_xpm[] = {
+"200 1 169 2",
+" c None",
+". c #F0F8F0",
+"+ c #EEF8EF",
+"@ c #EEF7ED",
+"# c #EDF6EC",
+"$ c #EBF6EB",
+"% c #E9F4E9",
+"& c #E9F4E8",
+"* c #E7F3E7",
+"= c #E6F3E6",
+"- c #E4F2E4",
+"; c #E2F1E3",
+"> c #E1F1E1",
+", c #E0F0E0",
+"' c #DFEFDF",
+") c #DDEFDE",
+"! c #DCEEDD",
+"~ c #DBEEDB",
+"{ c #DAEDDA",
+"] c #D8EDD8",
+"^ c #D7ECD7",
+"/ c #D5EBD5",
+"( c #D4EBD4",
+"_ c #D3EAD3",
+": c #D2EAD2",
+"< c #D0E9D0",
+"[ c #CFE8CF",
+"} c #CEE8CE",
+"| c #CCE7CC",
+"1 c #CBE6CB",
+"2 c #CAE5CA",
+"3 c #C9E5C9",
+"4 c #C7E4C7",
+"5 c #C6E4C6",
+"6 c #C4E3C4",
+"7 c #C3E2C3",
+"8 c #C2E2C2",
+"9 c #C1E1C0",
+"0 c #BFE1C0",
+"a c #BEE0BE",
+"b c #BDE0BC",
+"c c #BBDFBB",
+"d c #BADEBA",
+"e c #B8DEB8",
+"f c #B7DDB7",
+"g c #B6DCB6",
+"h c #B5DBB5",
+"i c #B3DBB3",
+"j c #B2DAB2",
+"k c #B1DAB1",
+"l c #AFD9AF",
+"m c #AED8AE",
+"n c #ADD8AD",
+"o c #ABD7AC",
+"p c #AAD6AA",
+"q c #A8D6A9",
+"r c #A7D5A7",
+"s c #A6D5A6",
+"t c #A4D4A4",
+"u c #A3D3A3",
+"v c #A2D3A2",
+"w c #A0D2A0",
+"x c #A0D1A0",
+"y c #9ED19E",
+"z c #9CD19D",
+"A c #9BCF9B",
+"B c #9ACF9A",
+"C c #99CF99",
+"D c #98CE97",
+"E c #96CD97",
+"F c #95CC94",
+"G c #94CC94",
+"H c #92CB92",
+"I c #91CA91",
+"J c #90CA8F",
+"K c #8EC98E",
+"L c #8DC88D",
+"M c #8BC88C",
+"N c #8AC88B",
+"O c #89C689",
+"P c #87C788",
+"Q c #86C586",
+"R c #85C585",
+"S c #84C484",
+"T c #82C483",
+"U c #81C380",
+"V c #7FC37F",
+"W c #7EC27E",
+"X c #7DC17D",
+"Y c #7BC17C",
+"Z c #7ABF7B",
+"` c #79BF79",
+" . c #78BF78",
+".. c #76BE76",
+"+. c #75BE75",
+"@. c #74BD73",
+"#. c #73BC72",
+"$. c #71BB71",
+"%. c #70BA70",
+"&. c #6FBA6E",
+"*. c #6EBA6E",
+"=. c #EFF7EF",
+"-. c #EEF7EE",
+";. c #ECF6EC",
+">. c #EAF5EA",
+",. c #E9F5E9",
+"'. c #E8F4E8",
+"). c #E4F3E4",
+"!. c #E3F1E3",
+"~. c #E2F1E2",
+"{. c #DFF0DF",
+"]. c #DEEFDD",
+"^. c #DCEFDC",
+"/. c #DAEED9",
+"(. c #D8ECD8",
+"_. c #D7ECD6",
+":. c #D6ECD6",
+"<. c #D4EAD4",
+"[. c #D2EAD1",
+"}. c #D1E9D1",
+"|. c #CDE7CD",
+"1. c #CBE7CB",
+"2. c #CAE6CA",
+"3. c #C8E5C9",
+"4. c #C7E5C7",
+"5. c #C6E4C5",
+"6. c #C5E3C4",
+"7. c #C0E1C1",
+"8. c #BFE1BF",
+"9. c #BDE0BE",
+"0. c #BDDFBC",
+"a. c #BCDEBB",
+"b. c #B4DBB5",
+"c. c #B2DAB1",
+"d. c #B0DAB0",
+"e. c #B0D9B0",
+"f. c #AED9AE",
+"g. c #ACD8AC",
+"h. c #ACD8AB",
+"i. c #AAD6A9",
+"j. c #A7D6A8",
+"k. c #A6D4A6",
+"l. c #A5D4A5",
+"m. c #A3D3A4",
+"n. c #A1D2A1",
+"o. c #9FD29F",
+"p. c #9CD09C",
+"q. c #9BD09C",
+"r. c #98CE99",
+"s. c #97CE98",
+"t. c #96CD96",
+"u. c #95CD95",
+"v. c #93CC93",
+"w. c #8FCA8F",
+"x. c #8DC88C",
+"y. c #8CC88B",
+"z. c #8AC78A",
+"A. c #88C687",
+"B. c #86C587",
+"C. c #84C585",
+"D. c #82C382",
+"E. c #80C381",
+"F. c #80C280",
+"G. c #7EC27F",
+"H. c #7CC07B",
+"I. c #7AC07B",
+"J. c #75BD75",
+"K. c #74BD74",
+"L. c #6EBB6E",
+". =.-.;.>.,.'.* = ).!.~., {.].^.~ /.(._.:.<._ [.}.[ |.| 1.2.3.4.5.6.7 8 7.8.9.0.a.d e f g b.i c.d.e.f.g.h.i.q j.k.l.m.v n.o.y p.q.B r.s.t.u.v.H I w.K x.y.z.O A.B.C.S D.E.F.G.X H.I.` ...J.K.#.$.%.L.*.*.L.%.$.#.K.J... .` I.H.X G.F.E.D.S C.B.A.O z.y.x.K w.I H v.u.t.s.r.B q.p.y o.n.v m.l.k.j.q i.h.g.f.e.d.c.i b.g f e d a.0.9.8.7.8 7 6.5.4.3.2.1.| |.[ }.[._ <.:._.(./.~ ^.].{., ~.!.).= * '.,.>.;.-.=.. "};
Added: trunk/gtk-pkg/src/icons/harddisk-full.png
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/icons/harddisk-full.png?rev=57423&view=auto
==============================================================================
Binary file - no diff available.
Added: trunk/gtk-pkg/src/icons/harddisk.png
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/icons/harddisk.png?rev=57423&view=auto
==============================================================================
Binary file - no diff available.
Added: trunk/gtk-pkg/src/icons/pkg-available-locked.png
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/icons/pkg-available-locked.png?rev=57423&view=auto
==============================================================================
Binary file - no diff available.
Added: trunk/gtk-pkg/src/icons/pkg-available.png
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/icons/pkg-available.png?rev=57423&view=auto
==============================================================================
Binary file - no diff available.
Added: trunk/gtk-pkg/src/icons/pkg-install-auto.png
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/icons/pkg-install-auto.png?rev=57423&view=auto
==============================================================================
Binary file - no diff available.
Added: trunk/gtk-pkg/src/icons/pkg-install.png
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/icons/pkg-install.png?rev=57423&view=auto
==============================================================================
Binary file - no diff available.
Added: trunk/gtk-pkg/src/icons/pkg-installed-locked.png
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/icons/pkg-installed-locked.png?rev=57423&view=auto
==============================================================================
Binary file - no diff available.
Added: trunk/gtk-pkg/src/icons/pkg-installed-upgradable-locked.png
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/icons/pkg-installed-upgradable-locked.png?rev=57423&view=auto
==============================================================================
Binary file - no diff available.
Added: trunk/gtk-pkg/src/icons/pkg-installed-upgradable.png
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/icons/pkg-installed-upgradable.png?rev=57423&view=auto
==============================================================================
Binary file - no diff available.
Added: trunk/gtk-pkg/src/icons/pkg-installed.png
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/icons/pkg-installed.png?rev=57423&view=auto
==============================================================================
Binary file - no diff available.
Added: trunk/gtk-pkg/src/icons/pkg-list-mode.xpm
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/icons/pkg-list-mode.xpm?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/src/icons/pkg-list-mode.xpm (added)
+++ trunk/gtk-pkg/src/icons/pkg-list-mode.xpm Thu Jun 4 12:11:35 2009
@@ -0,0 +1,13 @@
+/* XPM */
+static const char * pkg_list_mode_xpm[] = {
+"8 8 2 1",
+" c None",
+". c #000000",
+" ",
+"........",
+" ",
+" ",
+"...... ",
+" ",
+" ",
+"........"};
Added: trunk/gtk-pkg/src/icons/pkg-locked.png
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/icons/pkg-locked.png?rev=57423&view=auto
==============================================================================
Binary file - no diff available.
Added: trunk/gtk-pkg/src/icons/pkg-remove-auto.png
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/icons/pkg-remove-auto.png?rev=57423&view=auto
==============================================================================
Binary file - no diff available.
Added: trunk/gtk-pkg/src/icons/pkg-remove.png
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/icons/pkg-remove.png?rev=57423&view=auto
==============================================================================
Binary file - no diff available.
Added: trunk/gtk-pkg/src/icons/pkg-tiles-mode.xpm
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/icons/pkg-tiles-mode.xpm?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/src/icons/pkg-tiles-mode.xpm (added)
+++ trunk/gtk-pkg/src/icons/pkg-tiles-mode.xpm Thu Jun 4 12:11:35 2009
@@ -0,0 +1,13 @@
+/* XPM */
+static const char * pkg_tiles_mode_xpm[] = {
+"8 8 2 1",
+" c None",
+". c #000000",
+" ",
+" .. .. ",
+" .. .. ",
+" ",
+" ",
+" .. .. ",
+" .. .. ",
+" "};
Added: trunk/gtk-pkg/src/icons/pkg-unlocked.png
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/icons/pkg-unlocked.png?rev=57423&view=auto
==============================================================================
Binary file - no diff available.
Added: trunk/gtk-pkg/src/icons/pkg-upgrade.png
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/icons/pkg-upgrade.png?rev=57423&view=auto
==============================================================================
Binary file - no diff available.
Added: trunk/gtk-pkg/src/pkg-selector-help.h
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/pkg-selector-help.h?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/src/pkg-selector-help.h (added)
+++ trunk/gtk-pkg/src/pkg-selector-help.h Thu Jun 4 12:11:35 2009
@@ -0,0 +1,91 @@
+/*
+ Textdomain "yast2-gtk"
+ */
+
+static const char *pkg_help =
+__("<h1>Purpose</h1>"
+"<p>This tool lets you install, remove, and update applications.</p>"
+"<p>&product; 's software management is also called 'package management'. A package is "
+"generally an application bundle, but multiple packages that extend the application "
+"may be offered in order to avoid clutter (e.g. games tend to de-couple the music "
+"data in another package, since its not essential and requires significant disk space). "
+"The base package will get the application's name, while extra packages are suffix-ed. "
+"Common extras are:</p>"
+"<ul>"
+"<li>-plugin-: extends the application with some extra functionality.</li>"
+"<li>-devel: needed for software development.</li>"
+"<li>-debuginfo: needed for software beta-testing.</li>"
+"<li>-fr, -dr, -pl (language siglas): translation files (your language package will "
+"be marked for installation automatically).</li>"
+"</ul>"
+"<p>You will find both packages installed on your system, and packages that are made "
+"available through the setup-ed repositories. You cans either install or upgrade "
+"an available package, or remove an installed one.</p>"
+"<blockquote>A repository is a packages media; it can either be local (such as the &product; CDs), "
+"or a remote internet server. You can find utilities to setup repositories "
+"on the YaST control center.</blockquote>"
+""
+"<h1>Usage</h1>"
+"<h2>Available, Upgrades, Installed buttons</h2>"
+"<p>These buttons produce listings of the different sources of packages. 'Available' "
+"are the ones from the setup-ed repositories less those you have installed. "
+"'Installed' lists the packages installed in your system. 'Upgrades' is a "
+"mix listing of the installed packages that have more recent versions available. "
+"'All' will combine all sources.</p>"
+""
+"<h2>Filters</h2>"
+"<p>Enter free text into the search-field to match their names and descriptions. "
+"(a search for 'office' will bring up the 'OpenOffice' packages as well as "
+"AbiWord which carries the word 'office' in its description). You can also "
+"choose to view software from a specific repository.</p>"
+""
+"<h2>Groups & Collections</h2>"
+"<p>Software for &product; is indexed so that you can find software for a specific "
+"task when you don't know the name of the software you are looking for. Browse "
+"indexes of software through the Groups pane. A more detailed, hierarchical classification "
+"of software packages, like 'Multimedia/Video' is available through the 'Detailed' check "
+"button. 'Patterns' and 'Languages' are task-oriented collections of multiple packages that "
+"install like one (the installation of the 'server'-pattern for example will install various "
+"software needed for running a server). By using 'Install All' you make sure that future "
+"collection changes, when you upgrade &product;, will be honored.</p>"
+""
+"<h2>Software details in the box below</h2>"
+"<p>In the package detail view you can perform actions affecting this software; "
+"like install, uninstall, version-upgrade or -downgrade. All changes that you "
+"make will be saved, but not yet performed.</p>"
+"<p>You can review changes in the right-side pane of the software-manager. You can "
+"revoke changes individually at any time by clicking the 'undo'-button next to "
+"a saved change.</p>"
+"<p>The lock button can be used to lock the selected package state; it won't allow "
+"some automatic operation to install, upgrade or remove the package. This is only "
+"useful in very unusual cases: for instance, you may not want to install some "
+"drivers because they interfere with your system, yet you want to install some "
+"collection that includes them.</p>"
+"<p>The changes will be performed once you decide to click the Apply "
+"button in the lower-right corner. If you want to leave the software-manager "
+"without performing any changes, simply press 'Cancel'.</p>"
+""
+"<blockquote><i>Developed by Ricardo Cruz <rpmcruz@alunos.dcc.fc.up.pt><br>"
+"Thanks to Christian Jaeger for co-designing this tool.</i></blockquote>");
+
+static const char *patch_help =
+__("<h1>Purpose</h1>"
+"<p>This tool gives you control on overviewing and picking patches. You may also "
+"reverse patches that have been applied to the system.</p>"
+""
+"<h1>Usage</h1>"
+"<h2>Categories</h2>"
+"<p>Patches are grouped as follows:</p>"
+"<ul>"
+"<li>Security: patches a software flaw that could be exploited to gain "
+"restricted privilege.</li>"
+"<li>Recommended: fixes non-security related flaws (e.g. data corruption, "
+"performance slowdown)</li>"
+"<li>Optional: ones that only apply to few users.</li>"
+"</ul>"
+"<p>Only patches that apply to your system will be visible. &product; developers "
+"are very restrained in pushing patches; you can be sure that all patches are "
+"of signficant severity.</p>"
+"<p>If you are looking for applications enhancements, you should check for Upgrades "
+"on the Software Manager.</p>");
+
Added: trunk/gtk-pkg/src/ygtkhandlebox.c
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/ygtkhandlebox.c?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/src/ygtkhandlebox.c (added)
+++ trunk/gtk-pkg/src/ygtkhandlebox.c Thu Jun 4 12:11:35 2009
@@ -0,0 +1,66 @@
+/********************************************************************
+ * YaST2-GTK - http://en.opensuse.org/YaST2-GTK *
+ ********************************************************************/
+
+/* YGtkHandleBox widget */
+// check the header file for information about this widget
+
+#include
+#include "ygtkhandlebox.h"
+
+G_DEFINE_TYPE (YGtkHandleBox, ygtk_handle_box, GTK_TYPE_HANDLE_BOX)
+
+static void ygtk_handle_box_init (YGtkHandleBox *box)
+{
+}
+
+static void ygtk_handle_box_realize (GtkWidget *widget)
+{
+ GTK_WIDGET_CLASS (ygtk_handle_box_parent_class)->realize (widget);
+
+ GtkHandleBox *box = GTK_HANDLE_BOX (widget);
+ GdkWindow *window = box->float_window;
+ gdk_window_set_decorations (window, GDK_DECOR_RESIZEH);
+ gdk_window_set_type_hint (window, GDK_WINDOW_TYPE_HINT_DIALOG);
+ gdk_window_set_title (window, "");
+}
+
+static gboolean ygtk_handle_box_configure_event (GtkWidget *widget, GdkEventConfigure *event)
+{
+ GtkHandleBox *box = GTK_HANDLE_BOX (widget);
+ if (event->window == box->float_window) {
+ gtk_widget_queue_resize (widget);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void ygtk_handle_box_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
+{
+ GtkHandleBox *box = GTK_HANDLE_BOX (widget);
+ if (box->child_detached) {
+ gdk_window_move_resize (widget->window, allocation->x, allocation->y,
+ allocation->width, allocation->height);
+ gint width, height;
+ gdk_drawable_get_size (box->float_window, &width, &height);
+ gdk_window_resize (box->bin_window, width, height);
+ GtkAllocation child_alloc = { 0, 0, width, height };
+ gtk_widget_size_allocate (GTK_BIN (widget)->child, &child_alloc);
+ }
+ else
+ GTK_WIDGET_CLASS (ygtk_handle_box_parent_class)->size_allocate (widget, allocation);
+}
+
+GtkWidget* ygtk_handle_box_new (void)
+{ return g_object_new (YGTK_TYPE_HANDLE_BOX, NULL); }
+
+static void ygtk_handle_box_class_init (YGtkHandleBoxClass *klass)
+{
+ ygtk_handle_box_parent_class = g_type_class_peek_parent (klass);
+
+ GtkWidgetClass* widget_class = GTK_WIDGET_CLASS (klass);
+ widget_class->configure_event = ygtk_handle_box_configure_event;
+ widget_class->realize = ygtk_handle_box_realize;
+ widget_class->size_allocate = ygtk_handle_box_size_allocate;
+}
+
Added: trunk/gtk-pkg/src/ygtkhandlebox.h
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/ygtkhandlebox.h?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/src/ygtkhandlebox.h (added)
+++ trunk/gtk-pkg/src/ygtkhandlebox.h Thu Jun 4 12:11:35 2009
@@ -0,0 +1,44 @@
+/********************************************************************
+ * YaST2-GTK - http://en.opensuse.org/YaST2-GTK *
+ ********************************************************************/
+
+/* YGtkHandleBox changes the GtkHandleBox behavior so that the detached
+ window can be user resized.
+*/
+
+#ifndef YGTK_HANDLE_BOX_H
+#define YGTK_HANDLE_BOX_H
+
+#include
+
+G_BEGIN_DECLS
+
+#define YGTK_TYPE_HANDLE_BOX (ygtk_handle_box_get_type ())
+#define YGTK_HANDLE_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ YGTK_TYPE_HANDLE_BOX, YGtkHandleBox))
+#define YGTK_HANDLE_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ YGTK_TYPE_HANDLE_BOX, YGtkHandleBoxClass))
+#define YGTK_IS_HANDLE_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ YGTK_TYPE_HANDLE_BOX))
+#define YGTK_IS_HANDLE_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ YGTK_TYPE_HANDLE_BOX))
+#define YGTK_HANDLE_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ YGTK_TYPE_HANDLE_BOX, YGtkHandleBoxClass))
+
+typedef struct _YGtkHandleBox
+{
+ GtkHandleBox parent;
+} YGtkHandleBox;
+
+typedef struct _YGtkHandleBoxClass
+{
+ GtkHandleBoxClass parent_class;
+} YGtkHandleBoxClass;
+
+GtkWidget* ygtk_handle_box_new (void);
+GType ygtk_handle_box_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* YGTK_HANDLE_BOX_H */
+
Added: trunk/gtk-pkg/src/ygtktogglebutton.c
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/ygtktogglebutton.c?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/src/ygtktogglebutton.c (added)
+++ trunk/gtk-pkg/src/ygtktogglebutton.c Thu Jun 4 12:11:35 2009
@@ -0,0 +1,90 @@
+/********************************************************************
+ * YaST2-GTK - http://en.opensuse.org/YaST2-GTK *
+ ********************************************************************/
+
+/* YGtkToggleButton widget */
+// check the header file for information about this widget
+
+#include
+#include "ygtktogglebutton.h"
+#include
+
+static guint toggle_changed_signal;
+
+G_DEFINE_TYPE (YGtkToggleButton, ygtk_toggle_button, GTK_TYPE_TOGGLE_BUTTON)
+
+static void ygtk_toggle_button_init (YGtkToggleButton *button)
+{
+}
+
+static void ygtk_toggle_button_destroy (GtkObject *object)
+{
+ GTK_OBJECT_CLASS (ygtk_toggle_button_parent_class)->destroy (object);
+ YGtkToggleButton *button = YGTK_TOGGLE_BUTTON (object);
+ if (button->group && !button->foreign_group) {
+ g_slist_free (button->group);
+ button->group = NULL;
+ }
+}
+
+static void ygtk_toggle_button_toggled (GtkToggleButton *toggle)
+{
+ GSList *group = YGTK_TOGGLE_BUTTON (toggle)->group;
+
+ if (gtk_toggle_button_get_active (toggle)) {
+ // disable any active
+ GSList *i;
+ for (i = group; i; i = i->next) {
+ GtkToggleButton *t = i->data;
+ if (t->active && t != toggle) {
+ gtk_toggle_button_set_active (t, FALSE);
+ break;
+ }
+ }
+
+ if (i) {
+ gint nb = g_slist_index (group, toggle);
+ g_signal_emit (YGTK_TOGGLE_BUTTON (toggle), toggle_changed_signal, 0, nb);
+ }
+ }
+ else {
+ // force it to be enabled, if no other is (other could be enabled; eg. when
+ // this code gets triggered from the previous case).
+ GSList *i;
+ for (i = group; i; i = i->next) {
+ GtkToggleButton *t = i->data;
+ if (t->active && t != toggle)
+ break;
+ }
+ if (!i)
+ gtk_toggle_button_set_active (toggle, TRUE);
+ }
+}
+
+GSList *ygtk_toggle_button_get_group (YGtkToggleButton *button)
+{
+ return button->group;
+}
+
+GtkWidget *ygtk_toggle_button_new (GSList *group)
+{
+ YGtkToggleButton *button = g_object_new (YGTK_TYPE_TOGGLE_BUTTON, NULL);
+ button->group = g_slist_append (group, button);
+ button->foreign_group = group != NULL;
+ return (GtkWidget *) button;
+}
+
+static void ygtk_toggle_button_class_init (YGtkToggleButtonClass *klass)
+{
+ GtkObjectClass *gtkobject_class = GTK_OBJECT_CLASS (klass);
+ gtkobject_class->destroy = ygtk_toggle_button_destroy;
+
+ GtkToggleButtonClass *gtktogglebutton_class = GTK_TOGGLE_BUTTON_CLASS (klass);
+ gtktogglebutton_class->toggled = ygtk_toggle_button_toggled;
+
+ toggle_changed_signal = g_signal_new ("toggle-changed",
+ G_TYPE_FROM_CLASS (G_OBJECT_CLASS (klass)), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (YGtkToggleButtonClass, toggle_changed), NULL, NULL,
+ g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
+}
+
Added: trunk/gtk-pkg/src/ygtktogglebutton.h
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/ygtktogglebutton.h?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/src/ygtktogglebutton.h (added)
+++ trunk/gtk-pkg/src/ygtktogglebutton.h Thu Jun 4 12:11:35 2009
@@ -0,0 +1,49 @@
+/********************************************************************
+ * YaST2-GTK - http://en.opensuse.org/YaST2-GTK *
+ ********************************************************************/
+
+/* YGtkToggleButton extends GtkToggleButton to add groups, just like GtkRadioButtons.
+*/
+
+#ifndef YGTK_TOGGLE_BUTTON_H
+#define YGTK_TOGGLE_BUTTON_H
+
+#include
+G_BEGIN_DECLS
+
+#define YGTK_TYPE_TOGGLE_BUTTON (ygtk_toggle_button_get_type ())
+#define YGTK_TOGGLE_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ YGTK_TYPE_TOGGLE_BUTTON, YGtkToggleButton))
+#define YGTK_TOGGLE_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ YGTK_TYPE_TOGGLE_BUTTON, YGtkToggleButtonClass))
+#define YGTK_IS_TOGGLE_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ YGTK_TYPE_TOGGLE_BUTTON))
+#define YGTK_IS_TOGGLE_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ YGTK_TYPE_TOGGLE_BUTTON))
+#define YGTK_TOGGLE_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ YGTK_TYPE_TOGGLE_BUTTON, YGtkToggleButtonClass))
+
+typedef struct _YGtkToggleButton
+{
+ GtkToggleButton parent;
+ // members:
+ GSList *group;
+ gboolean foreign_group; // (shouldn't be needed...)
+} YGtkToggleButton;
+
+typedef struct _YGtkToggleButtonClass
+{
+ GtkToggleButtonClass parent_class;
+
+ // signals:
+ void (*toggle_changed) (GtkToggleButton *toggle, gint nb);
+} YGtkToggleButtonClass;
+
+GtkWidget* ygtk_toggle_button_new (GSList *group);
+GType ygtk_toggle_button_get_type (void) G_GNUC_CONST;
+
+GSList *ygtk_toggle_button_get_group (YGtkToggleButton *button);
+
+G_END_DECLS
+#endif /*YGTK_TOGGLE_BUTTON_H*/
+
Added: trunk/gtk-pkg/src/ygtktooltip.c
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/ygtktooltip.c?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/src/ygtktooltip.c (added)
+++ trunk/gtk-pkg/src/ygtktooltip.c Thu Jun 4 12:11:35 2009
@@ -0,0 +1,263 @@
+/********************************************************************
+ * YaST2-GTK - http://en.opensuse.org/YaST2-GTK *
+ ********************************************************************/
+
+/* YGtkTooltip widget */
+// check the header file for information about this widget
+
+#include
+#include "ygtktooltip.h"
+#include
+
+#define TOOLTIP_TIMEOUT 10000
+#define POINTER_LENGTH 10
+
+// header
+
+#define YGTK_TYPE_TOOLTIP (ygtk_tooltip_get_type ())
+#define YGTK_TOOLTIP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ YGTK_TYPE_TOOLTIP, YGtkTooltip))
+#define YGTK_TOOLTIP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ YGTK_TYPE_TOOLTIP, YGtkTooltipClass))
+#define YGTK_IS_TOOLTIP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ YGTK_TYPE_TOOLTIP))
+#define YGTK_IS_TOOLTIP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ YGTK_TYPE_TOOLTIP))
+#define YGTK_TOOLTIP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ YGTK_TYPE_TOOLTIP, YGtkTooltipClass))
+
+typedef struct YGtkTooltip
+{
+ GtkWindow parent;
+ // private:
+ YGtkPointerType pointer;
+ guint timeout_id;
+} YGtkTooltip;
+
+typedef struct YGtkTooltipClass
+{
+ GtkWindowClass parent_class;
+} YGtkTooltipClass;
+
+GtkWidget *ygtk_tooltip_new (void);
+GType ygtk_tooltip_get_type (void) G_GNUC_CONST;
+
+// implementation
+
+G_DEFINE_TYPE (YGtkTooltip, ygtk_tooltip, GTK_TYPE_WINDOW)
+
+static void ygtk_tooltip_init (YGtkTooltip *tooltip)
+{
+ GtkWidget *widget = GTK_WIDGET (tooltip);
+ GtkWindow *window = GTK_WINDOW (tooltip);
+ // we may need to do this if _new() not used
+ //g_object_set (G_OBJECT (tooltip), "type", GTK_WINDOW_POPUP, NULL);
+ gtk_window_set_type_hint (window, GDK_WINDOW_TYPE_HINT_TOOLTIP);
+ gtk_widget_set_app_paintable (widget, TRUE);
+ gtk_window_set_resizable (window, FALSE);
+ gtk_widget_set_name (widget, "gtk-tooltip");
+}
+
+static void ygtk_tooltip_finalize (GObject *object)
+{
+ YGtkTooltip *tooltip = YGTK_TOOLTIP (object);
+ if (tooltip->timeout_id) {
+ g_source_remove (tooltip->timeout_id);
+ tooltip->timeout_id = 0;
+ }
+ G_OBJECT_CLASS (ygtk_tooltip_parent_class)->finalize (object);
+}
+
+static void get_border (YGtkTooltip *tooltip, gint *left_border, gint *right_border,
+ gint *up_border, gint *down_border)
+{
+ GtkWidget *widget = GTK_WIDGET (tooltip);
+ *left_border = *right_border = widget->style->xthickness;
+ *up_border = *down_border = widget->style->ythickness;
+ int len = POINTER_LENGTH + 2;
+ switch (tooltip->pointer) {
+ case YGTK_POINTER_NONE: break;
+ case YGTK_POINTER_UP_LEFT:
+ *left_border += len;
+ break;
+ case YGTK_POINTER_UP_RIGHT:
+ *right_border += len;
+ break;
+ case YGTK_POINTER_DOWN_LEFT:
+ case YGTK_POINTER_DOWN_RIGHT:
+ *down_border += len;
+ break;
+ }
+}
+
+static void ygtk_tooltip_size_request (GtkWidget *widget, GtkRequisition *requisition)
+{
+ GTK_WIDGET_CLASS (ygtk_tooltip_parent_class)->size_request (widget, requisition);
+ gint left_border, right_border, up_border, down_border;
+ get_border (YGTK_TOOLTIP (widget), &left_border, &right_border,
+ &up_border, &down_border);
+ requisition->width += left_border + right_border;
+ requisition->height += up_border + down_border;
+}
+
+static void ygtk_tooltip_size_allocate (GtkWidget *widget, GtkAllocation *alloc)
+{
+ GTK_WIDGET_CLASS (ygtk_tooltip_parent_class)->size_allocate (widget, alloc);
+ gint left_border, right_border, up_border, down_border;
+ get_border (YGTK_TOOLTIP (widget), &left_border, &right_border,
+ &up_border, &down_border);
+ GtkAllocation child_alloc = {
+ alloc->x + left_border, alloc->y + up_border,
+ alloc->width - (left_border+right_border),
+ alloc->height - (up_border+down_border)
+ };
+ gtk_widget_size_allocate (GTK_BIN (widget)->child, &child_alloc);
+}
+
+static gboolean ygtk_tooltip_expose_event (GtkWidget *widget, GdkEventExpose *event)
+{
+ gtk_paint_flat_box (widget->style, widget->window, GTK_STATE_NORMAL,
+ GTK_SHADOW_OUT, NULL, widget, "tooltip", 0, 0, widget->allocation.width,
+ widget->allocation.height);
+ YGtkPointerType pointer = YGTK_TOOLTIP (widget)->pointer;
+ if (pointer) {
+ gint x = 0, y = 0, len_x = 0, len_y = 0;
+ switch (pointer) {
+ case YGTK_POINTER_NONE: break;
+ case YGTK_POINTER_UP_LEFT:
+ case YGTK_POINTER_DOWN_LEFT:
+ x = 2;
+ len_x = POINTER_LENGTH;
+ break;
+ case YGTK_POINTER_UP_RIGHT:
+ case YGTK_POINTER_DOWN_RIGHT:
+ x = widget->allocation.width - 2;
+ len_x = -POINTER_LENGTH;
+ break;
+ }
+ switch (pointer) {
+ case YGTK_POINTER_NONE: break;
+ case YGTK_POINTER_UP_LEFT:
+ case YGTK_POINTER_UP_RIGHT:
+ y = 2;
+ len_y = POINTER_LENGTH;
+ break;
+ case YGTK_POINTER_DOWN_LEFT:
+ case YGTK_POINTER_DOWN_RIGHT:
+ y = widget->allocation.height - 2;
+ len_y = -POINTER_LENGTH;
+ break;
+ }
+
+ GdkPoint points[3] = {
+ { x, y }, { x + len_x, y }, { x, y + len_y } };
+ gdk_draw_polygon (widget->window, *widget->style->dark_gc, TRUE, points, 3);
+ }
+ GTK_WIDGET_CLASS (ygtk_tooltip_parent_class)->expose_event (widget, event);
+ return FALSE;
+}
+
+static gboolean tooltip_timeout_cb (void *pdata)
+{
+ YGtkTooltip *tooltip = (YGtkTooltip *) pdata;
+ tooltip->timeout_id = 0;
+ gtk_widget_destroy (GTK_WIDGET (tooltip));
+ return FALSE;
+}
+
+static YGtkTooltip *ygtk_tooltip_create (const gchar *text, const gchar *stock)
+{
+ GtkWidget *tooltip, *box, *label, *image = 0;
+ tooltip = ygtk_tooltip_new();
+ label = gtk_label_new (text);
+ gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+ box = gtk_hbox_new (FALSE, 6);
+ if (stock) {
+ image = gtk_image_new_from_stock (stock, GTK_ICON_SIZE_BUTTON);
+ gtk_box_pack_start (GTK_BOX (box), image, FALSE, TRUE, 0);
+ }
+ gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
+ gtk_widget_show_all (box);
+ gtk_container_add (GTK_CONTAINER (tooltip), box);
+ return YGTK_TOOLTIP (tooltip);
+}
+
+static YGtkTooltip *singleton = 0;
+
+static void ygtk_tooltip_show (YGtkTooltip *tooltip, gint x, gint y)
+{
+ gtk_window_move (GTK_WINDOW (tooltip), x, y);
+ gtk_widget_show (GTK_WIDGET (tooltip));
+ if (singleton)
+ gtk_widget_destroy (GTK_WIDGET (singleton));
+ singleton = tooltip;
+ tooltip->timeout_id = g_timeout_add (TOOLTIP_TIMEOUT, tooltip_timeout_cb, tooltip);
+}
+
+void ygtk_tooltip_show_at (gint x, gint y, YGtkPointerType pointer,
+ const gchar *label, const gchar *stock)
+{
+ YGtkTooltip *tooltip = ygtk_tooltip_create (label, stock);
+ tooltip->pointer = pointer;
+ ygtk_tooltip_show (tooltip, x, y);
+}
+
+#define XMARGIN 8
+#define YMARGIN 2
+
+void ygtk_tooltip_show_at_widget (GtkWidget *widget, YGtkPointerType pointer,
+ const gchar *label, const gchar *stock)
+{
+ YGtkTooltip *tooltip = ygtk_tooltip_create (label, stock);
+ tooltip->pointer = pointer;
+ gint x, y;
+ gdk_window_get_origin (widget->window, &x, &y);
+ if (GTK_WIDGET_NO_WINDOW (widget)) {
+ x += widget->allocation.x;
+ y += widget->allocation.y;
+ }
+ GtkRequisition tooltip_req;
+ gtk_widget_size_request (GTK_WIDGET (tooltip), &tooltip_req);
+ switch (pointer) {
+ case YGTK_POINTER_NONE: break;
+ case YGTK_POINTER_UP_RIGHT:
+ case YGTK_POINTER_DOWN_RIGHT:
+ x -= (tooltip_req.width - widget->allocation.width) + XMARGIN;
+ break;
+ case YGTK_POINTER_UP_LEFT:
+ case YGTK_POINTER_DOWN_LEFT:
+ x += XMARGIN;
+ break;
+ }
+ switch (pointer) {
+ case YGTK_POINTER_NONE: break;
+ case YGTK_POINTER_UP_RIGHT:
+ case YGTK_POINTER_UP_LEFT:
+ y += widget->allocation.height + YMARGIN;
+ break;
+ case YGTK_POINTER_DOWN_RIGHT:
+ case YGTK_POINTER_DOWN_LEFT:
+ y -= tooltip_req.height + YMARGIN;
+ break;
+ }
+ ygtk_tooltip_show (tooltip, x, y);
+}
+
+GtkWidget *ygtk_tooltip_new (void)
+{
+ return g_object_new (YGTK_TYPE_TOOLTIP, "type", GTK_WINDOW_POPUP, NULL);
+}
+
+static void ygtk_tooltip_class_init (YGtkTooltipClass *klass)
+{
+ ygtk_tooltip_parent_class = g_type_class_peek_parent (klass);
+
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = ygtk_tooltip_finalize;
+
+ GtkWidgetClass* widget_class = GTK_WIDGET_CLASS (klass);
+ widget_class->size_request = ygtk_tooltip_size_request;
+ widget_class->size_allocate = ygtk_tooltip_size_allocate;
+ widget_class->expose_event = ygtk_tooltip_expose_event;
+}
+
Added: trunk/gtk-pkg/src/ygtktooltip.h
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/ygtktooltip.h?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/src/ygtktooltip.h (added)
+++ trunk/gtk-pkg/src/ygtktooltip.h Thu Jun 4 12:11:35 2009
@@ -0,0 +1,27 @@
+/********************************************************************
+ * YaST2-GTK - http://en.opensuse.org/YaST2-GTK *
+ ********************************************************************/
+
+/* YGtkTooltip, unlike GtkTooltip, can be used independently of a widget.
+ Also displays an arrow since it's meant to descript some element.
+*/
+
+#ifndef YGTK_TOOLTIP_H
+#define YGTK_TOOLTIP_H
+
+#include
+G_BEGIN_DECLS
+
+typedef enum { YGTK_POINTER_NONE, YGTK_POINTER_UP_LEFT, YGTK_POINTER_UP_RIGHT,
+ YGTK_POINTER_DOWN_LEFT, YGTK_POINTER_DOWN_RIGHT } YGtkPointerType;
+
+// will display the tooltip and destroy it after a few seconds
+// note: no need to free the thing yourself
+void ygtk_tooltip_show_at (gint x, gint y, YGtkPointerType pointer,
+ const gchar *label, const gchar *stock_id);
+void ygtk_tooltip_show_at_widget (GtkWidget *widget, YGtkPointerType pointer,
+ const gchar *label, const gchar *stock_id);
+
+G_END_DECLS
+#endif /*YGTK_TOOLTIP_H*/
+
Added: trunk/gtk-pkg/src/ygtkzyppwrapper.cc
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/ygtkzyppwrapper.cc?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/src/ygtkzyppwrapper.cc (added)
+++ trunk/gtk-pkg/src/ygtkzyppwrapper.cc Thu Jun 4 12:11:35 2009
@@ -0,0 +1,403 @@
+/********************************************************************
+ * YaST2-GTK - http://en.opensuse.org/YaST2-GTK *
+ ********************************************************************/
+
+/* YGtkZyppWrapper, gtk+ hooks for zypp wrapper */
+// check the header file for information about these hooks
+
+#define YUILogComponent "gtk"
+#include
+#include
+#include "ygtkzyppwrapper.h"
+#include "YGUtils.h"
+
+static GdkPixbuf *loadPixbuf (const char *icon)
+{ return YGUtils::loadPixbuf (std::string (DATADIR) + "/" + icon); }
+
+// bridge as we don't want to mix c++ class polymorphism and gobject
+static void ygtk_zypp_model_entry_changed (YGtkZyppModel *model, Ypp::Pool::Iter iter);
+static void ygtk_zypp_model_entry_inserted (YGtkZyppModel *model, Ypp::Pool::Iter iter);
+static void ygtk_zypp_model_entry_deleted (YGtkZyppModel *model, Ypp::Pool::Iter iter);
+struct YGtkZyppModel::PoolNotify : public Ypp::Pool::Listener {
+YGtkZyppModel *model;
+ virtual void entryChanged (Ypp::Pool::Iter iter, Ypp::Package *package)
+ { ygtk_zypp_model_entry_changed (model, iter); }
+ virtual void entryInserted (Ypp::Pool::Iter iter, Ypp::Package *package)
+ { ygtk_zypp_model_entry_inserted (model, iter); }
+ virtual void entryDeleted (Ypp::Pool::Iter iter, Ypp::Package *package)
+ { ygtk_zypp_model_entry_deleted (model, iter); }
+};
+
+// Icons resources
+struct PackageIcons {
+ GdkPixbuf *installed, *installed_upgradable, *installed_locked,
+ *installed_upgradable_locked, *available, *available_locked,
+ *to_install, *to_install_upgrade, *to_remove, *to_auto_install,
+ *to_auto_remove;
+ PackageIcons() {
+ installed = loadPixbuf ("pkg-installed.png");
+ installed_upgradable = loadPixbuf ("pkg-installed-upgradable.png");
+ installed_locked = loadPixbuf ("pkg-installed-locked.png");
+ installed_upgradable_locked = loadPixbuf ("pkg-installed-upgradable-locked.png");
+ available = loadPixbuf ("pkg-available.png");
+ available_locked = loadPixbuf ("pkg-available-locked.png");
+ to_install = loadPixbuf ("pkg-install.png");
+ to_install_upgrade = loadPixbuf ("pkg-upgrade.png");
+ to_remove = loadPixbuf ("pkg-remove.png");
+ to_auto_install = loadPixbuf ("pkg-install-auto.png");
+ to_auto_remove = loadPixbuf ("pkg-remove-auto.png");
+ }
+ ~PackageIcons() {
+ g_object_unref (G_OBJECT (installed));
+ g_object_unref (G_OBJECT (installed_upgradable));
+ g_object_unref (G_OBJECT (installed_upgradable_locked));
+ g_object_unref (G_OBJECT (installed_locked));
+ g_object_unref (G_OBJECT (available));
+ g_object_unref (G_OBJECT (available_locked));
+ g_object_unref (G_OBJECT (to_install));
+ g_object_unref (G_OBJECT (to_remove));
+ g_object_unref (G_OBJECT (to_install_upgrade));
+ g_object_unref (G_OBJECT (to_auto_install));
+ g_object_unref (G_OBJECT (to_auto_remove));
+ }
+};
+
+static PackageIcons *icons = NULL;
+void ygtk_zypp_model_finish (void)
+{
+ delete icons; icons = NULL;
+ Ypp::finish();
+}
+
+static void ygtk_zypp_model_tree_model_init (GtkTreeModelIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (YGtkZyppModel, ygtk_zypp_model, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, ygtk_zypp_model_tree_model_init))
+
+static void ygtk_zypp_model_init (YGtkZyppModel *zmodel)
+{
+ if (!icons)
+ icons = new PackageIcons();
+}
+
+static void ygtk_zypp_model_finalize (GObject *object)
+{
+ YGtkZyppModel *zmodel = YGTK_ZYPP_MODEL (object);
+ delete zmodel->notify;
+ zmodel->notify = NULL;
+ delete zmodel->pool;
+ zmodel->pool = NULL;
+ G_OBJECT_CLASS (ygtk_zypp_model_parent_class)->finalize (object);
+}
+
+static GtkTreeModelFlags ygtk_zypp_model_get_flags (GtkTreeModel *model)
+{
+ YGtkZyppModel *zmodel = YGTK_ZYPP_MODEL (model);
+ int flags = GTK_TREE_MODEL_ITERS_PERSIST;
+ if (zmodel->pool->isPlainList())
+ flags |= (GtkTreeModelFlags) GTK_TREE_MODEL_LIST_ONLY;
+ return (GtkTreeModelFlags) flags;
+}
+
+static gboolean ygtk_zypp_model_get_iter (GtkTreeModel *model, GtkTreeIter *iter,
+ GtkTreePath *path)
+{
+ YGtkZyppModel *zmodel = YGTK_ZYPP_MODEL (model);
+ gint *indices = gtk_tree_path_get_indices (path);
+ gint depth = gtk_tree_path_get_depth (path);
+
+ Ypp::Pool::Path zpath;
+ for (gint i = 0; i < depth; i++)
+ zpath.push_back (indices[i]);
+
+ iter->user_data = (gpointer) zmodel->pool->fromPath (zpath);
+ return iter->user_data != NULL;
+}
+
+static GtkTreePath *ygtk_zypp_model_get_path (GtkTreeModel *model, GtkTreeIter *iter)
+{
+ YGtkZyppModel *zmodel = YGTK_ZYPP_MODEL (model);
+ Ypp::Pool::Path zpath = zmodel->pool->toPath (iter->user_data);
+
+ GtkTreePath *path = gtk_tree_path_new();
+ for (Ypp::Pool::Path::const_iterator it = zpath.begin(); it != zpath.end(); it++)
+ gtk_tree_path_append_index (path, *it);
+ return path;
+}
+
+static gboolean ygtk_zypp_model_iter_next (GtkTreeModel *model, GtkTreeIter *iter)
+{
+ YGtkZyppModel *zmodel = YGTK_ZYPP_MODEL (model);
+ iter->user_data = zmodel->pool->getNext (iter->user_data);
+ return iter->user_data != NULL;
+}
+
+static gboolean ygtk_zypp_model_iter_parent (GtkTreeModel *model, GtkTreeIter *iter,
+ GtkTreeIter *child)
+{
+ YGtkZyppModel *zmodel = YGTK_ZYPP_MODEL (model);
+ iter->user_data = zmodel->pool->getParent (child->user_data);
+ return iter->user_data != NULL;
+}
+
+static gboolean ygtk_zypp_model_iter_has_child (GtkTreeModel *model, GtkTreeIter *iter)
+{
+ YGtkZyppModel *zmodel = YGTK_ZYPP_MODEL (model);
+ return zmodel->pool->getChild (iter->user_data) != NULL;
+}
+
+static gint ygtk_zypp_model_iter_n_children (GtkTreeModel *model, GtkTreeIter *iter)
+{
+ YGtkZyppModel *zmodel = YGTK_ZYPP_MODEL (model);
+ Ypp::Pool::Iter ziter;
+ if (iter == NULL) /* root */
+ ziter = zmodel->pool->getFirst();
+ else {
+ ziter = (Ypp::Pool::Iter) iter->user_data;
+ ziter = zmodel->pool->getChild (ziter);
+ }
+ if (!ziter)
+ return 0;
+ int children = 1;
+ while ((ziter = zmodel->pool->getNext (ziter)))
+ children++;
+ return children;
+}
+
+static gboolean ygtk_zypp_model_iter_nth_child (GtkTreeModel *model, GtkTreeIter *iter,
+ GtkTreeIter *parent, gint n)
+{
+ YGtkZyppModel *zmodel = YGTK_ZYPP_MODEL (model);
+ Ypp::Pool::Iter ziter;
+ if (parent == NULL) /* root */
+ ziter = zmodel->pool->getFirst();
+ else
+ ziter = zmodel->pool->getChild (parent->user_data);
+ if (!ziter)
+ return FALSE;
+ for (int c = 0; c < n; c++)
+ ziter = zmodel->pool->getNext (ziter);
+ iter->user_data = ziter;
+ return iter->user_data != NULL;
+}
+
+static gboolean ygtk_zypp_model_iter_children (GtkTreeModel *model, GtkTreeIter *iter,
+ GtkTreeIter *parent)
+{
+ return ygtk_zypp_model_iter_nth_child (model, iter, parent, 0);
+}
+
+void ygtk_zypp_model_entry_changed (YGtkZyppModel *model, Ypp::Pool::Iter ziter)
+{
+ GtkTreeIter iter;
+ iter.user_data = ziter;
+ GtkTreePath *path = ygtk_zypp_model_get_path (GTK_TREE_MODEL (model), &iter);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
+ gtk_tree_path_free (path);
+}
+
+void ygtk_zypp_model_entry_inserted (YGtkZyppModel *model, Ypp::Pool::Iter it)
+{
+ GtkTreeIter iter;
+ iter.user_data = it;
+ GtkTreePath *path = ygtk_zypp_model_get_path (GTK_TREE_MODEL (model), &iter);
+ gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
+ gtk_tree_path_free (path);
+}
+
+void ygtk_zypp_model_entry_deleted (YGtkZyppModel *model, Ypp::Pool::Iter it)
+{
+ GtkTreeIter iter;
+ iter.user_data = it;
+ GtkTreePath *path = ygtk_zypp_model_get_path (GTK_TREE_MODEL (model), &iter);
+ gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
+ gtk_tree_path_free (path);
+}
+
+static gint ygtk_zypp_model_get_n_columns (GtkTreeModel *model)
+{ return YGtkZyppModel::TOTAL_COLUMNS; }
+
+static GType ygtk_zypp_model_get_column_type (GtkTreeModel *tree_model, gint column)
+{
+ switch (column) {
+ case YGtkZyppModel::ICON_COLUMN:
+ return GDK_TYPE_PIXBUF;
+ case YGtkZyppModel::NAME_COLUMN:
+ case YGtkZyppModel::NAME_TRUNCATE_COLUMN:
+ case YGtkZyppModel::NAME_DESCRIPTION_COLUMN:
+ return G_TYPE_STRING;
+ case YGtkZyppModel::IS_INSTALLED_COLUMN:
+ return G_TYPE_BOOLEAN;
+ case YGtkZyppModel::PTR_COLUMN:
+ return G_TYPE_POINTER;
+ }
+ return 0;
+}
+
+static void ygtk_zypp_model_get_value (GtkTreeModel *model, GtkTreeIter *iter,
+ gint column, GValue *value)
+{
+ YGtkZyppModel *zmodel = YGTK_ZYPP_MODEL (model);
+ Ypp::Pool::Iter pool_iter = iter->user_data;
+ Ypp::Package *package = zmodel->pool->get (pool_iter);
+
+ g_value_init (value, ygtk_zypp_model_get_column_type (model, column));
+
+ if (!package) {
+ if (column == YGtkZyppModel::NAME_COLUMN ||
+ column == YGtkZyppModel::NAME_DESCRIPTION_COLUMN) {
+ std::string name = zmodel->pool->getName (iter->user_data);
+ if (column == YGtkZyppModel::NAME_DESCRIPTION_COLUMN)
+ name = "<big><b>" + name + "</span></b></big>";
+ g_value_set_string (value, g_strdup (name.c_str()));
+ }
+ return;
+ }
+
+ switch (column)
+ {
+ case YGtkZyppModel::ICON_COLUMN:
+ {
+ GdkPixbuf *pixbuf = 0;
+ switch (package->type()) {
+ case Ypp::Package::PATTERN_TYPE: {
+ std::string filename (package->icon());
+ GtkIconTheme *icons = gtk_icon_theme_get_default();
+ pixbuf = gtk_icon_theme_load_icon (icons,
+ filename.c_str(), 32, GtkIconLookupFlags (0), NULL);
+ break;
+ }
+ default:
+ break;
+ }
+ if (pixbuf) {
+ if (!package->isInstalled()) {
+ GdkPixbuf *_pixbuf = pixbuf;
+ pixbuf = YGUtils::setOpacity (_pixbuf, 50, true);
+ g_object_unref (_pixbuf);
+ }
+ }
+ else {
+ bool locked = package->isLocked();
+ bool auto_ = package->isAuto();
+ if (package->toInstall()) {
+ if (auto_)
+ pixbuf = icons->to_auto_install;
+ else {
+ pixbuf = icons->to_install;
+ if (package->isInstalled())
+ pixbuf = icons->to_install_upgrade;
+ }
+ }
+ else if (package->toRemove()) {
+ if (auto_)
+ pixbuf = icons->to_auto_remove;
+ else
+ pixbuf = icons->to_remove;
+ }
+ else if (package->hasUpgrade()) {
+ if (locked)
+ pixbuf = icons->installed_upgradable_locked;
+ else
+ pixbuf = icons->installed_upgradable;
+ }
+ else if (package->isInstalled()) {
+ if (locked)
+ pixbuf = icons->installed_locked;
+ else
+ pixbuf = icons->installed;
+ }
+ else {
+ if (locked)
+ pixbuf = icons->available_locked;
+ else
+ pixbuf = icons->available;
+ }
+ }
+ g_value_set_object (value, (GObject *) pixbuf);
+ break;
+ }
+ case YGtkZyppModel::NAME_COLUMN:
+ {
+ bool highlight = zmodel->pool->highlight (pool_iter);
+ std::string str (package->name());
+ if (highlight)
+ str = "<b>" + str + "</b>";
+ if (package->toModify())
+ str = "<i>" + str + "</i>";
+ g_value_set_string (value, g_strdup (str.c_str()));
+ break;
+ }
+ case YGtkZyppModel::NAME_TRUNCATE_COLUMN:
+ {
+ std::string str (YGUtils::truncate (package->name(), 15, 1));
+ g_value_set_string (value, g_strdup (str.c_str()));
+ break;
+ }
+ case YGtkZyppModel::NAME_DESCRIPTION_COLUMN:
+ {
+ bool highlight = zmodel->pool->highlight (pool_iter);
+ std::string str = package->name();
+/* if (highlight)
+ str = "" + str + "</span>";*/
+ std::string summary = package->summary();
+ if (!summary.empty()) {
+ YGUtils::escapeMarkup (summary);
+ str += "\n<small>" + summary + "</small>";
+ }
+ if (highlight)
+ str = "<b>" + str + "</b>";
+ g_value_set_string (value, g_strdup (str.c_str()));
+ break;
+ }
+ case YGtkZyppModel::IS_INSTALLED_COLUMN:
+ {
+ bool installed = package->toInstall() ||
+ (package->isInstalled() && !package->toRemove());
+ g_value_set_boolean (value, installed);
+ break;
+ }
+ case YGtkZyppModel::PTR_COLUMN:
+ {
+ void *ptr;
+ ptr = (void *) package;
+ g_value_set_pointer (value, ptr);
+ break;
+ }
+ case YGtkZyppModel::TOTAL_COLUMNS:
+ break;
+ }
+}
+
+YGtkZyppModel *ygtk_zypp_model_new (Ypp::Pool *pool)
+{
+ YGtkZyppModel *zmodel = (YGtkZyppModel *) g_object_new (YGTK_TYPE_ZYPP_MODEL, NULL);
+ zmodel->notify = new YGtkZyppModel::PoolNotify();
+ zmodel->notify->model = zmodel;
+ zmodel->pool = pool;
+ zmodel->pool->setListener (zmodel->notify);
+ return zmodel;
+}
+
+static void ygtk_zypp_model_class_init (YGtkZyppModelClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = ygtk_zypp_model_finalize;
+}
+
+static void ygtk_zypp_model_tree_model_init (GtkTreeModelIface *iface)
+{
+ iface->get_flags = ygtk_zypp_model_get_flags;
+ iface->get_n_columns = ygtk_zypp_model_get_n_columns;
+ iface->get_column_type = ygtk_zypp_model_get_column_type;
+ iface->get_iter = ygtk_zypp_model_get_iter;
+ iface->get_path = ygtk_zypp_model_get_path;
+ iface->get_value = ygtk_zypp_model_get_value;
+ iface->iter_next = ygtk_zypp_model_iter_next;
+ iface->iter_children = ygtk_zypp_model_iter_children;
+ iface->iter_has_child = ygtk_zypp_model_iter_has_child;
+ iface->iter_n_children = ygtk_zypp_model_iter_n_children;
+ iface->iter_nth_child = ygtk_zypp_model_iter_nth_child;
+ iface->iter_parent = ygtk_zypp_model_iter_parent;
+}
+
Added: trunk/gtk-pkg/src/ygtkzyppwrapper.h
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/ygtkzyppwrapper.h?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/src/ygtkzyppwrapper.h (added)
+++ trunk/gtk-pkg/src/ygtkzyppwrapper.h Thu Jun 4 12:11:35 2009
@@ -0,0 +1,51 @@
+/********************************************************************
+ * YaST2-GTK - http://en.opensuse.org/YaST2-GTK *
+ ********************************************************************/
+
+/* Contains ZyppWrapper query results in a GtkTreeModel.
+*/
+
+#ifndef YGTK_ZYPP_WRAPPER_H
+#define YGTK_ZYPP_WRAPPER_H
+
+#include "yzyppwrapper.h"
+#include
+
+#define YGTK_TYPE_ZYPP_MODEL (ygtk_zypp_model_get_type ())
+#define YGTK_ZYPP_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ YGTK_TYPE_ZYPP_MODEL, YGtkZyppModel))
+#define YGTK_ZYPP_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ YGTK_TYPE_ZYPP_MODEL, YGtkZyppModelClass))
+#define YGTK_IS_ZYPP_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), YGTK_TYPE_ZYPP_MODEL))
+#define YGTK_IS_ZYPP_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), YGTK_TYPE_ZYPP_MODEL))
+#define YGTK_ZYPP_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ YGTK_TYPE_ZYPP_MODEL, YGtkZyppModelClass))
+
+struct YGtkZyppModel
+{
+ GObject parent;
+
+ enum Columns {
+ ICON_COLUMN, NAME_COLUMN, NAME_TRUNCATE_COLUMN, NAME_DESCRIPTION_COLUMN,
+ IS_INSTALLED_COLUMN, PTR_COLUMN, TOTAL_COLUMNS
+ };
+
+ Ypp::Pool *pool;
+
+ struct PoolNotify;
+ PoolNotify *notify;
+};
+
+struct YGtkZyppModelClass
+{
+ GObjectClass parent_class;
+};
+
+YGtkZyppModel *ygtk_zypp_model_new (Ypp::Pool *pool);
+GType ygtk_zypp_model_get_type (void) G_GNUC_CONST;
+
+// besides calling Ypp for cleaning, it also cleans the icons of this hook
+void ygtk_zypp_model_finish (void);
+
+#endif /*YGTK_ZYPP_WRAPPER_H*/
+
Added: trunk/gtk-pkg/src/yzypptags.cc
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/yzypptags.cc?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/src/yzypptags.cc (added)
+++ trunk/gtk-pkg/src/yzypptags.cc Thu Jun 4 12:11:35 2009
@@ -0,0 +1,133 @@
+/********************************************************************
+ * YaST2-GTK - http://en.opensuse.org/YaST2-GTK *
+ ********************************************************************/
+
+/*
+ Textdomain "yast2-gtk"
+ */
+
+/* Tags PackageKit translator */
+// check the header file for information about this translator
+
+#include
+#include "YGi18n.h"
+#define YUILogComponent "gtk-pkg"
+#include
+#include
+#include "yzypptags.h"
+
+/**
+ * translations taken from packagekit
+ **/
+const char *
+zypp_tag_group_enum_to_localised_text (YPkgGroupEnum group)
+{
+ switch (group)
+ {
+ case PK_GROUP_ENUM_ACCESSIBILITY: return _( "Accessibility" );
+ case PK_GROUP_ENUM_ACCESSORIES: return _( "Accessories" );
+ case PK_GROUP_ENUM_EDUCATION: return _( "Education" );
+ case PK_GROUP_ENUM_GAMES: return _( "Games" );
+ case PK_GROUP_ENUM_GRAPHICS: return _( "Graphics" );
+ case PK_GROUP_ENUM_INTERNET: return _( "Internet" );
+ case PK_GROUP_ENUM_OFFICE: return _( "Office" );
+ case PK_GROUP_ENUM_OTHER: return _( "Other" );
+ case PK_GROUP_ENUM_PROGRAMMING: return _( "Programming" );
+ case PK_GROUP_ENUM_MULTIMEDIA: return _( "Multimedia" );
+ case PK_GROUP_ENUM_SYSTEM: return _( "System" );
+ case PK_GROUP_ENUM_DESKTOP_GNOME: return _( "GNOME Desktop" );
+ case PK_GROUP_ENUM_DESKTOP_KDE: return _( "KDE Desktop" );
+ case PK_GROUP_ENUM_DESKTOP_XFCE: return _( "XFCE Desktop" );
+ case PK_GROUP_ENUM_DESKTOP_OTHER: return _( "Other Desktops" );
+ case PK_GROUP_ENUM_PUBLISHING: return _( "Publishing" );
+ case PK_GROUP_ENUM_SERVERS: return _( "Servers" );
+ case PK_GROUP_ENUM_FONTS: return _( "Fonts" );
+ case PK_GROUP_ENUM_ADMIN_TOOLS: return _( "Admin Tools" );
+ case PK_GROUP_ENUM_LEGACY: return _( "Legacy" );
+ case PK_GROUP_ENUM_LOCALIZATION: return _( "Localization" );
+ case PK_GROUP_ENUM_VIRTUALIZATION: return _( "Virtualization" );
+ case PK_GROUP_ENUM_SECURITY: return _( "Security" );
+ case PK_GROUP_ENUM_POWER_MANAGEMENT: return _( "Power Management" );
+ case PK_GROUP_ENUM_COMMUNICATION: return _( "Communication" );
+ case PK_GROUP_ENUM_NETWORK: return _( "Network" );
+ case PK_GROUP_ENUM_MAPS: return _( "Maps" );
+ case PK_GROUP_ENUM_REPOS: return _( "Software Sources" );
+ case PK_GROUP_ENUM_UNKNOWN: return _( "Unknown Group" );
+ }
+ return _("Unknown Group");
+}
+
+const char *
+zypp_tag_enum_to_icon (YPkgGroupEnum group)
+{
+ // NOTE: some icons are customized (bug 404818)
+ switch (group)
+ {
+ case PK_GROUP_ENUM_ACCESSIBILITY: return( "package_main" );
+ case PK_GROUP_ENUM_ACCESSORIES: return( "package_applications" );
+ case PK_GROUP_ENUM_EDUCATION: return( "package_edutainment" );
+ case PK_GROUP_ENUM_GAMES: return( "package_games" );
+ case PK_GROUP_ENUM_GRAPHICS: return( "package_graphics" );
+ case PK_GROUP_ENUM_INTERNET: return( "package_network" );
+ case PK_GROUP_ENUM_OFFICE: return( "applications-office" );
+ case PK_GROUP_ENUM_OTHER: return( "package_main" );
+ case PK_GROUP_ENUM_PROGRAMMING: return( "package_development" );
+ case PK_GROUP_ENUM_MULTIMEDIA: return( "package_multimedia" );
+ case PK_GROUP_ENUM_SYSTEM: return( "applications-system" );
+ case PK_GROUP_ENUM_DESKTOP_GNOME: return( "pattern-gnome" );
+ case PK_GROUP_ENUM_DESKTOP_KDE: return( "pattern-kde" );
+ case PK_GROUP_ENUM_DESKTOP_XFCE: return( "pattern-xfce" );
+ case PK_GROUP_ENUM_DESKTOP_OTHER: return( "user-desktop" );
+ case PK_GROUP_ENUM_PUBLISHING: return( "package_main" );
+ case PK_GROUP_ENUM_SERVERS: return( "package_editors" );
+ case PK_GROUP_ENUM_FONTS: return( "package_main" );
+ case PK_GROUP_ENUM_ADMIN_TOOLS: return( "yast-sysconfig" );
+ case PK_GROUP_ENUM_LEGACY: return( "package_main" );
+ case PK_GROUP_ENUM_LOCALIZATION: return( "yast-language" );
+ case PK_GROUP_ENUM_VIRTUALIZATION: return( "yast-create-new-vm" );
+ case PK_GROUP_ENUM_SECURITY: return( "yast-security" );
+ case PK_GROUP_ENUM_POWER_MANAGEMENT: return( "package_settings_power" );
+ case PK_GROUP_ENUM_COMMUNICATION: return( "yast-modem" );
+ case PK_GROUP_ENUM_NETWORK: return( "package_network" );
+ case PK_GROUP_ENUM_MAPS: return( "package_main" );
+ case PK_GROUP_ENUM_REPOS: return( "package_main" );
+ case PK_GROUP_ENUM_UNKNOWN: return( "package_main" );
+ }
+ return "";
+}
+
+
+YPkgGroupEnum
+zypp_tag_convert (const std::string &groupu)
+{
+ std::string group = zypp::str::toLower(groupu);
+
+ if ( group.find( "amusements/teaching" ) != string::npos ) return PK_GROUP_ENUM_EDUCATION;
+ if ( group.find( "amusements" ) != string::npos ) return PK_GROUP_ENUM_GAMES;
+ if ( group.find( "development" ) != string::npos ) return PK_GROUP_ENUM_PROGRAMMING;
+ if ( group.find( "hardware" ) != string::npos ) return PK_GROUP_ENUM_SYSTEM;
+ if ( group.find( "archiving" ) != string::npos ) return PK_GROUP_ENUM_ADMIN_TOOLS;
+ if ( group.find( "clustering" ) != string::npos ) return PK_GROUP_ENUM_ADMIN_TOOLS;
+ if ( group.find( "system/monitoring" ) != string::npos ) return PK_GROUP_ENUM_ADMIN_TOOLS;
+ if ( group.find( "databases" ) != string::npos ) return PK_GROUP_ENUM_ADMIN_TOOLS;
+ if ( group.find( "system/management" ) != string::npos ) return PK_GROUP_ENUM_ADMIN_TOOLS;
+ if ( group.find( "graphics" ) != string::npos ) return PK_GROUP_ENUM_GRAPHICS;
+ if ( group.find( "multimedia" ) != string::npos ) return PK_GROUP_ENUM_MULTIMEDIA;
+ if ( group.find( "network" ) != string::npos ) return PK_GROUP_ENUM_NETWORK;
+ if ( group.find( "office" ) != string::npos ) return PK_GROUP_ENUM_OFFICE;
+ if ( group.find( "text" ) != string::npos ) return PK_GROUP_ENUM_OFFICE;
+ if ( group.find( "editors" ) != string::npos ) return PK_GROUP_ENUM_OFFICE;
+ if ( group.find( "publishing" ) != string::npos ) return PK_GROUP_ENUM_PUBLISHING;
+ if ( group.find( "security" ) != string::npos ) return PK_GROUP_ENUM_SECURITY;
+ if ( group.find( "telephony" ) != string::npos ) return PK_GROUP_ENUM_COMMUNICATION;
+ if ( group.find( "gnome" ) != string::npos ) return PK_GROUP_ENUM_DESKTOP_GNOME;
+ if ( group.find( "kde" ) != string::npos ) return PK_GROUP_ENUM_DESKTOP_KDE;
+ if ( group.find( "xfce" ) != string::npos ) return PK_GROUP_ENUM_DESKTOP_XFCE;
+ if ( group.find( "gui/other" ) != string::npos ) return PK_GROUP_ENUM_DESKTOP_OTHER;
+ if ( group.find( "localization" ) != string::npos ) return PK_GROUP_ENUM_LOCALIZATION;
+ if ( group.find( "system" ) != string::npos ) return PK_GROUP_ENUM_SYSTEM;
+ if ( group.find( "scientific" ) != string::npos ) return PK_GROUP_ENUM_EDUCATION;
+
+ return PK_GROUP_ENUM_UNKNOWN;
+}
+
Added: trunk/gtk-pkg/src/yzypptags.h
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/yzypptags.h?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/src/yzypptags.h (added)
+++ trunk/gtk-pkg/src/yzypptags.h Thu Jun 4 12:11:35 2009
@@ -0,0 +1,47 @@
+/********************************************************************
+ * YaST2-GTK - http://en.opensuse.org/YaST2-GTK *
+ ********************************************************************/
+
+/* Converts RPM to PackageKit-like terminology.
+ Code from yast-qt-pkg.
+*/
+
+typedef enum {
+ /* PackageKit values */
+ PK_GROUP_ENUM_ACCESSIBILITY,
+ PK_GROUP_ENUM_ACCESSORIES,
+ PK_GROUP_ENUM_EDUCATION,
+ PK_GROUP_ENUM_GAMES,
+ PK_GROUP_ENUM_GRAPHICS,
+ PK_GROUP_ENUM_INTERNET,
+ PK_GROUP_ENUM_OFFICE,
+ PK_GROUP_ENUM_OTHER,
+ PK_GROUP_ENUM_PROGRAMMING,
+ PK_GROUP_ENUM_MULTIMEDIA,
+ PK_GROUP_ENUM_SYSTEM,
+ PK_GROUP_ENUM_DESKTOP_GNOME,
+ PK_GROUP_ENUM_DESKTOP_KDE,
+ PK_GROUP_ENUM_DESKTOP_XFCE,
+ PK_GROUP_ENUM_DESKTOP_OTHER,
+ PK_GROUP_ENUM_PUBLISHING,
+ PK_GROUP_ENUM_SERVERS,
+ PK_GROUP_ENUM_FONTS,
+ PK_GROUP_ENUM_ADMIN_TOOLS,
+ PK_GROUP_ENUM_LEGACY,
+ PK_GROUP_ENUM_LOCALIZATION,
+ PK_GROUP_ENUM_VIRTUALIZATION,
+ PK_GROUP_ENUM_SECURITY,
+ PK_GROUP_ENUM_POWER_MANAGEMENT,
+ PK_GROUP_ENUM_COMMUNICATION,
+ PK_GROUP_ENUM_NETWORK,
+ PK_GROUP_ENUM_MAPS,
+ PK_GROUP_ENUM_REPOS,
+ PK_GROUP_ENUM_UNKNOWN,
+} YPkgGroupEnum;
+
+
+YPkgGroupEnum zypp_tag_convert (const std::string &rpm_group);
+
+const char *zypp_tag_group_enum_to_localised_text (YPkgGroupEnum group);
+const char *zypp_tag_enum_to_icon (YPkgGroupEnum group);
+
Added: trunk/gtk-pkg/src/yzyppwrapper.cc
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/yzyppwrapper.cc?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/src/yzyppwrapper.cc (added)
+++ trunk/gtk-pkg/src/yzyppwrapper.cc Thu Jun 4 12:11:35 2009
@@ -0,0 +1,2541 @@
+/********************************************************************
+ * YaST2-GTK - http://en.opensuse.org/YaST2-GTK *
+ ********************************************************************/
+
+/*
+ Textdomain "yast2-gtk"
+ */
+
+/* Ypp, zypp wrapper */
+// check the header file for information about this wrapper
+
+#include
+#include "YGi18n.h"
+#include "yzyppwrapper.h"
+#include "yzypptags.h"
+#include
+#include <string>
+#include <sstream>
+#define YUILogComponent "gtk-pkg"
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include "YGUtils.h"
+
+//** Zypp shortcuts
+
+typedef zypp::ResPoolProxy ZyppPool;
+inline ZyppPool zyppPool() { return zypp::getZYpp()->poolProxy(); }
+typedef zypp::ui::Selectable::Ptr ZyppSelectable;
+typedef zypp::ui::Selectable* ZyppSelectablePtr;
+typedef zypp::ResObject::constPtr ZyppObject;
+typedef zypp::ResObject* ZyppObjectPtr;
+typedef zypp::Package::constPtr ZyppPackage;
+typedef zypp::Patch::constPtr ZyppPatch;
+typedef zypp::Pattern::constPtr ZyppPattern;
+inline ZyppPackage tryCastToZyppPkg (ZyppObject obj)
+{ return zypp::dynamic_pointer_cast <const zypp::Package> (obj); }
+inline ZyppPatch tryCastToZyppPatch (ZyppObject obj)
+{ return zypp::dynamic_pointer_cast <const zypp::Patch> (obj); }
+inline ZyppPattern tryCastToZyppPattern (ZyppObject obj)
+{ return zypp::dynamic_pointer_cast <const zypp::Pattern> (obj); }
+
+//** Utilities
+
+// converts a set of tree representation in a form of a strings to a tree structure.
+// String tree representations are, for instance, filenames: /dir1/dir2/file
+struct StringTree {
+ typedef int (*Compare)(const char *, const char *);
+ Compare compare;
+ char delim;
+ const char *trans_domain;
+ GNode *root;
+
+ StringTree (Compare compare, char delim, const char *trans_domain)
+ : compare (compare), delim (delim), trans_domain (trans_domain)
+ {
+ // the root is a dummy node to keep GNode happy
+ root = g_node_new (NULL);
+ }
+
+ ~StringTree()
+ {
+ struct inner {
+ static void free (GNode *node, void *_data)
+ { delete ((Ypp::Node *) node->data); }
+ };
+ g_node_children_foreach (root, G_TRAVERSE_ALL, inner::free, NULL);
+ g_node_destroy (root);
+ }
+
+ Ypp::Node *getFirst()
+ {
+ if (root->children)
+ return (Ypp::Node *) root->children->data;
+ return NULL;
+ }
+
+ Ypp::Node *add (const std::string &tree_str, const std::string &order)
+ {
+ const gchar delimiter[2] = { delim, '\0' };
+ gchar **nodes_str = g_strsplit (tree_str.c_str(), delimiter, -1);
+
+ GNode *parent = root, *sibling = 0;
+ Ypp::Node *ret = 0;
+ gchar **i;
+ for (i = nodes_str; *i; i++) {
+ if (!**i)
+ continue;
+ const char *str = *i;
+ if (trans_domain)
+ str = dgettext (trans_domain, str);
+ bool found = false;
+ if (!order.empty())
+ // when ordered, make sure it already doesn't exist with another order
+ for (sibling = parent->children; sibling; sibling = sibling->next) {
+ Ypp::Node *node = (Ypp::Node *) sibling->data;
+ int cmp = (*compare) (str, node->name.c_str());
+ if (cmp == 0) {
+ found = true;
+ ret = node;
+ break;
+ }
+ }
+ if (!found) {
+ const char *s1 = order.empty() ? str : order.c_str();
+ for (sibling = parent->children; sibling; sibling = sibling->next) {
+ Ypp::Node *node = (Ypp::Node *) sibling->data;
+ const char *s2 = order.empty() ? node->name.c_str() : node->order.c_str();
+ int cmp = (*compare) (s1, s2);
+ if (cmp == 0) {
+ found = true;
+ ret = node;
+ break;
+ }
+ else if (cmp < 0)
+ break;
+ }
+ }
+ if (!found)
+ break;
+ parent = sibling;
+ }
+
+ for (; *i; i++) {
+ Ypp::Node *node = new Ypp::Node();
+ GNode *n = g_node_new ((void *) node);
+ const char *str = *i;
+ if (trans_domain)
+ str = dgettext (trans_domain, str);
+ node->name = str;
+ node->order = order;
+ node->icon = NULL;
+ node->impl = (void *) n;
+ g_node_insert_before (parent, sibling, n);
+ parent = n;
+ sibling = NULL;
+ ret = node;
+ }
+ g_strfreev (nodes_str);
+ return ret;
+ }
+};
+
+//** Singleton
+
+static Ypp *ypp = 0;
+
+Ypp *Ypp::get()
+{
+ if (!ypp)
+ ypp = new Ypp();
+ return ypp;
+}
+
+void Ypp::finish()
+{
+ delete ypp; ypp = NULL;
+}
+
+// Ypp::Impl declaration, to expose some methods for usage
+struct Ypp::Impl
+{
+public:
+ Impl();
+ ~Impl();
+
+ const Repository *getRepository (int nb);
+ const Repository *getRepository (const std::string &zyppId);
+ zypp::RepoInfo getRepoInfo (const Repository *repo);
+ Disk *getDisk();
+
+ // for Packages
+ bool acceptLicense (Ypp::Package *package, const std::string &license);
+ void notifyMessage (Ypp::Package *package, const std::string &message);
+ void packageModified (Ypp::Package *package);
+
+ // for the Primitive Pools
+ GSList *getPackages (Package::Type type);
+
+private:
+ bool resolveProblems();
+ Node *addCategory (Ypp::Package::Type type, const std::string &str, const std::string &order);
+ void polishCategories (Ypp::Package::Type type);
+ Node *addCategory2 (Ypp::Package::Type type, ZyppSelectable sel);
+
+ void startTransactions();
+ void finishTransactions();
+
+ friend class Ypp;
+ GSList *packages [Package::TOTAL_TYPES]; // primitive pools
+ StringTree *categories [Package::TOTAL_TYPES], *categories2;
+ GSList *repos;
+ const Repository *favoriteRepo;
+ int favoriteRepoPriority;
+ Disk *disk;
+ Interface *interface;
+ GSList *pkg_listeners;
+ bool inTransaction;
+ GSList *transactions;
+};
+
+//** Package
+
+struct Ypp::Package::Impl
+{
+ /* Ypp::Package serves as a proxy to this class which is derived into
+ PackageSel for packages, patterns and patches, and PackageLang for locales. */
+
+Type type;
+Package *m_parent;
+std::string m_name, m_summary;
+
+ Impl (Type type) : type (type) {}
+
+ virtual std::string name() = 0;
+ virtual std::string summary() = 0;
+ virtual Node *category() { return NULL; }
+ virtual Node *category2() { return NULL; }
+ virtual bool containsPackage (const Ypp::Package *package) = 0;
+ virtual void containsStats (int *installed, int *total) = 0;
+
+ virtual std::string description (MarkupType markup) = 0;
+ virtual std::string filelist (bool rich) { return ""; }
+ virtual std::string changelog() { return ""; }
+ virtual std::string authors (bool rich) { return ""; }
+ virtual std::string support (bool rich) { return ""; }
+ virtual std::string icon() = 0;
+ virtual bool isRecommended() const { return false; }
+ virtual bool isSuggested() const { return false; }
+ virtual int buildAge() const { return 0; }
+ virtual bool isUnsupported() const { return false; }
+
+ virtual std::string provides (bool rich) const { return ""; }
+ virtual std::string requires (bool rich) const { return ""; }
+
+ virtual const Ypp::Package::Version *getInstalledVersion() { return false; }
+ virtual const Ypp::Package::Version *getAvailableVersion (int nb) { return false; }
+
+ virtual bool isInstalled() = 0;
+ virtual bool hasUpgrade() = 0;
+ virtual bool isLocked() = 0;
+
+ virtual bool toInstall (const Ypp::Package::Version **repo = 0) = 0;
+ virtual bool toRemove() = 0;
+ virtual bool toModify() = 0;
+ virtual bool isAuto() = 0;
+
+ virtual void install (const Ypp::Package::Version *repo) = 0;
+ virtual void remove() = 0;
+ virtual void undo() = 0;
+ virtual bool canLock() = 0;
+ virtual void lock (bool lock) = 0;
+
+ // internal: did the resolver touch it
+ virtual bool isTouched() = 0;
+ virtual void setNotTouched() = 0;
+};
+
+Ypp::Package::Package (Impl *impl) : impl (impl) { impl->m_parent = this; }
+Ypp::Package::~Package() { delete impl; }
+
+Ypp::Package::Type Ypp::Package::type() const { return impl->type; }
+
+const std::string &Ypp::Package::name() const
+{
+ if (impl->m_name.empty())
+ impl->m_name = const_cast (impl)->name();
+ return impl->m_name;
+}
+
+const std::string &Ypp::Package::summary()
+{
+ if (impl->m_summary.empty())
+ impl->m_summary = const_cast (impl)->summary();
+ return impl->m_summary;
+}
+
+Ypp::Node *Ypp::Package::category() { return impl->category(); }
+Ypp::Node *Ypp::Package::category2() { return impl->category2(); }
+bool Ypp::Package::containsPackage (const Ypp::Package *package) const
+{ return const_cast (impl)->containsPackage (package); }
+void Ypp::Package::containsStats (int *installed, int *total) const
+{ const_cast (impl)->containsStats (installed, total); }
+
+std::string Ypp::Package::description (MarkupType markup) { return impl->description (markup); }
+std::string Ypp::Package::filelist (bool rich) { return impl->filelist (rich); }
+std::string Ypp::Package::changelog() { return impl->changelog(); }
+std::string Ypp::Package::authors (bool rich) { return impl->authors (rich); }
+std::string Ypp::Package::support (bool rich) { return impl->support (rich); }
+std::string Ypp::Package::icon() { return impl->icon(); }
+bool Ypp::Package::isRecommended() const { return impl->isRecommended(); }
+bool Ypp::Package::isSuggested() const { return impl->isSuggested(); }
+int Ypp::Package::buildAge() const { return impl->buildAge(); }
+bool Ypp::Package::isUnsupported() const { return impl->isUnsupported(); }
+
+std::string Ypp::Package::provides (bool rich) const { return impl->provides (rich); }
+std::string Ypp::Package::requires (bool rich) const { return impl->requires (rich); }
+
+const Ypp::Package::Version *Ypp::Package::getInstalledVersion()
+{ return impl->getInstalledVersion(); }
+const Ypp::Package::Version *Ypp::Package::getAvailableVersion (int nb)
+{ return impl->getAvailableVersion (nb); }
+const Ypp::Package::Version *Ypp::Package::fromRepository (const Repository *repo)
+{
+ for (int i = 0; getAvailableVersion (i); i++) {
+ const Version *version = getAvailableVersion (i);
+ if (version->repo == repo)
+ return version;
+ }
+ return NULL;
+}
+
+bool Ypp::Package::isInstalled() { return impl->isInstalled(); }
+bool Ypp::Package::hasUpgrade() { return impl->hasUpgrade(); }
+bool Ypp::Package::isLocked() { return impl->isLocked(); }
+
+bool Ypp::Package::toInstall (const Ypp::Package::Version **version)
+{ return impl->toInstall (version); }
+bool Ypp::Package::toRemove() { return impl->toRemove(); }
+bool Ypp::Package::toModify() { return impl->toModify(); }
+bool Ypp::Package::isAuto() { return impl->isAuto(); }
+
+void Ypp::Package::install (const Version *version)
+{
+ impl->install (version);
+ ypp->impl->packageModified (this);
+}
+
+void Ypp::Package::remove()
+{
+ impl->remove();
+ ypp->impl->packageModified (this);
+}
+
+void Ypp::Package::undo()
+{
+ impl->undo();
+ ypp->impl->packageModified (this);
+}
+
+bool Ypp::Package::canLock() { return impl->canLock(); }
+
+void Ypp::Package::lock (bool lock)
+{
+ impl->lock (lock);
+ ypp->impl->packageModified (this);
+}
+
+struct PackageSel : public Ypp::Package::Impl
+{
+ZyppSelectable m_sel;
+Ypp::Node *m_category, *m_category2;
+GSList *m_availableVersions;
+Ypp::Package::Version *m_installedVersion;
+bool m_isInstalled, m_hasUpgrade;
+zypp::ui::Status m_curStatus; // so we know if resolver touched it
+// for Patterns
+GSList *m_containsPackages;
+int m_installedPkgs, m_totalPkgs;
+
+ PackageSel (Ypp::Package::Type type, ZyppSelectable sel, Ypp::Node *category, Ypp::Node *category2)
+ : Impl (type), m_sel (sel), m_category (category), m_category2 (category2),
+ m_availableVersions (NULL), m_installedVersion (NULL), m_containsPackages (NULL)
+ {
+ // for patterns, there is no reliable way to know if it's installed (because
+ // if it set to be installed that will alter candidate's satisfied status.)
+ if (type == Ypp::Package::PATTERN_TYPE || type == Ypp::Package::PATCH_TYPE)
+ m_isInstalled = m_sel->candidateObj().isSatisfied();
+ else {
+ if (m_sel->installedEmpty())
+ m_isInstalled = false;
+ else
+ m_isInstalled = !m_sel->installedObj().isBroken();
+ }
+ // don't use getAvailableVersion(0) for hasUpgrade() has its inneficient.
+ // let's just cache candidate() at start, which should point to the newest version.
+ m_hasUpgrade = false;
+ ZyppObject candidate = sel->candidateObj();
+ ZyppObject installed = sel->installedObj();
+ if (!!candidate && !!installed)
+ m_hasUpgrade = zypp::Edition::compare (candidate->edition(), installed->edition()) > 0;
+
+ setNotTouched();
+ m_installedPkgs = m_totalPkgs = 0;
+ }
+
+ virtual ~PackageSel()
+ {
+ delete m_installedVersion;
+ for (GSList *i = m_availableVersions; i; i = i->next)
+ delete ((Ypp::Package::Version *) i->data);
+ g_slist_free (m_availableVersions);
+ g_slist_free (m_containsPackages);
+ }
+
+ virtual bool isTouched()
+ { return m_curStatus != m_sel->status(); }
+ virtual void setNotTouched()
+ { m_curStatus = m_sel->status(); }
+
+ GSList *getContainedPackages()
+ {
+ if (!m_containsPackages) {
+ switch (type) {
+ case Ypp::Package::PATTERN_TYPE: {
+ ZyppObject object = m_sel->theObj();
+ ZyppPattern pattern = tryCastToZyppPattern (object);
+ zypp::Pattern::Contents contents (pattern->contents());
+ for (zypp::Pattern::Contents::Selectable_iterator it =
+ contents.selectableBegin(); it != contents.selectableEnd(); it++) {
+ ZyppSelectablePtr sel = get_pointer (*it);
+ m_containsPackages = g_slist_append (m_containsPackages, sel);
+ if (!sel->installedEmpty())
+ m_installedPkgs++;
+ m_totalPkgs++;
+ }
+ break;
+ }
+ case Ypp::Package::PATCH_TYPE: {
+ ZyppObject object = m_sel->theObj();
+ ZyppPatch patch = tryCastToZyppPatch (object);
+ zypp::Patch::Contents contents (patch->contents());
+ for (zypp::Patch::Contents::Selectable_iterator it =
+ contents.selectableBegin(); it != contents.selectableEnd(); it++) {
+ ZyppSelectablePtr sel = get_pointer (*it);
+ m_containsPackages = g_slist_append (m_containsPackages, sel);
+ if (!sel->installedEmpty())
+ m_installedPkgs++;
+ m_totalPkgs++;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ return m_containsPackages;
+ }
+
+ virtual std::string name()
+ {
+ if (type == Ypp::Package::PATTERN_TYPE)
+ return m_sel->theObj()->summary();
+ return m_sel->name();
+ }
+
+ virtual std::string summary()
+ {
+ if (type == Ypp::Package::PATTERN_TYPE) {
+ int installed, total;
+ containsStats (&installed, &total);
+ std::ostringstream stream;
+ stream << _("Installed: ") << installed << _(" of ") << total;
+ return stream.str();
+ }
+ return m_sel->theObj()->summary();
+ }
+
+ virtual std::string description (MarkupType markup)
+ {
+ ZyppObject object = m_sel->theObj();
+ std::string text = object->description(), br = "<br>";
+ if (markup == GTK_MARKUP && type == Ypp::Package::PACKAGE_TYPE) {
+ text += "\n";
+ const Ypp::Package::Version *version;
+ version = getInstalledVersion();
+ if (version)
+ text += std::string ("\n") + _("Installed:") + " " + version->number;
+ version = getAvailableVersion (0);
+ if (version) {
+ text += std::string ("\n") + _("Candidate:") + " " + version->number;
+ text += std::string (" (") + _("from") + " " + version->repo->name + ")";
+ }
+ return text;
+ }
+ if (markup == NO_MARKUP)
+ return text;
+
+ switch (type) {
+ case Ypp::Package::PACKAGE_TYPE:
+ {
+ // if it has this header, then it is HTML
+ const char *header = "<!-- DT:Rich -->", header_len = 16;
+ if (!text.compare (0, header_len, header, header_len))
+ ;
+ else {
+ // cut authors block
+ std::string::size_type i = text.find ("\nAuthors:", 0);
+ if (i == std::string::npos)
+ i = text.find ("\nAuthor:", 0);
+ if (i != std::string::npos)
+ text.erase (i);
+ // cut any lines at the end
+ while (text.length() > 0 && text [text.length()-1] == '\n')
+ text.erase (text.length()-1);
+
+ YGUtils::escapeMarkup (text);
+ YGUtils::replace (text, "\n\n", 2, "<br>"); // break every double line
+ text += br;
+ }
+
+ if (!isInstalled() && (isRecommended() || isSuggested())) {
+ text += "";
+ if (isRecommended())
+ text += _("(As this package is an extension to an already installed package, it is <b>recommended</b> it be installed.)");
+ if (isSuggested())
+ text += _("(As this package complements some installed packages, it is <b>suggested</b> it be installed.)");
+ text += "</font>" + br;
+ }
+
+ // specific
+ ZyppPackage package = tryCastToZyppPkg (object);
+ std::string url = package->url(), license = package->license();
+ if (!url.empty())
+ text += br + "<b>" + _("Website:") + "</b> " + url + "</a>";
+ if (!license.empty())
+ text += br + "<b>" + _("License:") + "</b> " + license;
+#if ZYPP_VERSION >= 5013001
+ text += br + "<b>" + _("Size:") + "</b> " + object->installSize().asString();
+#else
+ text += br + "<b>" + _("Size:") + "</b> " + object->installsize().asString();
+#endif
+
+ bool hasCandidate = m_sel->hasCandidateObj();
+ if (isInstalled()) {
+ text += br + "<b>" + _("Installed at:") + "</b> " + m_sel->installedObj()->installtime().form("%x");
+ if (!hasUpgrade())
+ hasCandidate = false; // only for upgrades
+ if (hasCandidate)
+ text += " ";
+ }
+ else if (hasCandidate)
+ text += br;
+ if (hasCandidate)
+ text += std::string ("<b>") + _("Last build from:") + "</b> " + m_sel->candidateObj()->buildtime().form("%x");
+ break;
+ }
+ case Ypp::Package::PATCH_TYPE:
+ {
+ ZyppPatch patch = tryCastToZyppPatch (object);
+ if (patch->rebootSuggested())
+ text += br + br + "<b>" + _("Reboot needed!") + "</b>";
+ if (patch->referencesBegin() != patch->referencesEnd()) {
+ text += br + br + "<b>Bugzilla:</b><ul>";
+ for (zypp::Patch::ReferenceIterator it = patch->referencesBegin();
+ it != patch->referencesEnd(); it++)
+ text += "<li>" + it.title() + "</a></li>";
+ text += "</ul>";
+ }
+ break;
+ }
+ case Ypp::Package::PATTERN_TYPE:
+ {
+ int installed, total;
+ containsStats (&installed, &total);
+ std::ostringstream stream;
+ stream << "\n\n" << _("Installed: ") << installed << _(" of ") << total;
+ text += stream.str();
+ break;
+ }
+ default:
+ break;
+ }
+ return text;
+ }
+
+ virtual std::string filelist (bool rich)
+ {
+ std::string text;
+ ZyppObject object = m_sel->installedObj();
+ ZyppPackage package = tryCastToZyppPkg (object);
+ if (package) {
+ if (rich) {
+ StringTree tree (strcmp, '/', NULL);
+
+ const std::list std::string &filesList = package->filenames();
+ for (std::list std::string::const_iterator it = filesList.begin();
+ it != filesList.end(); it++)
+ tree.add (*it, "");
+
+ struct inner {
+ static std::string getPath (GNode *node)
+ {
+ Ypp::Node *yNode = (Ypp::Node *) node->data;
+ if (!yNode)
+ return std::string();
+ return getPath (node->parent) + "/" + yNode->name;
+ }
+ static bool hasNextLeaf (GNode *node)
+ {
+ GNode *i;
+ for (i = node->next; i; i = i->next)
+ if (!i->children)
+ return true;
+ return false;
+ }
+ static bool hasPrevLeaf (GNode *node)
+ {
+ GNode *i;
+ for (i = node->prev; i; i = i->prev)
+ if (!i->children)
+ return true;
+ return false;
+ }
+ static gboolean traverse (GNode *node, void *_data)
+ {
+ Ypp::Node *yNode = (Ypp::Node *) node->data;
+ if (yNode) {
+ std::string *str = (std::string *) _data;
+ if (!hasPrevLeaf (node)) {
+ std::string path = getPath (node->parent);
+ *str += "<a href=" + path + ">" + path + "</a>";
+ *str += "<blockquote>";
+ }
+ else
+ *str += ", ";
+ *str += yNode->name;
+
+ if (!hasNextLeaf (node))
+ *str += "</blockquote>";
+ }
+ return FALSE;
+ }
+ };
+ g_node_traverse (tree.root, G_LEVEL_ORDER, G_TRAVERSE_LEAFS, -1,
+ inner::traverse, (void *) &text);
+ }
+ else {
+ const std::list std::string &filesList = package->filenames();
+ for (std::list std::string::const_iterator it = filesList.begin();
+ it != filesList.end(); it++)
+ text += *it + " ";
+ }
+ }
+ return text;
+ }
+
+ virtual std::string changelog()
+ {
+ std::string text;
+ ZyppObject object = m_sel->installedObj();
+ ZyppPackage package = tryCastToZyppPkg (object);
+ if (package) {
+ const std::list zypp::ChangelogEntry &changelogList = package->changelog();
+ for (std::list zypp::ChangelogEntry::const_iterator it = changelogList.begin();
+ it != changelogList.end(); it++) {
+ std::string date (it->date().form ("%d %B %Y")), author (it->author()),
+ changes (it->text());
+ YGUtils::escapeMarkup (author);
+ YGUtils::escapeMarkup (changes);
+ YGUtils::replace (changes, "\n", 1, "<br>");
+ if (author.compare (0, 2, "- ", 2) == 0) // zypp returns a lot of author strings as
+ author.erase (0, 2); // "- author". wtf?
+ text += date + " (" + author + "):<br><blockquote>" + changes + "</blockquote>";
+ }
+ }
+ return text;
+ }
+
+ virtual std::string authors (bool rich)
+ {
+ std::string text;
+ ZyppObject object = m_sel->theObj();
+ ZyppPackage package = tryCastToZyppPkg (object);
+ if (package) {
+ std::string packager = package->packager(), vendor = package->vendor(), authors;
+ YGUtils::escapeMarkup (packager);
+ YGUtils::escapeMarkup (vendor);
+ const std::list std::string &authorsList = package->authors();
+ for (std::list std::string::const_iterator it = authorsList.begin();
+ it != authorsList.end(); it++) {
+ std::string author (*it);
+ if (rich)
+ YGUtils::escapeMarkup (author);
+ if (!authors.empty()) {
+ if (rich)
+ authors += "<br>";
+ else
+ authors += "\n";
+ }
+ authors += author;
+ }
+ // look for Authors line in description
+ std::string description = package->description();
+ std::string::size_type i = description.find ("\nAuthors:\n-----", 0);
+ if (i != std::string::npos) {
+ i += sizeof ("\nAuthors:\n----");
+ i = description.find ("\n", i);
+ if (i != std::string::npos)
+ i++;
+ }
+ else {
+ i = description.find ("\nAuthor:", 0);
+ if (i == std::string::npos) {
+ i = description.find ("\nAuthors:", 0);
+ if (i != std::string::npos)
+ i++;
+ }
+ if (i != std::string::npos)
+ i += sizeof ("\nAuthor:");
+ }
+ if (i != std::string::npos) {
+ std::string str = description.substr (i);
+ if (rich) {
+ YGUtils::escapeMarkup (str);
+ YGUtils::replace (str, "\n", 1, "<br>");
+ }
+ authors += str;
+ }
+ if (rich) {
+ if (!authors.empty())
+ text += _("Developed by:") + ("<blockquote>" + authors) + "</blockquote>";
+ if (!packager.empty() || (!vendor.empty() && !text.empty())) {
+ text += _("Packaged by:");
+ text += "<blockquote>";
+ if (!packager.empty())
+ text += packager;
+ if (!vendor.empty()) {
+ if (!packager.empty())
+ text += "<br>(";
+ text += vendor;
+ if (!packager.empty())
+ text += ")";
+ }
+ text += "</blockquote>";
+ }
+ }
+ else
+ return authors;
+ }
+ return text;
+ }
+
+ virtual std::string support (bool rich)
+ {
+ std::string text;
+#if ZYPP_VERSION >= 5013001
+ ZyppObject object = m_sel->theObj();
+ ZyppPackage package = tryCastToZyppPkg (object);
+ if (package) {
+ zypp::VendorSupportOption opt = package->vendorSupport();
+ text = zypp::asUserString (opt) + ": ";
+ std::string str (zypp::asUserStringDescription (opt));
+ if (rich)
+ YGUtils::escapeMarkup (str);
+ text += str;
+ }
+#endif
+ return text;
+ }
+
+ virtual std::string icon()
+ {
+ if (type == Ypp::Package::PATTERN_TYPE) {
+ ZyppObject object = m_sel->theObj();
+ ZyppPattern pattern = tryCastToZyppPattern (object);
+ std::string icon = pattern->icon().asString().c_str();
+ // from yast2-qt: HACK most patterns have wrong default icon
+ if ((icon == zypp::Pathname("yast-system").asString()) || icon.empty())
+ icon = "pattern-generic";
+ // mine: remove start "./"
+ else if (icon.compare (0, 2, "./", 2) == 0)
+ icon.erase (0, 2);
+ return icon;
+ }
+ return "";
+ }
+
+ virtual bool isRecommended() const
+ {
+ // like yast2-qt: different instances may be assigned different groups
+ if (m_sel->hasCandidateObj())
+ for (int i = 0; i < 2; i++) {
+ ZyppObject obj;
+ if (i == 0)
+ obj = m_sel->candidateObj();
+ else
+ obj = m_sel->installedObj();
+ if (obj && zypp::PoolItem (obj).status().isRecommended())
+ return true;
+ }
+ return false;
+ }
+
+ virtual bool isSuggested() const
+ {
+ if (m_sel->hasCandidateObj())
+ for (int i = 0; i < 2; i++) {
+ ZyppObject obj;
+ if (i == 0)
+ obj = m_sel->candidateObj();
+ else
+ obj = m_sel->installedObj();
+ if (obj && zypp::PoolItem (obj).status().isSuggested())
+ return true;
+ }
+ return false;
+ }
+
+ virtual int buildAge() const
+ {
+ if (m_sel->hasCandidateObj()) {
+ time_t build = static_cast (m_sel->candidateObj()->buildtime());
+ time_t now = time (NULL);
+ return (now - build) / (60*60*24); // in days
+ }
+ return -1;
+ }
+
+ virtual bool isUnsupported() const
+ {
+#if ZYPP_VERSION >= 5013001
+ if (type != Ypp::Package::PACKAGE_TYPE)
+ return false;
+ ZyppObject object = m_sel->theObj();
+ ZyppPackage package = tryCastToZyppPkg (object);
+ return package->maybeUnsupported();
+#else
+ return false;
+#endif
+ }
+
+ virtual std::string provides (bool rich) const
+ {
+ std::string text;
+ ZyppObject object = m_sel->theObj();
+ const zypp::Capabilities &capSet = object->dep (zypp::Dep::PROVIDES);
+ for (zypp::Capabilities::const_iterator it = capSet.begin();
+ it != capSet.end(); it++) {
+ if (!text.empty())
+ text += "\n";
+ text += it->asString();
+ }
+ if (rich)
+ YGUtils::escapeMarkup (text);
+ return text;
+ }
+
+ virtual std::string requires (bool rich) const
+ {
+ std::string text;
+ ZyppObject object = m_sel->theObj();
+ const zypp::Capabilities &capSet = object->dep (zypp::Dep::REQUIRES);
+ for (zypp::Capabilities::const_iterator it = capSet.begin();
+ it != capSet.end(); it++) {
+ if (!text.empty())
+ text += "\n";
+ text += it->asString();
+ }
+ if (rich)
+ YGUtils::escapeMarkup (text);
+ return text;
+ }
+
+ virtual bool containsPackage (const Ypp::Package *package)
+ {
+ PackageSel *sel = (PackageSel *) package->impl;
+ return g_slist_find (getContainedPackages(), get_pointer (sel->m_sel)) != NULL;
+ }
+
+ virtual void containsStats (int *installed, int *total)
+ {
+ getContainedPackages(); // init
+ *installed = m_installedPkgs;
+ *total = m_totalPkgs;
+ }
+
+ virtual Ypp::Node *category()
+ { return m_category; }
+
+ virtual Ypp::Node *category2()
+ { return m_category2; }
+
+ virtual bool isInstalled()
+ {
+ return m_isInstalled;
+ }
+
+ virtual bool hasUpgrade()
+ {
+ return m_hasUpgrade;
+ }
+
+ virtual bool isLocked()
+ {
+ zypp::ui::Status status = m_sel->status();
+ return status == zypp::ui::S_Taboo || status == zypp::ui::S_Protected;
+ }
+
+ virtual bool toInstall (const Ypp::Package::Version **version)
+ {
+ if (version) {
+ ZyppObject candidate = m_sel->candidateObj();
+ for (int i = 0; getAvailableVersion (i); i++) {
+ const Ypp::Package::Version *v = getAvailableVersion (i);
+ ZyppObject obj = (ZyppObjectPtr) v->impl;
+ if (obj == candidate) {
+ *version = v;
+ break;
+ }
+ }
+ }
+ return m_sel->toInstall();
+ }
+
+ virtual bool toRemove()
+ {
+ return m_sel->toDelete();
+ }
+
+ virtual bool toModify()
+ {
+ return m_sel->toModify();
+ }
+
+ virtual bool isAuto()
+ {
+ zypp::ui::Status status = m_sel->status();
+ return status == zypp::ui::S_AutoInstall || status == zypp::ui::S_AutoUpdate ||
+ status == zypp::ui::S_AutoDel;
+ }
+
+ virtual void install (const Ypp::Package::Version *version)
+ {
+ if (isLocked())
+ return;
+ if (!m_sel->hasLicenceConfirmed())
+ {
+ ZyppObject obj = m_sel->candidateObj();
+ const std::string &license = obj->licenseToConfirm();
+ if (!license.empty())
+ if (!ypp->impl->acceptLicense (m_parent, license))
+ return;
+ m_sel->setLicenceConfirmed();
+
+ const std::string &msg = obj->insnotify();
+ if (!msg.empty())
+ ypp->impl->notifyMessage (m_parent, msg);
+ }
+
+ zypp::ui::Status status = m_sel->status();
+ switch (status) {
+ // not applicable
+ case zypp::ui::S_Protected:
+ case zypp::ui::S_Taboo:
+ case zypp::ui::S_Install:
+ case zypp::ui::S_Update:
+ break;
+ // undo
+ case zypp::ui::S_Del:
+ status = zypp::ui::S_KeepInstalled;
+ break;
+ // nothing to do about it
+ case zypp::ui::S_AutoDel:
+ break;
+ // action
+ case zypp::ui::S_NoInst:
+ case zypp::ui::S_AutoInstall:
+ status = zypp::ui::S_Install;
+ break;
+ case zypp::ui::S_KeepInstalled:
+ case zypp::ui::S_AutoUpdate:
+ status = zypp::ui::S_Update;
+ break;
+ }
+
+ m_sel->setStatus (status);
+ if (toInstall (NULL)) {
+ if (!version) {
+ version = getAvailableVersion (0);
+ const Ypp::Repository *repo = ypp->favoriteRepository();
+ if (repo && fromRepository (repo))
+ version = fromRepository (repo);
+ }
+ ZyppObject candidate = (ZyppObjectPtr) version->impl;
+ if (!m_sel->setCandidate (candidate)) {
+ yuiWarning () << "Error: Could not set package '" << name() << "' candidate to '" << version->number << "'\n";
+ return;
+ }
+ }
+ }
+
+ virtual void remove()
+ {
+ if (m_sel->hasCandidateObj()) {
+ const std::string &msg = m_sel->candidateObj()->delnotify();
+ if (!msg.empty())
+ ypp->impl->notifyMessage (m_parent, msg);
+ }
+
+ zypp::ui::Status status = m_sel->status();
+ switch (status) {
+ // not applicable
+ case zypp::ui::S_Protected:
+ case zypp::ui::S_Taboo:
+ case zypp::ui::S_NoInst:
+ case zypp::ui::S_Del:
+ break;
+ // undo
+ case zypp::ui::S_Install:
+ status = zypp::ui::S_NoInst;
+ break;
+ // nothing to do about it
+ case zypp::ui::S_AutoInstall:
+ case zypp::ui::S_AutoUpdate:
+ break;
+ case zypp::ui::S_Update:
+ status = zypp::ui::S_KeepInstalled;
+ break;
+ // action
+ case zypp::ui::S_KeepInstalled:
+ case zypp::ui::S_AutoDel:
+ status = zypp::ui::S_Del;
+ break;
+ }
+
+ m_sel->setStatus (status);
+ }
+
+ virtual void undo()
+ {
+ zypp::ui::Status status = m_sel->status();
+ switch (status) {
+ // not applicable
+ case zypp::ui::S_Protected:
+ case zypp::ui::S_Taboo:
+ case zypp::ui::S_NoInst:
+ case zypp::ui::S_KeepInstalled:
+ break;
+
+ // undo
+ case zypp::ui::S_Install:
+ status = zypp::ui::S_NoInst;
+ break;
+ case zypp::ui::S_Update:
+ case zypp::ui::S_Del:
+ status = zypp::ui::S_KeepInstalled;
+ break;
+
+ // for auto status, undo them by locking them
+ case zypp::ui::S_AutoInstall:
+ status = zypp::ui::S_Taboo;
+ break;
+ case zypp::ui::S_AutoUpdate:
+ case zypp::ui::S_AutoDel:
+ status = zypp::ui::S_Protected;
+ break;
+ }
+
+ m_sel->setStatus (status);
+ }
+
+ virtual bool canLock() { return true; }
+
+ virtual void lock (bool lock)
+ {
+ undo();
+
+ zypp::ui::Status status;
+ if (lock)
+ status = isInstalled() ? zypp::ui::S_Protected : zypp::ui::S_Taboo;
+ else
+ status = isInstalled() ? zypp::ui::S_KeepInstalled : zypp::ui::S_NoInst;
+
+ m_sel->setStatus (status);
+ }
+
+ static Ypp::Package::Version *constructVersion (
+ ZyppObject object, ZyppObject installedObj)
+ {
+ Ypp::Package::Version *version = new Ypp::Package::Version();
+ version->number = object->edition().asString();
+ version->arch = object->arch().asString();
+ version->repo = ypp->impl->getRepository (object->repoInfo().alias());
+ version->cmp = installedObj ? zypp::Edition::compare (object->edition(), installedObj->edition()) : 0;
+ version->impl = (void *) get_pointer (object);
+ return version;
+ }
+
+ virtual const Ypp::Package::Version *getInstalledVersion()
+ {
+ if (!m_installedVersion) {
+ const ZyppObject installedObj = m_sel->installedObj();
+ if (installedObj != NULL)
+ m_installedVersion = constructVersion (installedObj, NULL);
+ else { // patch
+ if (m_sel->candidateObj() && m_sel->candidateObj().isSatisfied())
+ m_installedVersion = constructVersion (m_sel->candidateObj(), NULL);
+ }
+
+ }
+ return m_installedVersion;
+ }
+
+ virtual const Ypp::Package::Version *getAvailableVersion (int nb)
+ {
+ if (!m_availableVersions) {
+ const ZyppObject installedObj = m_sel->installedObj();
+ const ZyppObject candidateObj = m_sel->candidateObj();
+ for (zypp::ui::Selectable::available_iterator it = m_sel->availableBegin();
+ it != m_sel->availableEnd(); it++) {
+ if (candidateObj && (*it)->edition() == candidateObj->edition() &&
+ (*it)->arch() == candidateObj->arch())
+ continue;
+ Ypp::Package::Version *version = constructVersion (*it, installedObj);
+ m_availableVersions = g_slist_append (m_availableVersions, version);
+ }
+ if (candidateObj) { // make sure this goes first
+ Ypp::Package::Version *version = constructVersion (candidateObj, installedObj);
+ m_availableVersions = g_slist_prepend (m_availableVersions, version);
+ }
+#if 0 // let zypp order prevail
+ struct inner {
+ static gint version_compare (gconstpointer pa, gconstpointer pb)
+ {
+ ZyppObjectPtr a = (ZyppObjectPtr) ((Ypp::Package::Version *) pa)->impl;
+ ZyppObjectPtr b = (ZyppObjectPtr) ((Ypp::Package::Version *) pb)->impl;
+ // swapped arguments, as we want them sorted from newer to older
+ return zypp::Edition::compare (b->edition(), a->edition());
+ }
+ };
+ m_availableVersions = g_slist_sort (m_availableVersions, inner::version_compare);
+#endif
+ }
+ return (Ypp::Package::Version *) g_slist_nth_data (m_availableVersions, nb);
+ }
+
+ virtual const Ypp::Package::Version *fromRepository (const Ypp::Repository *repo)
+ {
+ for (int i = 0; getAvailableVersion (i); i++)
+ if (getAvailableVersion (i)->repo == repo)
+ return getAvailableVersion (i);
+ return NULL;
+ }
+};
+
+struct PackageLang : public Ypp::Package::Impl
+{
+zypp::Locale m_locale;
+GSList *m_containsPackages;
+bool m_installed, m_setInstalled;
+int m_installedPkgs, m_totalPkgs;
+
+ PackageLang (Ypp::Package::Type type, const zypp::Locale &zyppLang)
+ : Impl (type), m_locale (zyppLang), m_containsPackages (NULL)
+ {
+ m_installed = m_setInstalled = isSetInstalled();
+ m_installedPkgs = m_totalPkgs = 0;
+ }
+
+ ~PackageLang()
+ {
+ g_slist_free (m_containsPackages);
+ }
+
+ virtual bool isTouched()
+ { return m_setInstalled == isSetInstalled(); }
+ virtual void setNotTouched()
+ { m_setInstalled = isSetInstalled(); }
+
+ virtual std::string name()
+ { return m_locale.name(); }
+
+ virtual std::string summary()
+ {
+ int installed, total;
+ containsStats (&installed, &total);
+ std::ostringstream stream;
+ stream << _("Installed: ") << installed << _(" of ") << total;
+ return stream.str();
+ }
+
+ virtual std::string description (MarkupType markup)
+ {
+ std::string text ("(" + m_locale.code() + ")");
+ int installed, total;
+ containsStats (&installed, &total);
+ std::ostringstream stream;
+ stream << "\n\n" << _("Installed: ") << installed << _(" of ") << total;
+ text += stream.str();
+ return text;
+ }
+
+ GSList *getContainedPackages()
+ {
+ if (!m_containsPackages) {
+ zypp::sat::LocaleSupport myLocale (m_locale);
+ for_( it, myLocale.selectableBegin(), myLocale.selectableEnd() ) {
+ ZyppSelectablePtr sel = get_pointer (*it);
+ m_containsPackages = g_slist_append (m_containsPackages, sel);
+ if (!sel->installedEmpty())
+ m_installedPkgs++;
+ m_totalPkgs++;
+ }
+ }
+ return m_containsPackages;
+ }
+
+ virtual bool containsPackage (const Ypp::Package *package)
+ {
+ PackageSel *sel = (PackageSel *) package->impl;
+ return g_slist_find (getContainedPackages(), get_pointer (sel->m_sel)) != NULL;
+ }
+
+ virtual void containsStats (int *installed, int *total)
+ {
+ getContainedPackages(); // init
+ *installed = m_installedPkgs;
+ *total = m_totalPkgs;
+ }
+
+ virtual std::string icon()
+ {
+ #define ICON_PATH "/usr/share/locale/l10n/"
+ static int hasPath = -1;
+ if (hasPath == -1)
+ hasPath = g_file_test (ICON_PATH, G_FILE_TEST_IS_DIR) ? 1 : 0;
+ if (hasPath) {
+ std::string code (m_locale.code());
+ std::string::size_type i = code.find_last_of ('_');
+ if (i != std::string::npos) {
+ code.erase (0, i+1);
+ // down case country name
+ gchar *str = g_ascii_strdown (code.c_str(), -1);
+ code = str;
+ g_free (str);
+ }
+ std::string filename (ICON_PATH);
+ filename += code + "/flag.png";
+ if (g_file_test (filename.c_str(), G_FILE_TEST_IS_REGULAR))
+ return filename;
+ }
+ return "";
+ }
+
+ bool isSetInstalled()
+ { return zypp::getZYpp()->pool().isRequestedLocale (m_locale); }
+
+ virtual bool isInstalled()
+ { return m_installed; }
+ virtual bool hasUpgrade()
+ { return false; }
+ virtual bool isLocked()
+ { return false; }
+
+ virtual bool toInstall (const Ypp::Package::Version **repo)
+ { return !m_installed && isSetInstalled(); }
+ virtual bool toRemove()
+ { return m_installed && !isSetInstalled(); }
+ virtual bool toModify()
+ { return m_installed != isSetInstalled(); }
+ virtual bool isAuto()
+ { return false; }
+
+ virtual void install (const Ypp::Package::Version *repo)
+ {
+ if (!isSetInstalled())
+ zypp::getZYpp()->pool().addRequestedLocale (m_locale);
+ }
+
+ virtual void remove()
+ {
+ if (isSetInstalled())
+ zypp::getZYpp()->pool().eraseRequestedLocale (m_locale);
+ }
+
+ virtual void undo()
+ {
+ if (isSetInstalled())
+ remove();
+ else if (m_installed)
+ install (0);
+ }
+
+ virtual bool canLock() { return false; }
+ virtual void lock (bool lock) {}
+};
+
+// Packages Factory
+GSList *Ypp::Impl::getPackages (Ypp::Package::Type type)
+{
+ if (!packages[type]) {
+ GSList *pool = NULL;
+ struct inner {
+ static gint compare (gconstpointer _a, gconstpointer _b)
+ {
+ Package *a = (Package *) _a;
+ Package *b = (Package *) _b;
+ return strcasecmp (a->name().c_str(), b->name().c_str());
+ }
+ static gint compare_utf8 (gconstpointer _a, gconstpointer _b)
+ { // slower -- don't use for packages -- only for patterns and languages
+ Package *a = (Package *) _a;
+ Package *b = (Package *) _b;
+ return g_utf8_collate (a->name().c_str(), b->name().c_str());
+ }
+ static gint compare_pattern (gconstpointer a, gconstpointer b)
+ {
+ ZyppPattern pattern1 = tryCastToZyppPattern (((PackageSel *) ((Package *) a)->impl)->m_sel->theObj());
+ ZyppPattern pattern2 = tryCastToZyppPattern (((PackageSel *) ((Package *) b)->impl)->m_sel->theObj());
+ return strcmp (pattern1->order().c_str(), pattern2->order().c_str());
+ }
+ };
+
+ if (type == Package::LANGUAGE_TYPE) {
+ zypp::LocaleSet locales = zypp::getZYpp()->pool().getAvailableLocales();
+ for (zypp::LocaleSet::const_iterator it = locales.begin();
+ it != locales.end(); it++) {
+ Package *package = new Package (new PackageLang (type, *it));
+ pool = g_slist_prepend (pool, package);
+ }
+ }
+ else { // Pool Selectables
+ ZyppPool::const_iterator it, end;
+ switch (type) {
+ case Package::PACKAGE_TYPE:
+ it = zyppPool().byKindBegin zypp::Package();
+ end = zyppPool().byKindEnd zypp::Package();
+
+ // for the categories
+ bindtextdomain ("rpm-groups", LOCALEDIR);
+ bind_textdomain_codeset ("rpm-groups", "utf8");
+ break;
+ case Package::PATTERN_TYPE:
+ it = zyppPool().byKindBegin zypp::Pattern();
+ end = zyppPool().byKindEnd zypp::Pattern();
+ break;
+ case Package::PATCH_TYPE:
+ it = zyppPool().byKindBegin zypp::Patch();
+ end = zyppPool().byKindEnd zypp::Patch();
+ break;
+ default:
+ break;
+ }
+ for (; it != end; it++) {
+ Ypp::Node *category = 0, *category2 = 0;
+ ZyppSelectable sel = *it;
+ ZyppObject object = sel->theObj();
+
+ // don't show if installed broken and there is no available
+ if (!sel->candidateObj()) {
+ if (!sel->installedEmpty() && sel->installedObj().isBroken())
+ continue;
+ }
+
+ // add category and test visibility
+ switch (type) {
+ case Package::PACKAGE_TYPE:
+ {
+ ZyppPackage zpackage = tryCastToZyppPkg (object);
+ if (!zpackage)
+ continue;
+ category = addCategory (type, zpackage->group(), "");
+ category2 = addCategory2 (type, sel);
+ break;
+ }
+ case Package::PATTERN_TYPE:
+ {
+ ZyppPattern pattern = tryCastToZyppPattern (object);
+ if (!pattern || !pattern->userVisible())
+ continue;
+ category = addCategory (type, pattern->category(), pattern->order());
+ break;
+ }
+ case Package::PATCH_TYPE:
+ {
+ ZyppPatch patch = tryCastToZyppPatch (object);
+ if (!patch)
+ continue;
+ if (sel->candidateObj()) {
+ if (!sel->candidateObj().isRelevant())
+ continue;
+ }
+ category = addCategory (type, patch->category(), "");
+ break;
+ }
+ default:
+ break;
+ }
+
+ Package *package = new Package (new PackageSel (type, sel, category, category2));
+ pool = g_slist_prepend (pool, package);
+ }
+ }
+ // its faster to prepend then reverse, as we avoid iterating for each append
+ // lets reverse before sorting, as they are somewhat sorted already
+ pool = g_slist_reverse (pool);
+ // a sort merge. Don't use g_slist_insert_sorted() -- its linear
+ if (type == Ypp::Package::PATTERN_TYPE)
+ pool = g_slist_sort (pool, inner::compare_pattern);
+ else if (type == Ypp::Package::LANGUAGE_TYPE)
+ pool = g_slist_sort (pool, inner::compare_utf8);
+ else
+ pool = g_slist_sort (pool, inner::compare);
+ packages[type] = pool;
+ polishCategories (type);
+ }
+ return packages[type];
+}
+
+//** Query
+
+struct Ypp::QueryPool::Query::Impl
+{
+ template <typename T>
+ struct Key
+ {
+ Key() : defined (false) {}
+ void set (T v)
+ {
+ defined = true;
+ value = v;
+ }
+ bool is (const T &v) const
+ {
+ if (!defined) return true;
+ return value == v;
+ }
+ bool defined;
+ T value;
+ };
+
+ template <typename T>
+ struct Keys
+ {
+ Keys() : defined (false) {}
+ void add (T v)
+ {
+ defined = true;
+ values.push_back (v);
+ }
+ bool is (const T &v) const
+ {
+ if (!defined) return true;
+ typename std::list <T>::const_iterator it;
+ for (it = values.begin(); it != values.end(); it++)
+ if (*it == v)
+ return true;
+ return false;
+ }
+ bool defined;
+ std::list <T> values;
+ };
+
+ Keys Ypp::Package::Type types;
+ Keys std::string names;
+ int use_name : 1, use_summary : 1, use_description : 1, use_filelist : 1,
+ use_authors : 1, full_word_match : 1;
+ Keys categories, categories2;
+ Keys collections;
+ Keys repositories;
+ Key <bool> isInstalled;
+ Key <bool> hasUpgrade;
+ Key <bool> toModify;
+ Key <bool> isRecommended;
+ Key <bool> isSuggested;
+ Key <int> buildAge;
+ Key <bool> isUnsupported;
+ bool clear;
+ Ypp::Package *highlight;
+
+ Impl()
+ {
+ highlight = NULL;
+ clear = false;
+ }
+
+ bool match (Package *package)
+ {
+ struct inner {
+ static bool strstr (const char *str1, const char *str2,
+ bool case_sensitive, bool full_word_match)
+ {
+ const char *i;
+ if (case_sensitive)
+ i = ::strstr (str1, str2);
+ else
+ i = ::strcasestr (str1, str2);
+ if (full_word_match && i) { // check boundries
+ if (i != str1 && isalpha (i[-1]))
+ return false;
+ int len = strlen (str2);
+ if (i [len] && isalpha (i [len]))
+ return false;
+ return true;
+ }
+ return i;
+ }
+ };
+
+ if (clear)
+ return false;
+ bool match = true;
+ if (match && types.defined)
+ match = types.is (package->type());
+ if (match && (isInstalled.defined || hasUpgrade.defined)) {
+ // only one of the specified status must match
+ bool status_match = false;
+ if (isInstalled.defined)
+ status_match = isInstalled.is (package->isInstalled());
+ if (!status_match && hasUpgrade.defined)
+ status_match = hasUpgrade.is (package->hasUpgrade());
+ match = status_match;
+ }
+ if (match && toModify.defined)
+ match = toModify.is (package->toModify());
+ if (match && isRecommended.defined)
+ match = isRecommended.is (package->isRecommended());
+ if (match && isSuggested.defined)
+ match = isSuggested.is (package->isSuggested());
+ if (match && buildAge.defined) {
+ int age = package->buildAge();
+ if (age < 0 || age > buildAge.value)
+ match = false;
+ }
+ if (match && isUnsupported.defined)
+ match = isUnsupported.is (package->isUnsupported());
+ if (match && names.defined) {
+ const std::list std::string &values = names.values;
+ std::list std::string::const_iterator it;
+ for (it = values.begin(); it != values.end(); it++) {
+ const char *key = it->c_str();
+ bool str_match = false;
+ if (use_name)
+ str_match = inner::strstr (package->name().c_str(), key,
+ false, full_word_match);
+ if (!str_match && use_summary)
+ str_match = inner::strstr (package->summary().c_str(), key,
+ false, full_word_match);
+ if (!str_match && use_description)
+ str_match = inner::strstr (package->description (NO_MARKUP).c_str(), key,
+ false, full_word_match);
+ if (!str_match && use_filelist)
+ str_match = inner::strstr (package->filelist (false).c_str(), key,
+ false, full_word_match);
+ if (!str_match && use_authors)
+ str_match = inner::strstr (package->authors (false).c_str(), key,
+ false, full_word_match);
+ if (!str_match) {
+ match = false;
+ break;
+ }
+ }
+ if (match && !highlight && use_name) {
+ if (values.size() == 1 && !strcasecmp (values.front().c_str(), package->name().c_str()))
+ highlight = package;
+ }
+ }
+ if (match && categories.defined) {
+ Ypp::Node *pkg_category = package->category();
+ const std::list &values = categories.values;
+ std::list ::const_iterator it;
+ for (it = values.begin(); it != values.end(); it++) {
+ GNode *node = (GNode *) (*it)->impl;
+ if (g_node_find (node, G_PRE_ORDER, G_TRAVERSE_ALL, pkg_category))
+ break;
+ }
+ match = it != values.end();
+ }
+ if (match && categories2.defined) {
+ Ypp::Node *pkg_category = package->category2();
+ const std::list &values = categories2.values;
+ std::list ::const_iterator it;
+ for (it = values.begin(); it != values.end(); it++) {
+ GNode *node = (GNode *) (*it)->impl;
+ if (g_node_find (node, G_PRE_ORDER, G_TRAVERSE_ALL, pkg_category))
+ break;
+ }
+ match = it != values.end();
+ }
+ if (match && repositories.defined) {
+ const std::list &values = repositories.values;
+ std::list ::const_iterator it;
+ for (it = values.begin(); it != values.end(); it++) {
+ bool match = false;
+ for (int i = 0; package->getAvailableVersion (i); i++) {
+ const Ypp::Package::Version *version = package->getAvailableVersion (i);
+ if (version->repo == *it) {
+ // filter if available isn't upgrade
+ if (package->isInstalled() && hasUpgrade.defined && hasUpgrade.value) {
+ if (version->cmp > 0)
+ match = true;
+ }
+ else
+ match = true;
+ break;
+ }
+ }
+ if (match)
+ break;
+ }
+ match = it != values.end();
+ }
+ if (match && collections.defined) {
+ const std::list &values = collections.values;
+ std::list ::const_iterator it;
+ for (it = values.begin(); it != values.end(); it++)
+ if (package->fromCollection (*it))
+ break;
+ match = it != values.end();
+ }
+ return match;
+ }
+};
+
+Ypp::QueryPool::Query::Query()
+{ impl = new Impl(); }
+Ypp::QueryPool::Query::~Query()
+{ delete impl; }
+
+void Ypp::QueryPool::Query::addType (Ypp::Package::Type value)
+{ impl->types.add (value); }
+void Ypp::QueryPool::Query::addNames (std::string value, char separator, bool use_name,
+ bool use_summary, bool use_description, bool use_filelist, bool use_authors,
+ bool full_word_match)
+{
+ if (separator) {
+ const gchar delimiter[2] = { separator, '\0' };
+ gchar **names = g_strsplit (value.c_str(), delimiter, -1);
+ for (gchar **i = names; *i; i++)
+ impl->names.add (*i);
+ g_strfreev (names);
+ }
+ else
+ impl->names.add (value);
+ impl->use_name = use_name;
+ impl->use_summary = use_summary;
+ impl->use_description = use_description;
+ impl->use_filelist = use_filelist;
+ impl->use_authors = use_authors;
+ impl->full_word_match = full_word_match;
+}
+void Ypp::QueryPool::Query::addCategory (Ypp::Node *value)
+{ impl->categories.add (value); }
+void Ypp::QueryPool::Query::addCategory2 (Ypp::Node *value)
+{ impl->categories2.add (value); }
+void Ypp::QueryPool::Query::addCollection (const Ypp::Package *value)
+{ impl->collections.add (value); }
+void Ypp::QueryPool::Query::addRepository (const Repository *value)
+{ impl->repositories.add (value); }
+void Ypp::QueryPool::Query::setIsInstalled (bool value)
+{ impl->isInstalled.set (value); }
+void Ypp::QueryPool::Query::setHasUpgrade (bool value)
+{ impl->hasUpgrade.set (value); }
+void Ypp::QueryPool::Query::setToModify (bool value)
+{ impl->toModify.set (value); }
+void Ypp::QueryPool::Query::setIsRecommended (bool value)
+{ impl->isRecommended.set (value); }
+void Ypp::QueryPool::Query::setIsSuggested (bool value)
+{ impl->isSuggested.set (value); }
+void Ypp::QueryPool::Query::setBuildAge (int value)
+{ impl->buildAge.set (value); }
+void Ypp::QueryPool::Query::setIsUnsupported (bool value)
+{ impl->isUnsupported.set (value); }
+void Ypp::QueryPool::Query::setClear()
+{ impl->clear = true; }
+
+//** Pool
+
+struct Ypp::Pool::Impl : public Ypp::PkgListener
+{
+Pool::Listener *listener;
+
+ Impl() : listener (NULL)
+ { ypp->addPkgListener (this); }
+ virtual ~Impl()
+ { ypp->removePkgListener (this); }
+
+ virtual bool matches (Package *package) = 0;
+
+ virtual Iter find (Package *package) = 0;
+ virtual Iter insert (Package *package) = 0;
+ virtual void remove (Iter iter, Package *package) = 0;
+
+ virtual void packageModified (Package *package)
+ {
+ bool match = matches (package);
+ Iter iter = find (package);
+ if (iter) { // is on the pool
+ if (match) { // modified
+ if (listener)
+ listener->entryChanged (iter, package);
+ }
+ else { // removed
+ if (listener)
+ listener->entryDeleted (iter, package);
+ remove (iter, package);
+ }
+ }
+ else { // not on pool
+ if (match) { // inserted
+ iter = insert (package);
+ if (listener)
+ listener->entryInserted (iter, package);
+ }
+ }
+ }
+};
+
+Ypp::Pool::Pool (Ypp::Pool::Impl *impl)
+: impl (impl)
+{}
+Ypp::Pool::~Pool()
+{ delete impl; }
+
+void Ypp::Pool::setListener (Ypp::Pool::Listener *listener)
+{ impl->listener = listener; }
+
+int Ypp::Pool::size()
+{
+ int size = 0;
+ for (Iter iter = getFirst(); iter; iter = getNext (iter))
+ size++;
+ return size;
+}
+
+Ypp::Pool::Iter Ypp::Pool::fromPath (const Ypp::Pool::Path &path)
+{
+ Iter iter = 0;
+ for (Path::const_iterator it = path.begin(); it != path.end(); it++) {
+ if (iter == NULL)
+ iter = getFirst();
+ else
+ iter = getChild (iter);
+ int row = *it;
+ for (int r = 0; r < row; r++)
+ iter = getNext (iter);
+ }
+ return iter;
+}
+
+Ypp::Pool::Path Ypp::Pool::toPath (Ypp::Pool::Iter iter)
+{
+ Path path;
+ Iter parent, sibling;
+ bool done = false;
+ while (!done) {
+ parent = getParent (iter);
+ if (parent)
+ sibling = getChild (parent);
+ else {
+ sibling = getFirst();
+ done = true;
+ }
+ int row = 0;
+ for (; sibling != iter; sibling = getNext (sibling))
+ row++;
+ path.push_front (row);
+ iter = parent;
+ }
+ return path;
+}
+
+//** QueryPool
+
+struct Ypp::QueryPool::Impl : public Ypp::Pool::Impl
+{
+Query *query;
+GSList *packages;
+
+ Impl (Query *query, bool startEmpty)
+ : Pool::Impl(), query (query), packages (NULL)
+ {
+ if (!startEmpty)
+ packages = buildPool (query);
+ }
+ virtual ~Impl()
+ {
+ delete query;
+ g_slist_free (packages);
+ }
+
+ virtual bool matches (Package *package)
+ {
+ return query->impl->match (package);
+ }
+
+ virtual Iter find (Package *package)
+ {
+ GSList *i;
+ for (i = packages; i; i = i->next) {
+ if (package == i->data)
+ break;
+ }
+ return (Iter) i;
+ }
+
+ virtual Iter insert (Package *package)
+ {
+ packages = g_slist_append (packages, (gpointer) package);
+ Iter iter = (Iter) g_slist_last (packages);
+ return iter;
+ }
+
+ virtual void remove (Iter iter, Package *package)
+ {
+ packages = g_slist_delete_link (packages, (GSList *) iter);
+ }
+
+private:
+ static GSList *buildPool (Query *query) // at construction
+ {
+ GSList *pool = NULL;
+ for (int t = 0; t < Ypp::Package::TOTAL_TYPES; t++) {
+ if (!query->impl->types.is ((Ypp::Package::Type) t))
+ continue;
+ if (!query->impl->types.defined && t != Ypp::Package::PACKAGE_TYPE)
+ continue;
+ GSList *entire_pool = ypp->impl->getPackages ((Ypp::Package::Type) t);
+ for (GSList *i = entire_pool; i; i = i->next) {
+ Package *pkg = (Package *) i->data;
+ if (query->impl->match (pkg))
+ pool = g_slist_append (pool, i->data);
+ }
+ }
+ return pool;
+ }
+};
+
+Ypp::QueryPool::QueryPool (Query *query, bool startEmpty)
+: Ypp::Pool ((impl = new Ypp::QueryPool::Impl (query, startEmpty)))
+{}
+
+Ypp::Pool::Iter Ypp::QueryPool::getFirst()
+{ return impl->packages; }
+
+Ypp::Pool::Iter Ypp::QueryPool::getNext (Ypp::Pool::Iter iter)
+{ return ((GSList *) iter)->next; }
+
+Ypp::Package *Ypp::QueryPool::get (Ypp::Pool::Iter iter)
+{ return (Ypp::Package *) ((GSList *) iter)->data; }
+
+bool Ypp::QueryPool::highlight (Ypp::Pool::Iter iter)
+{ return impl->query->impl->highlight == get (iter); }
+
+//** TreePool
+
+struct Ypp::TreePool::Impl : public Ypp::Pool::Impl
+{
+Package::Type type;
+GNode *root;
+
+ Impl (Package::Type type)
+ : Pool::Impl(), type (type)
+ {
+ root = g_node_new (NULL);
+ buildPool (root);
+ }
+ virtual ~Impl()
+ {
+ g_node_destroy (root);
+ }
+
+ virtual bool matches (Package *package)
+ {
+ return package->type() == type;
+ }
+
+ virtual Iter find (Package *package)
+ {
+ return (Iter) g_node_find (root, G_PRE_ORDER, G_TRAVERSE_LEAVES, package);
+ }
+
+ virtual Iter insert (Package *package) { return 0; }
+ virtual void remove (Iter iter, Package *package) {}
+
+private:
+ void buildPool (GNode *root) // at construction
+ {
+ GSList *packages = ypp->impl->getPackages (type);
+ Ypp::Node *node = NULL; // null for first round
+ GNode *cat = root;
+ do {
+ for (GSList *p = packages; p; p = p->next) {
+ Ypp::Package *pkg = (Ypp::Package *) p->data;
+ if (pkg->category() == node)
+ g_node_append_data (cat, pkg);
+ }
+ if (node)
+ node = node->next();
+ else
+ node = ypp->getFirstCategory (type);
+ if (node)
+ cat = g_node_append_data (root, node);
+ } while (node);
+ }
+};
+
+Ypp::TreePool::TreePool (Ypp::Package::Type type)
+: Ypp::Pool ((impl = new Ypp::TreePool::Impl (type)))
+{}
+
+Ypp::Pool::Iter Ypp::TreePool::getFirst()
+{ return impl->root->children; }
+
+Ypp::Pool::Iter Ypp::TreePool::getNext (Ypp::Pool::Iter iter)
+{ return ((GNode *) iter)->next; }
+
+Ypp::Pool::Iter Ypp::TreePool::getParent (Ypp::Pool::Iter iter)
+{
+ GNode *parent = ((GNode *) iter)->parent;
+ if (parent == impl->root)
+ return NULL;
+ return parent;
+}
+
+Ypp::Pool::Iter Ypp::TreePool::getChild (Ypp::Pool::Iter iter)
+{ return ((GNode *) iter)->children; }
+
+Ypp::Package *Ypp::TreePool::get (Ypp::Pool::Iter iter)
+{
+ GNode *node = (GNode *) iter;
+ return node->children ? NULL : (Ypp::Package *) node->data;
+}
+
+std::string Ypp::TreePool::getName (Ypp::Pool::Iter iter)
+{
+ Ypp::Package *package = get (iter);
+ if (package)
+ return package->name();
+ return ((Ypp::Node *) ((GNode *) iter)->data)->name;
+}
+
+//** Misc
+
+struct Ypp::Disk::Impl
+{
+Ypp::Disk::Listener *listener;
+GSList *partitions;
+
+ Impl()
+ : partitions (NULL)
+ {
+ if (zypp::getZYpp()->diskUsage().empty())
+ zypp::getZYpp()->setPartitions (
+ zypp::DiskUsageCounter::detectMountPoints());
+ }
+
+ ~Impl()
+ {
+ clearPartitions();
+ }
+
+ void packageModified()
+ {
+ clearPartitions();
+ if (listener)
+ listener->update();
+ }
+
+ void clearPartitions()
+ {
+ for (GSList *i = partitions; i; i = i->next)
+ delete ((Partition *) i->data);
+ g_slist_free (partitions);
+ partitions = NULL;
+ }
+
+ const Partition *getPartition (int nb)
+ {
+ if (!partitions) {
+ typedef zypp::DiskUsageCounter::MountPoint ZyppDu;
+ typedef zypp::DiskUsageCounter::MountPointSet ZyppDuSet;
+ typedef zypp::DiskUsageCounter::MountPointSet::iterator ZyppDuSetIterator;
+
+ ZyppDuSet diskUsage = zypp::getZYpp()->diskUsage();
+ for (ZyppDuSetIterator it = diskUsage.begin(); it != diskUsage.end(); it++) {
+ const ZyppDu &point = *it;
+ if (!point.readonly) {
+ // partition fields: dir, used_size, total_size (size on Kb)
+ Ypp::Disk::Partition *partition = new Partition();
+ partition->path = point.dir;
+ partition->used = point.pkg_size;
+ partition->delta = point.pkg_size - point.used_size;
+ partition->total = point.total_size;
+ partition->used_str =
+ zypp::ByteCount (partition->used, zypp::ByteCount::K).asString() + "B";
+ partition->delta_str =
+ zypp::ByteCount (partition->delta, zypp::ByteCount::K).asString() + "B";
+ partition->total_str =
+ zypp::ByteCount (partition->total, zypp::ByteCount::K).asString() + "B";
+ partitions = g_slist_append (partitions, (gpointer) partition);
+ }
+ }
+ }
+ return (Partition *) g_slist_nth_data (partitions, nb);
+ }
+};
+
+Ypp::Disk::Disk()
+{ impl = new Impl(); }
+Ypp::Disk::~Disk()
+{ delete impl; }
+
+void Ypp::Disk::setListener (Ypp::Disk::Listener *listener)
+{ impl->listener = listener; }
+
+const Ypp::Disk::Partition *Ypp::Disk::getPartition (int nb)
+{ return impl->getPartition (nb); }
+
+Ypp::Package *Ypp::findPackage (Ypp::Package::Type type, const std::string &name)
+{
+ GSList *pool = ypp->impl->getPackages (type);
+ for (GSList *i = pool; i; i = i->next) {
+ Package *pkg = (Package *) i->data;
+ if (pkg->name() == name)
+ return pkg;
+ }
+ return NULL;
+}
+
+Ypp::Node *Ypp::getFirstCategory (Ypp::Package::Type type)
+{
+ impl->getPackages (type);
+ if (impl->categories[type] != 0)
+ return impl->categories[type]->getFirst();
+ return NULL;
+}
+
+Ypp::Node *Ypp::getFirstCategory2 (Ypp::Package::Type type)
+{
+ impl->getPackages (type);
+ return impl->categories2->getFirst();
+}
+
+Ypp::Node *Ypp::Node::next()
+{
+ GNode *ret = ((GNode *) impl)->next;
+ if (ret) return (Ypp::Node *) ret->data;
+ return NULL;
+}
+
+Ypp::Node *Ypp::Node::child()
+{
+ GNode *ret = ((GNode *) impl)->children;
+ if (ret) return (Ypp::Node *) ret->data;
+ return NULL;
+}
+
+Ypp::Node *Ypp::Impl::addCategory (Ypp::Package::Type type, const std::string &category_str, const std::string &order)
+{
+ struct inner {
+ static int cmp (const char *a, const char *b)
+ {
+ // Other group should always go as last
+ if (!strcmp (a, _("Other")))
+ return !strcmp (b, _("Other")) ? 0 : 1;
+ if (!strcmp (b, _("Other")))
+ return -1;
+ return strcasecmp (a, b);
+// return g_utf8_collate (a, b); // slow?
+ }
+ };
+
+ std::string category = category_str;
+ if (type == Package::PATCH_TYPE) {
+ if (category_str == "security")
+ category = _("Security");
+ else if (category_str == "recommended")
+ category = _("Recommended");
+ else if (category_str == "optional")
+ category = _("Optional");
+ else if (category_str == "yast")
+ category = "YaST";
+ else if (category_str == "document")
+ category = _("Documentation");
+ }
+
+ if (!categories[type]) {
+ const char *trans_domain = 0;
+ if (type == Package::PACKAGE_TYPE)
+ trans_domain = "rpm-groups";
+ categories[type] = new StringTree (inner::cmp, '/', trans_domain);
+ }
+ return categories[type]->add (category, order);
+}
+
+Ypp::Node *Ypp::Impl::addCategory2 (Ypp::Package::Type type, ZyppSelectable sel)
+{
+ struct inner {
+ static int cmp (const char *a, const char *b)
+ {
+ int r = g_utf8_collate (a, b);
+ if (r != 0) {
+ const char *unknown = zypp_tag_group_enum_to_localised_text
+ (PK_GROUP_ENUM_UNKNOWN);
+ if (!strcmp (a, unknown))
+ return 1;
+ if (!strcmp (b, unknown))
+ return -1;
+ }
+ return r;
+ }
+ };
+
+ // different instances may be assigned different groups
+ YPkgGroupEnum group = PK_GROUP_ENUM_UNKNOWN;
+ for (int i = 0; i < 2; i++) {
+ ZyppObject obj;
+ if (i == 0)
+ obj = sel->candidateObj();
+ else
+ obj = sel->installedObj();
+ ZyppPackage pkg = tryCastToZyppPkg (obj);
+ if (pkg) {
+ group = zypp_tag_convert (pkg->group());
+ if (group != PK_GROUP_ENUM_UNKNOWN)
+ break;
+ }
+ }
+ const char *group_name = zypp_tag_group_enum_to_localised_text (group);
+ const char *group_icon = zypp_tag_enum_to_icon (group);
+
+ if (!categories2)
+ categories2 = new StringTree (inner::cmp, '/', NULL);
+ Ypp::Node *node = categories2->add (group_name, "");
+ node->icon = group_icon;
+ return node;
+}
+
+void Ypp::Impl::polishCategories (Ypp::Package::Type type)
+{
+ // some treatment on categories
+ // Packages must be on leaves. If not, create a "Other" leaf, and put it there.
+ if (type == Package::PACKAGE_TYPE) {
+ GSList *pool = ypp->impl->getPackages (type);
+ for (GSList *i = pool; i; i = i->next) {
+ Package *pkg = (Package *) i->data;
+ PackageSel *sel = (PackageSel *) pkg->impl;
+ Ypp::Node *ynode = pkg->category();
+ if (ynode->child()) {
+ GNode *node = (GNode *) ynode->impl;
+ GNode *last = g_node_last_child (node);
+ if (((Ypp::Node *) last->data)->name == _("Other"))
+ sel->m_category = (Ypp::Node *) last->data;
+ else {
+ // must create a "Other" node
+ Ypp::Node *yN = new Ypp::Node();
+ GNode *n = g_node_new ((void *) yN);
+ yN->name = _("Other");
+ yN->icon = NULL;
+ yN->impl = (void *) n;
+ g_node_insert_before (node, NULL, n);
+ sel->m_category = yN;
+ }
+ }
+ }
+ }
+}
+
+//** Ypp top methods & internal connections
+
+Ypp::Impl::Impl()
+: repos (NULL), favoriteRepo (NULL), disk (NULL), interface (NULL),
+ pkg_listeners (NULL), inTransaction (false), transactions (NULL)
+{
+ for (int i = 0; i < Package::TOTAL_TYPES; i++) {
+ packages[i] = NULL;
+ categories[i] = NULL;
+ categories2 = NULL;
+ }
+}
+
+Ypp::Impl::~Impl()
+{
+ struct inner {
+ static void free_package (void *data, void *_data)
+ { delete ((Package *) data); }
+ static void free_repo (void *data, void *_data)
+ { delete ((Repository *) data); }
+ };
+
+ for (int t = 0; t < Package::TOTAL_TYPES; t++) {
+ g_slist_foreach (packages[t], inner::free_package, NULL);
+ g_slist_free (packages[t]);
+ delete categories[t];
+ }
+ delete categories2;
+
+ g_slist_foreach (repos, inner::free_repo, NULL);
+ g_slist_free (repos);
+
+ // don't delete pools as they don't actually belong to Ypp, just listeners
+ g_slist_free (pkg_listeners);
+ delete disk;
+}
+
+const Ypp::Repository *Ypp::Impl::getRepository (int nb)
+{
+ if (!repos) {
+ struct inner {
+ static void addRepo (Ypp::Impl *impl, const zypp::RepoInfo &info)
+ {
+ Repository *repo = new Repository();
+ repo->name = info.name();
+ if (!info.baseUrlsEmpty())
+ repo->url = info.baseUrlsBegin()->asString();
+ repo->alias = info.alias();
+ repo->enabled = info.enabled();
+ impl->repos = g_slist_append (impl->repos, repo);
+ }
+ };
+ for (zypp::ResPoolProxy::repository_iterator it = zyppPool().knownRepositoriesBegin();
+ it != zyppPool().knownRepositoriesEnd(); it++) {
+ const zypp::Repository &zrepo = *it;
+ if (zrepo.isSystemRepo())
+ continue;
+ inner::addRepo (this, zrepo.info());
+ }
+ // zyppPool::knownRepositories is more accurate, but it doesn't feature disabled
+ // repositories. Add them with the following API.
+ zypp::RepoManager manager;
+ std::list zypp::RepoInfo known_repos = manager.knownRepositories();
+ for (std::list zypp::RepoInfo::const_iterator it = known_repos.begin();
+ it != known_repos.end(); it++) {
+ const zypp::RepoInfo info = *it;
+ if (info.enabled())
+ continue;
+ inner::addRepo (this, info);
+ }
+ }
+ return (Repository *) g_slist_nth_data (repos, nb);
+}
+
+const Ypp::Repository *Ypp::Impl::getRepository (const std::string &alias)
+{
+ for (int i = 0; getRepository (i); i++)
+ if (getRepository (i)->alias == alias)
+ return getRepository (i);
+ return NULL; /*error*/
+}
+
+zypp::RepoInfo Ypp::Impl::getRepoInfo (const Repository *repo)
+{
+ zypp::RepoManager manager;
+ std::list zypp::RepoInfo zrepos = manager.knownRepositories();
+ for (std::list zypp::RepoInfo::const_iterator it = zrepos.begin();
+ it != zrepos.end(); it++)
+ if (repo->alias == it->alias())
+ return *it;
+ // error
+ zypp::RepoInfo i;
+ return i;
+}
+
+Ypp::Disk *Ypp::Impl::getDisk()
+{
+ if (!disk)
+ disk = new Disk();
+ return disk;
+}
+
+bool Ypp::Impl::acceptLicense (Ypp::Package *package, const std::string &license)
+{
+ if (interface)
+ return interface->acceptLicense (package, license);
+ return true;
+}
+
+void Ypp::Impl::notifyMessage (Ypp::Package *package, const std::string &message)
+{
+ if (interface)
+ interface->notifyMessage (package, message);
+}
+
+Ypp::Problem::Solution *Ypp::Problem::getSolution (int nb)
+{
+ return (Ypp::Problem::Solution *) g_slist_nth_data ((GSList *) impl, nb);
+}
+
+bool Ypp::Impl::resolveProblems()
+{
+ zypp::Resolver_Ptr zResolver = zypp::getZYpp()->resolver();
+ bool resolved = false;
+ while (true) {
+ if (zResolver->resolvePool()) {
+ resolved = true;
+ break;
+ }
+ zypp::ResolverProblemList zProblems = zResolver->problems();
+ if ((resolved = zProblems.empty()))
+ break;
+ if (!interface)
+ break;
+
+ std::list problems;
+ for (zypp::ResolverProblemList::iterator it = zProblems.begin();
+ it != zProblems.end(); it++) {
+ Problem *problem = new Problem();
+ problem->description = (*it)->description();
+ problem->details = (*it)->details();
+ GSList *solutions = NULL;
+ zypp::ProblemSolutionList zSolutions = (*it)->solutions();
+ for (zypp::ProblemSolutionList::iterator jt = zSolutions.begin();
+ jt != zSolutions.end(); jt++) {
+ Problem::Solution *solution = new Problem::Solution();
+ solution->description = (*jt)->description();
+ solution->details = (*jt)->details();
+ solution->apply = false;
+ solution->impl = (void *) get_pointer (*jt);
+ solutions = g_slist_append (solutions, solution);
+ }
+ problem->impl = (void *) solutions;
+ problems.push_back (problem);
+ }
+
+ resolved = interface->resolveProblems (problems);
+
+ if (resolved) {
+ zypp::ProblemSolutionList choices;
+ for (std::list ::iterator it = problems.begin();
+ it != problems.end(); it++) {
+ for (int i = 0; (*it)->getSolution (i); i++) {
+ Problem::Solution *solution = (*it)->getSolution (i);
+ if (resolved && solution->apply)
+ choices.push_back ((zypp::ProblemSolution *) solution->impl);
+ delete solution;
+ }
+ delete *it;
+ }
+
+ zResolver->applySolutions (choices);
+ }
+ else
+ break;
+ }
+
+ if (!resolved)
+ zResolver->undo();
+ return resolved;
+}
+
+void Ypp::Impl::packageModified (Ypp::Package *package)
+{
+ if (!g_slist_find (transactions, package)) /* could be a result of undo */
+ transactions = g_slist_append (transactions, package);
+ if (!inTransaction)
+ finishTransactions();
+}
+
+void Ypp::Impl::startTransactions()
+{
+ inTransaction = true;
+}
+
+void Ypp::Impl::finishTransactions()
+{
+ inTransaction = true;
+ bool cancel = (resolveProblems() == false);
+ // check if any package was modified from a restricted repo
+ if (!cancel && ypp->favoriteRepository()) {
+ const Repository *repo = ypp->favoriteRepository();
+ std::list > confirmPkgs;
+ for (GSList *p = packages [Ypp::Package::PACKAGE_TYPE]; p; p = p->next) {
+ Ypp::Package *pkg = (Ypp::Package *) p->data;
+ if (pkg->impl->isTouched()) {
+ const Ypp::Package::Version *version = 0;
+ if (pkg->toInstall (&version)) {
+ if (version->repo != repo) {
+ std::pair p (pkg, version->repo);
+ confirmPkgs.push_back (p);
+ }
+ }
+ }
+ }
+ if (!confirmPkgs.empty())
+ cancel = (interface->allowRestrictedRepo (confirmPkgs) == false);
+ }
+
+ if (cancel) {
+ // user canceled resolver -- undo all
+ for (GSList *i = transactions; i; i = i->next)
+ ((Ypp::Package *) i->data)->undo();
+ }
+ else {
+ // resolver won't tell us what changed -- tell pools about Auto packages
+ // notify pools by the following order: 1st user selected, then autos (dependencies)
+ for (int order = 0; order < 2; order++)
+ for (int type = 0; type < Ypp::Package::TOTAL_TYPES; type++) {
+ for (GSList *p = packages [type]; p; p = p->next) {
+ Ypp::Package *pkg = (Ypp::Package *) p->data;
+ if (pkg->impl->isTouched()) {
+ bool isAuto = pkg->isAuto();
+ if ((order == 0 && !isAuto) || (order == 1 && isAuto)) {
+ for (GSList *i = pkg_listeners; i; i = i->next)
+ ((PkgListener *) i->data)->packageModified (pkg);
+ pkg->impl->setNotTouched();
+ }
+ }
+ }
+ }
+ }
+ g_slist_free (transactions);
+ transactions = NULL;
+ inTransaction = false;
+
+ if (disk)
+ disk->impl->packageModified();
+}
+
+Ypp::Ypp()
+{
+ impl = new Impl();
+
+ zyppPool().saveState();
+ zyppPool().saveState();
+ zyppPool().saveState();
+}
+
+Ypp::~Ypp()
+{
+ setFavoriteRepository (NULL);
+ delete impl;
+}
+
+const Ypp::Repository *Ypp::getRepository (int nb)
+{ return impl->getRepository (nb); }
+
+void Ypp::setFavoriteRepository (const Ypp::Repository *repo)
+{
+ if (impl->favoriteRepo) {
+ zypp::RepoInfo info = impl->getRepoInfo (impl->favoriteRepo);
+ info.setPriority (impl->favoriteRepoPriority);
+ }
+
+ impl->favoriteRepo = repo;
+
+ if (repo) {
+ zypp::RepoInfo info = impl->getRepoInfo (repo);
+ impl->favoriteRepoPriority = info.priority();
+ info.setPriority (1);
+ }
+}
+
+const Ypp::Repository *Ypp::favoriteRepository()
+{ return impl->favoriteRepo; }
+
+Ypp::Disk *Ypp::getDisk()
+{ return impl->getDisk(); }
+
+void Ypp::setInterface (Ypp::Interface *interface)
+{
+ impl->interface = interface;
+ // run the solver at start to check for problems
+ impl->resolveProblems();
+}
+
+void Ypp::addPkgListener (PkgListener *listener)
+{ impl->pkg_listeners = g_slist_append (impl->pkg_listeners, listener); }
+void Ypp::removePkgListener (PkgListener *listener)
+{ impl->pkg_listeners = g_slist_remove (impl->pkg_listeners, listener); }
+
+bool Ypp::isModified()
+{
+ return zyppPool().diffState() ||
+ zyppPool().diffState() ||
+ zyppPool().diffState();
+}
+
+void Ypp::startTransactions()
+{ impl->startTransactions(); }
+
+void Ypp::finishTransactions()
+{ impl->finishTransactions(); }
+
+#include <fstream>
+#include
+
+bool Ypp::importList (const char *filename)
+{
+ bool ret = true;
+ startTransactions();
+ try {
+ std::ifstream importFile (filename);
+ zypp::syscontent::Reader reader (importFile);
+
+ for (zypp::syscontent::Reader::const_iterator it = reader.begin();
+ it != reader.end(); it++) {
+ std::string kind = it->kind(), name = it->name();
+
+ Package::Type type = Ypp::Package::PACKAGE_TYPE;
+// if (kind == "package")
+ if (kind == "pattern")
+ type = Ypp::Package::PATTERN_TYPE;
+
+ Ypp::Package *pkg = findPackage (type, name);
+ if (pkg && !pkg->isInstalled())
+ pkg->install (0);
+ }
+ }
+ catch (const zypp::Exception &exception) {
+ ret = false;
+ }
+ finishTransactions();
+ return ret;
+}
+
+bool Ypp::exportList (const char *filename)
+{
+ bool ret = true;
+ zypp::syscontent::Writer writer;
+ const zypp::ResPool &pool = zypp::getZYpp()->pool();
+
+ // from yast-qt:
+ for_each (pool.begin(), pool.end(),
+ boost::bind (&zypp::syscontent::Writer::addIf, boost::ref (writer), _1));
+
+ try {
+ std::ofstream exportFile (filename);
+ exportFile.exceptions (std::ios_base::badbit | std::ios_base::failbit);
+ exportFile << writer;
+
+ yuiMilestone() << "Package list exported to " << filename << endl;
+ }
+ catch (std::exception &exception) {
+ ret = false;
+ }
+ return ret;
+}
+
+bool Ypp::createSolverTestcase (const char *dirname)
+{
+ bool success;
+ yuiMilestone() << "Generating solver test case START" << endl;
+ success = zypp::getZYpp()->resolver()->createSolverTestcase (dirname);
+ yuiMilestone() << "Generating solver test case END" << endl;
+ return success;
+}
+
Added: trunk/gtk-pkg/src/yzyppwrapper.h
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk-pkg/src/yzyppwrapper.h?rev=57423&view=auto
==============================================================================
--- trunk/gtk-pkg/src/yzyppwrapper.h (added)
+++ trunk/gtk-pkg/src/yzyppwrapper.h Thu Jun 4 12:11:35 2009
@@ -0,0 +1,290 @@
+/********************************************************************
+ * YaST2-GTK - http://en.opensuse.org/YaST2-GTK *
+ ********************************************************************/
+
+/* A simplification of libzypp's API.
+
+ To get a list of packages, setup a Query object and create a Pool with
+ it. Package has a set of manipulation methods, the results of which are
+ then reported to Pool listeners, which you can choose to act on your
+ interface, if you want them reflected on the viewer.
+ Iterate the pool using Pool::Iter. If you want to keep references to them
+ around for the UI, you probably want to look at paths.
+
+ You must register an object that implements Interface, as some transactions
+ are bound by user decisions. Ypp is a singleton; first call to get() will
+ initialize it; you should call finish() when you're done to de-allocate
+ caches.
+ The only thing you should free is Pool objects. A Query will be freed by
+ the Pool object you pass it to.
+*/
+
+#ifndef ZYPP_WRAPPER_H
+#define ZYPP_WRAPPER_H
+
+#include <string>
+#include <list>
+
+enum MarkupType {
+ HTML_MARKUP, GTK_MARKUP, NO_MARKUP
+};
+
+struct Ypp
+{
+ struct Repository;
+
+ // Utilities
+ struct Node {
+ std::string name, order;
+ const char *icon;
+ Node *next();
+ Node *child();
+ void *impl;
+ };
+
+ // Entries
+ struct Package {
+ enum Type {
+ PACKAGE_TYPE, PATTERN_TYPE, LANGUAGE_TYPE, PATCH_TYPE, TOTAL_TYPES
+ };
+
+ Type type() const;
+ const std::string &name() const;
+ const std::string &summary();
+ Node *category();
+ Node *category2();
+ bool containsPackage (const Ypp::Package *package) const;
+ bool fromCollection (const Ypp::Package *collection) const
+ { return collection->containsPackage (this); }
+ void containsStats (int *installed, int *total) const;
+
+ std::string description (MarkupType markup);
+ std::string filelist (bool rich);
+ std::string changelog();
+ std::string authors (bool rich);
+ std::string support (bool rich);
+ std::string icon();
+ bool isRecommended() const;
+ bool isSuggested() const;
+ int buildAge() const; // if < 0 , unsupported or error
+ bool isUnsupported() const;
+
+ std::string provides (bool rich) const;
+ std::string requires (bool rich) const;
+
+ struct Version {
+ std::string number, arch;
+ const Repository *repo;
+ int cmp /* relatively to installed -- ignore if not installed */;
+ void *impl;
+ };
+ const Version *getInstalledVersion();
+ const Version *getAvailableVersion (int nb);
+ // convenience -- null if not:
+ const Version *fromRepository (const Repository *repo);
+
+ bool isInstalled();
+ bool hasUpgrade();
+ bool isLocked();
+
+ bool toInstall (const Version **repo = 0);
+ bool toRemove();
+ bool toModify();
+ bool isAuto(); /* installing/removing cause of dependency */
+
+ void install (const Version *version); // if installed, will re-install
+ // null for most recent version
+ void remove();
+ void undo();
+ bool canLock();
+ void lock (bool lock);
+
+ struct Impl;
+ Impl *impl;
+ Package (Impl *impl);
+ ~Package();
+ };
+
+ // when installing/removing/... a few packages at a time, you should use this methods,
+ // so that problem resolver gets only kicked after they are all queued
+ void startTransactions();
+ void finishTransactions();
+
+ // Pool
+ struct Pool {
+ typedef void * Iter;
+ virtual Iter getFirst() = 0;
+ virtual Iter getNext (Iter it) = 0;
+ virtual Iter getParent (Iter it) = 0;
+ virtual Iter getChild (Iter it) = 0;
+ virtual bool isPlainList() const = 0;
+ bool empty() { return !getFirst(); }
+ int size();
+
+ typedef std::list <int> Path;
+ Iter fromPath (const Path &path);
+ Path toPath (Iter it);
+
+ virtual std::string getName (Iter it) = 0;
+ virtual Package *get (Iter it) = 0; /* may be NULL */
+ virtual bool highlight (Iter it) = 0;
+
+ struct Listener {
+ virtual void entryInserted (Iter iter, Package *package) = 0;
+ virtual void entryDeleted (Iter iter, Package *package) = 0;
+ virtual void entryChanged (Iter iter, Package *package) = 0;
+ };
+ void setListener (Listener *listener);
+
+ struct Impl;
+ Impl *impl;
+ Pool (Impl *impl);
+ virtual ~Pool();
+ };
+
+ // plain listing of packages as filtered
+ // this is a live pool -- entries can be inserted and removed
+ struct QueryPool : public Pool {
+ struct Query {
+ Query();
+ void addType (Package::Type type);
+ void addNames (std::string name, char separator = 0, bool use_name = true,
+ bool use_summary = true, bool use_description = false,
+ bool use_filelist = false, bool use_authors = false,
+ bool full_word_match = false);
+ void addCategory (Ypp::Node *category);
+ void addCategory2 (Ypp::Node *category);
+ void addCollection (const Ypp::Package *package);
+ void addRepository (const Ypp::Repository *repository);
+ void setIsInstalled (bool installed);
+ void setHasUpgrade (bool upgradable);
+ void setToModify (bool modify);
+ void setIsRecommended (bool recommended);
+ void setIsSuggested (bool suggested);
+ void setBuildAge (int days);
+ void setIsUnsupported (bool unsupported);
+ void setClear();
+
+ ~Query();
+ struct Impl;
+ Impl *impl;
+ };
+
+ // startEmpty is an optimization when you know the pool won't have
+ // elements at creations.
+ QueryPool (Query *query, bool startEmpty = false);
+
+ virtual Pool::Iter getFirst();
+ virtual Pool::Iter getNext (Pool::Iter it);
+ virtual Pool::Iter getParent (Pool::Iter it) { return NULL; }
+ virtual Pool::Iter getChild (Pool::Iter it) { return NULL; }
+ virtual bool isPlainList() const { return true; }
+
+ virtual Package *get (Pool::Iter it);
+ virtual std::string getName (Pool::Iter it)
+ { return get (it)->name(); }
+
+ virtual bool highlight (Pool::Iter it);
+
+ struct Impl;
+ Impl *impl;
+ };
+
+ // Pool of categories with the packages as leaves -- only for 1D categories
+ // this is a dead pool -- entries can be changed, but not inserted or removed
+ struct TreePool : public Pool {
+ TreePool (Ypp::Package::Type type);
+
+ virtual Pool::Iter getFirst();
+ virtual Pool::Iter getNext (Pool::Iter it);
+ virtual Pool::Iter getParent (Pool::Iter it);
+ virtual Pool::Iter getChild (Pool::Iter it);
+ virtual bool isPlainList() const { return false; }
+
+ virtual std::string getName (Pool::Iter it);
+ virtual Package *get (Pool::Iter it); /* may be NULL */
+ virtual bool highlight (Pool::Iter it) { return false; }
+
+ struct Impl;
+ Impl *impl;
+ };
+
+ // Resolver
+ struct Problem {
+ std::string description, details;
+ struct Solution {
+ std::string description, details;
+ bool apply;
+ void *impl;
+ };
+ Solution *getSolution (int nb);
+ void *impl;
+ };
+
+ // Module
+ static Ypp *get();
+ static void finish();
+
+ struct Interface {
+ virtual bool acceptLicense (Package *package, const std::string &license) = 0;
+ virtual void notifyMessage (Package *package, const std::string &message) = 0;
+ // resolveProblems = false to cancel the action that had that effect
+ virtual bool resolveProblems (const std::list &problems) = 0;
+ virtual bool allowRestrictedRepo (const std::list > &pkgs) = 0;
+ };
+ void setInterface (Interface *interface);
+
+ struct PkgListener {
+ virtual void packageModified (Package *package) = 0;
+ };
+ void addPkgListener (PkgListener *listener);
+ void removePkgListener (PkgListener *listener);
+
+ // Repositories
+ struct Repository {
+ std::string name, url, alias /*internal use*/;
+ bool enabled;
+ };
+ const Repository *getRepository (int nb);
+ void setFavoriteRepository (const Repository *repo); /* 0 to disable restrictions */
+ const Repository *favoriteRepository();
+
+ // Misc
+ Package *findPackage (Package::Type type, const std::string &name);
+
+ Node *getFirstCategory (Package::Type type);
+ Node *getFirstCategory2 (Package::Type type);
+
+ struct Disk {
+ struct Partition {
+ std::string path, used_str, delta_str, total_str;
+ long long used, delta, total;
+ };
+ const Partition *getPartition (int nb);
+
+ struct Listener {
+ virtual void update() = 0;
+ };
+ void setListener (Listener *listener);
+
+ Disk();
+ ~Disk();
+ struct Impl;
+ Impl *impl;
+ };
+ Disk *getDisk();
+
+ bool isModified(); // any change made?
+
+ bool importList (const char *filename);
+ bool exportList (const char *filename);
+ bool createSolverTestcase (const char *dirname);
+
+ Ypp();
+ ~Ypp();
+ struct Impl;
+ Impl *impl;
+};
+
+#endif /*ZYPP_WRAPPER_H*/
+
--
To unsubscribe, e-mail: yast-commit+unsubscribe@opensuse.org
For additional commands, e-mail: yast-commit+help@opensuse.org