summaryrefslogtreecommitdiff
path: root/portato/gui
diff options
context:
space:
mode:
Diffstat (limited to 'portato/gui')
-rw-r--r--portato/gui/queue.py116
-rw-r--r--portato/gui/templates/MainWindow.glade195
-rw-r--r--portato/gui/templates/PreferenceWindow.glade101
-rw-r--r--portato/gui/templates/popups.glade4
-rw-r--r--portato/gui/updater.py15
-rw-r--r--portato/gui/windows/main.py416
-rw-r--r--portato/gui/windows/preference.py16
7 files changed, 526 insertions, 337 deletions
diff --git a/portato/gui/queue.py b/portato/gui/queue.py
index a75048d..ce7e620 100644
--- a/portato/gui/queue.py
+++ b/portato/gui/queue.py
@@ -15,13 +15,16 @@ from __future__ import absolute_import
# some stuff needed
import os, pty
import signal, threading, time
+import itertools as itt
from subprocess import Popen
# some backend things
from .. import backend, plugin
from ..backend import flags, system
-from ..helper import debug, info, send_signal_to_group, unique_array
+from ..backend.exceptions import BlockedException
+from ..helper import debug, info, warning, send_signal_to_group, unique_array, flatten
from ..waiting_queue import WaitingQueue
+from ..odict import OrderedDict
from .updater import Updater
# the wrapper
@@ -55,6 +58,7 @@ class EmergeQueue:
# dictionaries with data about the packages in the queue
self.iters = {"install" : {}, "uninstall" : {}, "update" : {}} # iterator in the tree
self.deps = {"install" : {}, "update" : {}} # all the deps of the package
+ self.blocks = {"install" : OrderedDict(), "update" : OrderedDict()}
# member vars
self.tree = tree
@@ -189,20 +193,21 @@ class EmergeQueue:
# add iter
subIt = self.tree.append(it, self.tree.build_append_value(cpv, oneshot = oneshot, update = update, downgrade = downgrade, version = uVersion, useChange = changedUse))
- self.iters[type].update({cpv: subIt})
+ self.iters[type][cpv] = subIt
# get dependencies
- deps = pkg.get_dep_packages() # this might raise a BlockedException
- self.deps[type].update({cpv : deps})
+ deps = pkg.get_dep_packages(return_blocks = True)
+ self.deps[type][cpv] = deps
- # recursive call
for d in deps:
- try:
+ if d[0] == "!": # block
+ dep = d[1:]
+ if not dep in self.blocks[type]:
+ self.blocks[type][dep] = set()
+
+ self.blocks[type][dep].add(cpv)
+ else: # recursive call
self.update_tree(subIt, d, unmask, type = type)
- except backend.BlockedException, e: # BlockedException occured -> delete current tree and re-raise exception
- debug("Something blocked: %s", e[0])
- self.remove_with_children(subIt)
- raise
def append (self, cpv, type = "install", update = False, forceUpdate = False, unmask = False, oneshot = False):
"""Appends a cpv either to the merge queue or to the unmerge-queue.
@@ -226,7 +231,7 @@ class EmergeQueue:
if type in ("install", "update"): # emerge
if update:
pkg = self._get_pkg_from_cpv(cpv, unmask)
- deps = pkg.get_dep_packages()
+ deps = pkg.get_dep_packages(return_blocks = True)
if not forceUpdate and cpv in self.deps[type] and deps == self.deps[type][cpv]:
return # nothing changed - return
@@ -248,6 +253,51 @@ class EmergeQueue:
self.update_tree(self.tree.get_emerge_it(), cpv, unmask, type = type, oneshot = oneshot)
elif type == "update" and self.tree:
self.update_tree(self.tree.get_update_it(), cpv, unmask, type = type, oneshot = oneshot)
+
+ # handle blocks
+ if self.blocks[type]:
+ # check whether anything blocks something in the queue
+ for block in self.blocks[type]:
+ for c in self.iters[type]:
+ if system.cpv_matches(c, block):
+ blocked = ", ".join(self.blocks[type][block])
+ warning("'%s' is blocked by: %s", c, blocked)
+ self.remove_with_children(self.iters[type][c], False)
+ raise BlockedException(c, blocked)
+
+ #
+ # check whether we block a version that we are going to replace nevertheless
+ #
+
+ # get the blocks that block an installed package
+ inst = []
+ for block in self.blocks[type]:
+ pkgs = system.find_packages(block, "installed")
+ if pkgs:
+ inst.append((pkgs, block))
+
+ # the slot-cp's of the packages in the queue
+ slots = {}
+ for c in self.iters[type]:
+ slots[system.new_package(c).get_slot_cp()] = cpv
+
+ # check the installed blocks against the slot-cp's
+ for pkgs, block in inst[:]:
+ done = False
+ for pkg in pkgs:
+ done = False
+ if pkg.get_slot_cp() in slots:
+ debug("Block '%s' can be ignored, because the blocking package is going to be replaced with '%s'.", block, slots[pkg.get_slot_cp()])
+ done = True
+ if done:
+ inst.remove((pkgs,block))
+
+ if inst: # there is still something left to block
+ for pkgs, block in inst:
+ blocked = ", ".join(self.blocks[type][block])
+ warning("'%s' blocks the installation of: %s", pkgs[0].get_cpv(), blocked)
+ self.remove_with_children(self.iters[type][cpv], False)
+ raise BlockedException(blocked, pkgs[0].get_cpv())
else: # unmerge
self.unmergequeue.append(cpv)
@@ -544,15 +594,32 @@ class EmergeQueue:
@type it: Iterator
@param removeNewFlags: True if new flags should be removed; False otherwise. Default: True.
@type removeNewFlags: boolean"""
+
+ def __remove (type, cpv):
+ del self.iters[type][cpv]
+ try:
+ del self.deps[type][cpv]
+ except KeyError: # this seems to be removed due to a BlockedException - so no deps here atm ;)
+ debug("Catched KeyError => %s seems not to be in self.deps. Should be no harm in normal cases.", cpv)
+
+ for key in self.blocks[type].keys():
+ if cpv in self.blocks[type][key]:
+ self.blocks[type][key].remove(cpv)
+
+ if not self.blocks[type][key]: # list is empty -> remove the whole key
+ del self.blocks[type][key]
+
+ if removeNewFlags: # remove the changed flags
+ flags.remove_new_use_flags(cpv)
+ flags.remove_new_masked(cpv)
+ flags.remove_new_testing(cpv)
if self.tree.iter_has_parent(it):
cpv = self.tree.get_value(it, self.tree.get_cpv_column())
if self.tree.is_in_emerge(it): # Emerge
- del self.iters["install"][cpv]
- try:
- del self.deps["install"][cpv]
- except KeyError: # this seems to be removed due to a BlockedException - so no deps here atm ;)
- debug("Catched KeyError => %s seems not to be in self.deps. Should be no harm in normal cases.", cpv)
+
+ __remove("install", cpv)
+
try:
self.mergequeue.remove(cpv)
except ValueError: # this is a dependency - ignore
@@ -560,27 +627,14 @@ class EmergeQueue:
self.oneshotmerge.remove(cpv)
except ValueError:
debug("Catched ValueError => %s seems not to be in merge-queue. Should be no harm.", cpv)
-
- if removeNewFlags: # remove the changed flags
- flags.remove_new_use_flags(cpv)
- flags.remove_new_masked(cpv)
- flags.remove_new_testing(cpv)
elif self.tree.is_in_unmerge(it): # in Unmerge
del self.iters["uninstall"][cpv]
self.unmergequeue.remove(cpv)
elif self.tree.is_in_update(it):
- del self.iters["update"][cpv]
- try:
- del self.deps["update"][cpv]
- except KeyError: # this seems to be removed due to a BlockedException - so no deps here atm ;)
- debug("Catched KeyError => %s seems not to be in self.deps. Should be no harm in normal cases.", cpv)
-
- if removeNewFlags: # remove the changed flags
- flags.remove_new_use_flags(cpv)
- flags.remove_new_masked(cpv)
- flags.remove_new_testing(cpv)
+ __remove("update", cpv)
+
self.tree.remove(it)
diff --git a/portato/gui/templates/MainWindow.glade b/portato/gui/templates/MainWindow.glade
index 788a339..54a08c9 100644
--- a/portato/gui/templates/MainWindow.glade
+++ b/portato/gui/templates/MainWindow.glade
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
-<!--Generated with glade3 3.4.3 on Mon Apr 21 23:09:43 2008 -->
+<!--Generated with glade3 3.4.4 on Sat Jun 7 19:07:21 2008 -->
<glade-interface>
<widget class="GtkWindow" id="MainWindow">
<property name="border_width">2</property>
@@ -46,8 +46,8 @@
<property name="label" translatable="yes">Re_load Portage</property>
<property name="use_underline">True</property>
<signal name="activate" handler="cb_reload_clicked"/>
- <accelerator key="R" modifiers="GDK_CONTROL_MASK" signal="activate"/>
<accelerator key="F5" modifiers="" signal="activate"/>
+ <accelerator key="R" modifiers="GDK_CONTROL_MASK" signal="activate"/>
<child internal-child="image">
<widget class="GtkImage" id="menu-item-image9">
<property name="visible">True</property>
@@ -463,7 +463,6 @@
<property name="visible">True</property>
<property name="headers_clickable">True</property>
<property name="search_column">1</property>
- <signal name="cursor_changed" handler="cb_version_list_changed"/>
</widget>
</child>
</widget>
@@ -616,271 +615,271 @@
<placeholder/>
</child>
<child>
- <widget class="GtkLabel" id="useFlagsLabel">
+ <widget class="GtkLabel" id="licenseLabel">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="no_show_all">True</property>
<property name="xalign">0</property>
- <property name="label">use flags</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_END</property>
+ <property name="label" translatable="yes">label</property>
<property name="single_line_mode">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
- <property name="top_attach">4</property>
- <property name="bottom_attach">5</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="useFlagsLabelLabel">
+ <widget class="GtkLabel" id="licenseLabelLabel">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="no_show_all">True</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">&lt;b&gt;Use Flags:&lt;/b&gt;</property>
+ <property name="label" translatable="yes">&lt;b&gt;License:&lt;/b&gt;</property>
<property name="use_markup">True</property>
<property name="single_line_mode">True</property>
</widget>
<packing>
- <property name="top_attach">4</property>
- <property name="bottom_attach">5</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
<property name="y_padding">5</property>
</packing>
</child>
<child>
- <widget class="GtkCheckButton" id="testingCheck">
+ <widget class="GtkLabel" id="notInSysLabel">
<property name="visible">True</property>
- <property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="no_show_all">True</property>
- <property name="label" translatable="yes">Testing</property>
- <property name="xalign">0</property>
- <property name="response_id">0</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="cb_testing_toggled"/>
+ <property name="label" translatable="yes">&lt;b&gt;Installed, but not in portage anymore&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
</widget>
<packing>
- <property name="top_attach">7</property>
- <property name="bottom_attach">8</property>
- <property name="x_options">GTK_FILL</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="maskedLabel">
+ <widget class="GtkLabel" id="missingLabel">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="xalign">0</property>
+ <property name="no_show_all">True</property>
+ <property name="label" translatable="yes">&lt;span foreground='red'&gt;&lt;b&gt;MISSING KEYWORD&lt;/b&gt;&lt;/span&gt;</property>
+ <property name="use_markup">True</property>
</widget>
<packing>
- <property name="left_attach">1</property>
<property name="right_attach">2</property>
- <property name="top_attach">8</property>
- <property name="bottom_attach">9</property>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkCheckButton" id="maskedCheck">
+ <widget class="GtkHBox" id="linkBox">
<property name="visible">True</property>
- <property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="no_show_all">True</property>
- <property name="label" translatable="yes">Masked</property>
- <property name="xalign">0</property>
- <property name="response_id">0</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="cb_masked_toggled"/>
+ <property name="spacing">5</property>
+ <child>
+ <placeholder/>
+ </child>
</widget>
<packing>
- <property name="top_attach">8</property>
- <property name="bottom_attach">9</property>
- <property name="x_options">GTK_FILL</property>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkCheckButton" id="installedCheck">
+ <widget class="GtkLabel" id="descLabelLabel">
<property name="visible">True</property>
- <property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="no_show_all">True</property>
- <property name="label" translatable="yes">Installed</property>
<property name="xalign">0</property>
- <property name="response_id">0</property>
- <property name="draw_indicator">True</property>
- <signal name="button_press_event" handler="cb_button_pressed"/>
+ <property name="label" translatable="yes">&lt;b&gt;Description:&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ <property name="single_line_mode">True</property>
</widget>
<packing>
- <property name="top_attach">6</property>
- <property name="bottom_attach">7</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
+ <property name="y_padding">5</property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="homepageLinkLabel">
+ <widget class="GtkLabel" id="overlayLabelLabel">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="no_show_all">True</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">&lt;b&gt;Homepage:&lt;/b&gt;</property>
+ <property name="label" translatable="yes">&lt;b&gt;Overlay:&lt;/b&gt;</property>
<property name="use_markup">True</property>
<property name="single_line_mode">True</property>
</widget>
<packing>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
<property name="y_padding">5</property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="overlayLabel">
+ <widget class="GtkLabel" id="descLabel">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="no_show_all">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">label</property>
- <property name="single_line_mode">True</property>
+ <property name="wrap">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="descLabel">
+ <widget class="GtkLabel" id="overlayLabel">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="no_show_all">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">label</property>
- <property name="wrap">True</property>
+ <property name="single_line_mode">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="overlayLabelLabel">
+ <widget class="GtkLabel" id="homepageLinkLabel">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="no_show_all">True</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">&lt;b&gt;Overlay:&lt;/b&gt;</property>
+ <property name="label" translatable="yes">&lt;b&gt;Homepage:&lt;/b&gt;</property>
<property name="use_markup">True</property>
<property name="single_line_mode">True</property>
</widget>
<packing>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
<property name="y_padding">5</property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="descLabelLabel">
+ <widget class="GtkCheckButton" id="installedCheck">
<property name="visible">True</property>
+ <property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="no_show_all">True</property>
+ <property name="label" translatable="yes">Installed</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">&lt;b&gt;Description:&lt;/b&gt;</property>
- <property name="use_markup">True</property>
- <property name="single_line_mode">True</property>
+ <property name="response_id">0</property>
+ <property name="draw_indicator">True</property>
+ <signal name="button_press_event" handler="cb_button_pressed"/>
</widget>
<packing>
+ <property name="top_attach">6</property>
+ <property name="bottom_attach">7</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
- <property name="y_padding">5</property>
</packing>
</child>
<child>
- <widget class="GtkHBox" id="linkBox">
+ <widget class="GtkCheckButton" id="maskedCheck">
<property name="visible">True</property>
+ <property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="spacing">5</property>
- <child>
- <placeholder/>
- </child>
+ <property name="no_show_all">True</property>
+ <property name="label" translatable="yes">Masked</property>
+ <property name="xalign">0</property>
+ <property name="response_id">0</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="cb_masked_toggled"/>
</widget>
<packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
+ <property name="top_attach">8</property>
+ <property name="bottom_attach">9</property>
+ <property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="missingLabel">
+ <widget class="GtkLabel" id="maskedLabel">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="no_show_all">True</property>
- <property name="label" translatable="yes">&lt;span foreground='red'&gt;&lt;b&gt;MISSING KEYWORD&lt;/b&gt;&lt;/span&gt;</property>
- <property name="use_markup">True</property>
+ <property name="xalign">0</property>
</widget>
<packing>
+ <property name="left_attach">1</property>
<property name="right_attach">2</property>
- <property name="top_attach">5</property>
- <property name="bottom_attach">6</property>
+ <property name="top_attach">8</property>
+ <property name="bottom_attach">9</property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="notInSysLabel">
+ <widget class="GtkCheckButton" id="testingCheck">
<property name="visible">True</property>
+ <property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="no_show_all">True</property>
- <property name="label" translatable="yes">&lt;b&gt;Installed, but not in portage anymore&lt;/b&gt;</property>
- <property name="use_markup">True</property>
+ <property name="label" translatable="yes">Testing</property>
+ <property name="xalign">0</property>
+ <property name="response_id">0</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="cb_testing_toggled"/>
</widget>
<packing>
- <property name="right_attach">2</property>
- <property name="top_attach">5</property>
- <property name="bottom_attach">6</property>
+ <property name="top_attach">7</property>
+ <property name="bottom_attach">8</property>
+ <property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="licenseLabelLabel">
+ <widget class="GtkLabel" id="useFlagsLabelLabel">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="no_show_all">True</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">&lt;b&gt;License:&lt;/b&gt;</property>
+ <property name="label" translatable="yes">&lt;b&gt;Use Flags:&lt;/b&gt;</property>
<property name="use_markup">True</property>
<property name="single_line_mode">True</property>
</widget>
<packing>
- <property name="top_attach">3</property>
- <property name="bottom_attach">4</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
<property name="y_padding">5</property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="licenseLabel">
+ <widget class="GtkLabel" id="useFlagsLabel">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="no_show_all">True</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">label</property>
+ <property name="label">use flags</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_END</property>
<property name="single_line_mode">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
- <property name="top_attach">3</property>
- <property name="bottom_attach">4</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
<property name="y_options"></property>
</packing>
</child>
diff --git a/portato/gui/templates/PreferenceWindow.glade b/portato/gui/templates/PreferenceWindow.glade
index 4cc7dce..3dc556b 100644
--- a/portato/gui/templates/PreferenceWindow.glade
+++ b/portato/gui/templates/PreferenceWindow.glade
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
-<!--Generated with glade3 3.4.1 on Tue Mar 25 16:14:57 2008 -->
+<!--Generated with glade3 3.4.4 on Sun Jun 8 01:45:17 2008 -->
<glade-interface>
<widget class="GtkWindow" id="PreferenceWindow">
<property name="border_width">5</property>
@@ -517,7 +517,7 @@
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
- <property name="tooltip_markup">Update the package list with the current search results while you are typing.
+ <property name="tooltip_markup" translatable="yes">Update the package list with the current search results while you are typing.
&lt;b&gt;Note&lt;/b&gt;: Will slow down the typing process.</property>
<property name="label" translatable="yes">Search while typing</property>
<property name="yalign">0.47999998927116394</property>
@@ -561,31 +561,66 @@
<property name="left_padding">12</property>
<property name="right_padding">5</property>
<child>
- <widget class="GtkHBox" id="hbox1">
+ <widget class="GtkVBox" id="vbox1">
<property name="visible">True</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="spacing">5</property>
<child>
- <widget class="GtkLabel" id="label11">
+ <widget class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Console Font</property>
+ <property name="spacing">5</property>
+ <child>
+ <widget class="GtkLabel" id="label11">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Console Font</property>
+ <property name="single_line_mode">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkFontButton" id="consoleFontBtn">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="response_id">0</property>
+ <property name="title" translatable="yes">Chose a console font</property>
+ <property name="use_font">True</property>
+ <property name="use_size">True</property>
+ <property name="show_style">False</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
</widget>
</child>
<child>
- <widget class="GtkFontButton" id="consoleFontBtn">
+ <widget class="GtkHBox" id="hbox">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="response_id">0</property>
- <property name="title" translatable="yes">Chose a console font</property>
- <property name="use_font">True</property>
- <property name="use_size">True</property>
- <property name="show_style">False</property>
+ <child>
+ <widget class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Maximum length of the console title</property>
+ <property name="single_line_mode">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkSpinButton" id="titleLengthSpinBtn">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="adjustment">0 0 300 1 10 10</property>
+ <property name="snap_to_ticks">True</property>
+ <property name="numeric">True</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
</widget>
<packing>
+ <property name="padding">4</property>
<property name="position">1</property>
</packing>
</child>
@@ -714,13 +749,33 @@
<property name="left_padding">12</property>
<property name="right_padding">5</property>
<child>
- <widget class="GtkCheckButton" id="showSlotsCheck">
+ <widget class="GtkVBox" id="vbox3">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="label" translatable="yes">Show slots in the version list</property>
- <property name="response_id">0</property>
- <property name="draw_indicator">True</property>
+ <child>
+ <widget class="GtkCheckButton" id="showSlotsCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Show slots in the version list</property>
+ <property name="response_id">0</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkCheckButton" id="collapseCatCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_tooltip">True</property>
+ <property name="tooltip_markup" translatable="yes">Organize the categories in a tree. Thereby collapse categories with the same prefix:
+As an example: &lt;i&gt;app-admin&lt;/i&gt;, &lt;i&gt;app-emacs&lt;/i&gt;, and &lt;i&gt;app-vim&lt;/i&gt; would be collapsed into &lt;i&gt;&lt;b&gt;app&lt;/b&gt;&lt;/i&gt; as root and &lt;i&gt;admin&lt;/i&gt;, &lt;i&gt;emacs&lt;/i&gt;, and &lt;i&gt;vim&lt;/i&gt; as children.</property>
+ <property name="label" translatable="yes">Collapse categories with same prefix</property>
+ <property name="response_id">0</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
</widget>
</child>
</widget>
diff --git a/portato/gui/templates/popups.glade b/portato/gui/templates/popups.glade
index 270449b..63169c3 100644
--- a/portato/gui/templates/popups.glade
+++ b/portato/gui/templates/popups.glade
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
-<!--Generated with glade3 3.4.1 on Fri Feb 29 00:01:56 2008 -->
+<!--Generated with glade3 3.4.4 on Mon Jun 9 20:49:26 2008 -->
<glade-interface>
<widget class="GtkMenu" id="systrayPopup">
<property name="visible">True</property>
@@ -18,7 +18,7 @@
<property name="visible">True</property>
<property name="label" translatable="yes">_Kill Emerge</property>
<property name="use_underline">True</property>
- <signal name="activate" handler="cb_kill_emerge"/>
+ <signal name="activate" handler="cb_kill_clicked"/>
<child internal-child="image">
<widget class="GtkImage" id="menu-item-image16">
<property name="visible">True</property>
diff --git a/portato/gui/updater.py b/portato/gui/updater.py
index f293fbc..ba46ffd 100644
--- a/portato/gui/updater.py
+++ b/portato/gui/updater.py
@@ -15,7 +15,7 @@ from __future__ import absolute_import
from ..backend import system
import threading, subprocess, time
-from ..helper import debug, error
+from ..helper import debug, warning, error
class Updater (object):
"""
@@ -79,21 +79,26 @@ q
"""
self.stopEvent.set()
- def find (self, pv):
+ def find (self, pv, masked = False):
"""
As qlop only returns 'package-version' we need to assign it to a cpv.
This is done here.
"""
- pkgs = system.find_packages("=%s" % pv, only_cpv = True)
+ pkgs = system.find_packages("=%s" % pv, only_cpv = True, masked = masked)
if len(pkgs) > 1: # ambigous - try to find the one which is also in the iterators
for p in pkgs:
if p in self.iterators:
return p
elif not pkgs: # nothing found =|
- error(_("Trying to remove package '%s' from queue which does not exist in system."), pv)
- return None
+ if not masked:
+ warning(_("No unmasked version of package '%s' found. Trying masked ones. This normally should not happen..."), pv)
+ return self.find(pv, True)
+
+ else:
+ error(_("Trying to remove package '%s' from queue which does not exist in system."), pv)
+ return None
else: # only one choice =)
return pkgs[0]
diff --git a/portato/gui/windows/main.py b/portato/gui/windows/main.py
index 36054a1..b675d17 100644
--- a/portato/gui/windows/main.py
+++ b/portato/gui/windows/main.py
@@ -19,6 +19,7 @@ import gobject
# other
import os.path
import itertools as itt
+from collections import defaultdict
# our backend stuff
from ...backend import flags, system # must be the first to avoid circular deps
@@ -67,10 +68,6 @@ class PackageTable:
# the notebook
self.notebook = self.tree.get_widget("packageNotebook")
- # the version combo
- self.versionList = self.tree.get_widget("versionList")
- self.build_version_list()
-
# chechboxes
self.installedCheck = self.tree.get_widget("installedCheck")
self.maskedCheck = self.tree.get_widget("maskedCheck")
@@ -117,15 +114,13 @@ class PackageTable:
self.icons["or"] = self.window.render_icon(gtk.STOCK_MEDIA_PAUSE, gtk.ICON_SIZE_MENU)
self.icons["block"] = self.window.render_icon(gtk.STOCK_NO, gtk.ICON_SIZE_MENU)
- def update (self, cp, queue = None, version = None, doEmerge = True, instantChange = False, type = None):
+ def update (self, pkg, queue = None, doEmerge = True, instantChange = False, type = None):
"""Updates the table to show the contents for the package.
- @param cp: the selected package
- @type cp: string (cp)
+ @param pkg: the selected package
+ @type pkg: Package
@param queue: emerge-queue (if None the emerge-buttons are disabled)
@type queue: EmergeQueue
- @param version: if not None, specifies the version to select
- @type version: string
@param doEmerge: if False, the emerge buttons are disabled
@type doEmerge: boolean
@param instantChange: if True the changed keywords are updated instantly
@@ -133,40 +128,28 @@ class PackageTable:
@param type: the type of the queue this package is in; if None there is no queue :)
@type type: string"""
- self.cp = cp # category/package
- self.version = version # version - if not None this is used
+ self.pkg = pkg
self.queue = queue
self.doEmerge = doEmerge
self.instantChange = instantChange
self.type = type
- # packages and installed packages
- if not self.doEmerge:
- self.instPackages = self.packages = system.find_packages("=%s-%s" % (cp, version), masked = True)
- else:
- self.packages = system.sort_package_list(system.find_packages(cp, masked = True))
- self.instPackages = system.sort_package_list(system.find_packages(cp, "installed", masked = True))
-
- # version-combo-box
- self.versionList.get_model().clear()
- self.fill_version_list()
-
if not self.queue or not self.doEmerge:
self.emergeBtn.set_sensitive(False)
self.unmergeBtn.set_sensitive(False)
# current status
- self.cb_version_list_changed()
+ self._update_table()
self.vb.show_all()
def hide (self):
self.vb.hide_all()
def set_labels (self):
- pkg = self.actual_package()
+ pkg = self.pkg
# name
- self.nameLabel.set_markup("<b>%s</b>" % pkg.get_cp())
+ self.nameLabel.set_markup("<b>%s</b>" % pkg.get_cpv())
# description
desc = pkg.get_package_settings("DESCRIPTION") or _("<no description>")
@@ -275,7 +258,7 @@ class PackageTable:
store.append(it, [get_icon(dep), dep.dep])
try:
- deptree = self.actual_package().get_dependencies()
+ deptree = self.pkg.get_dependencies()
except AssertionError:
w = _("Can't display dependencies: This package has an unsupported dependency string.")
error(w)
@@ -285,7 +268,7 @@ class PackageTable:
def fill_use_list(self):
- pkg = self.actual_package()
+ pkg = self.pkg
pkg_flags = pkg.get_iuse_flags()
pkg_flags.sort()
@@ -309,7 +292,7 @@ class PackageTable:
enabled = use in euse
installed = use in instuse
- store.append(actual_exp_it, [enabled, installed, use, system.get_use_desc(use, self.cp)])
+ store.append(actual_exp_it, [enabled, installed, use, system.get_use_desc(use, self.pkg.get_cp())])
def build_dep_list (self):
store = gtk.TreeStore(gtk.gdk.Pixbuf, str)
@@ -348,115 +331,27 @@ class PackageTable:
self.useList.set_search_column(2)
self.useList.set_enable_tree_lines(True)
- def build_version_list (self):
- store = gtk.ListStore(gtk.gdk.Pixbuf, str, str)
-
- # build view
- self.versionList.set_model(store)
-
- col = gtk.TreeViewColumn(_("Versions"))
- col.set_property("expand", True)
-
- self.slotcol = gtk.TreeViewColumn(_("Slot"))
- self.slotcol.set_property("expand", True)
-
- # adding the pixbuf
- cell = gtk.CellRendererPixbuf()
- col.pack_start(cell, False)
- col.add_attribute(cell, "pixbuf", 0)
-
- # adding the package name
- cell = gtk.CellRendererText()
- col.pack_start(cell, True)
- col.add_attribute(cell, "text", 1)
-
- # adding the slot
- cell = gtk.CellRendererText()
- self.slotcol.pack_start(cell, True)
- self.slotcol.add_attribute(cell, "text", 2)
-
- self.versionList.append_column(col)
- self.versionList.append_column(self.slotcol)
-
- def fill_version_list (self):
-
- store = self.versionList.get_model()
-
- # this is here for performance reasons
- # to not query the package with info, we do not need
- if self.main.cfg.get_boolean("showSlots", "GUI"):
- def get_slot(pkg):
- return pkg.get_package_settings("SLOT")
-
- self.slotcol.set_visible(True)
-
- else:
- def get_slot(*args):
- return ""
-
- self.slotcol.set_visible(False)
-
- # append versions
- for vers, inst, slot in ((x.get_version(), x.is_installed(), get_slot(x)) for x in self.packages):
- if inst:
- icon = self.main.instPixbuf
- else:
- icon = None
-
- store.append([icon, vers, slot])
-
- pos = ((0,)) # default
-
- # activate the first one
- try:
- best_version = ""
- if self.version:
- best_version = self.version
- else:
- best_version = system.find_best_match(self.packages[0].get_cp(), only_installed = (self.instPackages != [])).get_version()
- for i in range(len(self.packages)):
- if self.packages[i].get_version() == best_version:
- pos = (i,)
- break
- except AttributeError: # no package found
- pass
-
- self.versionList.get_selection().select_path(pos)
- self.versionList.scroll_to_cell(pos)
-
- def actual_package (self):
- """Returns the actual selected package.
-
- @returns: the actual selected package
- @rtype: backend.Package"""
-
- model, iter = self.versionList.get_selection().get_selected()
- if iter:
- return self.packages[model.get_path(iter)[0]]
- else:
- return self.packages[0]
-
def _update_keywords (self, emerge, update = False):
if emerge:
type = "install" if not self.type else self.type
try:
try:
- self.queue.append(self.actual_package().get_cpv(), type = type, update = update)
+ self.queue.append(self.pkg.get_cpv(), type = type, update = update)
except PackageNotFoundException, e:
if unmask_dialog(e[0]) == gtk.RESPONSE_YES:
- self.queue.append(self.actual_package().get_cpv(), type = type, unmask = True, update = update)
+ self.queue.append(self.pkg.get_cpv(), type = type, unmask = True, update = update)
except BlockedException, e:
blocked_dialog(e[0], e[1])
else:
try:
- self.queue.append(self.actual_package().get_cpv(), type = "uninstall")
+ self.queue.append(self.pkg.get_cpv(), type = "uninstall")
except PackageNotFoundException, e:
error(_("Package could not be found: %s"), e[0])
#masked_dialog(e[0])
- def cb_version_list_changed (self, *args):
+ def _update_table (self, *args):
- pkg = self.actual_package()
+ pkg = self.pkg
# set the views
for v in (self.ebuildView, self.changelogView, self.filesView):
@@ -530,7 +425,7 @@ class PackageTable:
if self.doEmerge:
# set emerge-button-label
- if not self.actual_package().is_installed():
+ if not pkg.is_installed():
self.unmergeBtn.set_sensitive(False)
else:
self.unmergeBtn.set_sensitive(True)
@@ -546,12 +441,10 @@ class PackageTable:
def cb_package_revert_clicked (self, button):
"""Callback for pressed revert-button."""
- self.actual_package().remove_new_use_flags()
- self.actual_package().remove_new_masked()
- self.actual_package().remove_new_testing()
- self.versionList.get_model().clear()
- self.fill_version_list()
- self.cb_version_list_changed()
+ self.pkg.remove_new_use_flags()
+ self.pkg.remove_new_masked()
+ self.pkg.remove_new_testing()
+ self._update_table()
if self.instantChange:
self._update_keywords(True, update = True)
return True
@@ -573,21 +466,21 @@ class PackageTable:
status = button.get_active()
# end of recursion :)
- if self.actual_package().is_testing(use_keywords = False) == status:
+ if self.pkg.is_testing(use_keywords = False) == status:
return False
# if the package is not testing - don't allow to set it as such
- if not self.actual_package().is_testing(use_keywords = False):
+ if not self.pkg.is_testing(use_keywords = False):
button.set_active(False)
return True
# re-set to testing status
- if not self.actual_package().is_testing(use_keywords = True):
- self.actual_package().set_testing(False)
+ if not self.pkg.is_testing(use_keywords = True):
+ self.pkg.set_testing(False)
button.set_label(_("Testing"))
button.set_active(True)
else: # disable testing
- self.actual_package().set_testing(True)
+ self.pkg.set_testing(True)
button.set_label("<i>(%s)</i>" % _("Testing"))
button.get_child().set_use_markup(True)
button.set_active(True)
@@ -600,7 +493,7 @@ class PackageTable:
def cb_masked_toggled (self, button):
"""Callback for toggled masking-checkbox."""
status = button.get_active()
- pkg = self.actual_package()
+ pkg = self.pkg
if pkg.is_masked(use_changed = False) == status and not pkg.is_locally_masked():
return False
@@ -637,7 +530,7 @@ class PackageTable:
def cb_use_flag_toggled (self, cell, path, store):
"""Callback for a toggled use-flag button."""
flag = store[path][2]
- pkg = self.actual_package()
+ pkg = self.pkg
if pkg.use_expanded(flag): # ignore expanded flags
return False
@@ -733,12 +626,17 @@ class MainWindow (Window):
self.hpaned = self.tree.get_widget("hpaned")
self.hpaned.set_position(int(self.window.get_size()[0]/1.5))
- # cat and pkg list
+ # lists
+ self.selCatName = ""
+ self.selCP = ""
+ self.selCPV = ""
self.sortPkgListByName = True
self.catList = self.tree.get_widget("catList")
self.pkgList = self.tree.get_widget("pkgList")
+ self.versionList = self.tree.get_widget("versionList")
self.build_cat_list()
self.build_pkg_list()
+ self.build_version_list()
# search entry
self.searchEntry = self.tree.get_widget("searchEntry")
@@ -804,9 +702,6 @@ class MainWindow (Window):
self.queueTree = GtkTree(self.queueList.get_model())
self.queue = EmergeQueue(console = self.console, tree = self.queueTree, db = self.db, title_update = self.title_update, threadClass = GtkThread)
- self.catList.get_selection().select_path(1)
- self.pkgList.get_selection().select_path(0)
-
# session
splash(_("Restoring Session"))
try:
@@ -821,8 +716,25 @@ class MainWindow (Window):
self.window.show_all()
- def show_package (self, *args, **kwargs):
- self.packageTable.update(*args, **kwargs)
+ def show_package (self, pkg = None, cpv = None, cp = None, version = None, **kwargs):
+ p = None
+
+ if pkg:
+ p = pkg
+ elif cpv:
+ p = system.find_packages("="+cpv, masked = True)[0]
+ elif cp:
+ if version:
+ p = system.find_packages("=%s-%s" % (cp, version), masked = True)[0]
+
+ else:
+ best = system.find_best_match(cp)
+ if best:
+ p = best
+ else:
+ p = system.find_packages(cp)[0]
+
+ self.packageTable.update(p, **kwargs)
def build_terminal (self):
"""
@@ -860,28 +772,53 @@ class MainWindow (Window):
Builds the category list.
"""
- store = gtk.ListStore(str)
+ store = gtk.TreeStore(str)
+
+ self.fill_cat_store(store)
self.catList.set_model(store)
cell = gtk.CellRendererText()
col = gtk.TreeViewColumn(_("Categories"), cell, text = 0)
self.catList.append_column(col)
- self.fill_cat_store(store)
self.catList.get_selection().connect("changed", self.cb_cat_list_selection)
- def fill_cat_store (self, store):
+ def fill_cat_store (self, store = None):
"""
Fills the category store with data.
-
+
@param store: the store to fill
@type store: gtk.ListStore
"""
+ if store is None:
+ store = self.catList.get_model()
+
+ store.clear()
+
cats = self.db.get_categories(installed = not self.showAll)
- for p in cats:
- store.append([p])
+ if not self.cfg.get_boolean("collapseCats", "GUI"):
+ for p in cats:
+ store.append(None, [p])
+ else:
+ splitCats = defaultdict(list)
+ for c in cats:
+ try:
+ pre, post = c.split("-", 1)
+ except ValueError: # no "-" in cat name -- do not split
+ debug("Category '%s' can't be split up. Should be no harm.", c)
+ splitCats["not-split"].append(c)
+ else:
+ splitCats[pre].append(post)
+
+ for sc in splitCats:
+ if sc == "not-split":
+ it = None # append not splitted stuff to root
+ else:
+ it = store.append(None, [sc])
+ for cat in splitCats[sc]:
+ store.append(it, [cat])
# sort them alphabetically
store.set_sort_column_id(0, gtk.SORT_ASCENDING)
@@ -895,7 +832,7 @@ class MainWindow (Window):
"""
store = gtk.ListStore(gtk.gdk.Pixbuf, str, str)
- self.fill_pkg_store(store,name)
+ self.fill_pkg_store(store, name)
# build view
self.pkgList.set_model(store)
@@ -918,7 +855,7 @@ class MainWindow (Window):
self.pkgList.get_selection().connect("changed", self.cb_pkg_list_selection)
- def fill_pkg_store (self, store, name = None):
+ def fill_pkg_store (self, store = None, name = None):
"""
Fills a given ListStore with the packages in a category.
@@ -927,6 +864,10 @@ class MainWindow (Window):
@param name: the name of the category
@type name: string
"""
+
+ if store is None:
+ store = self.pkgList.get_model()
+ store.clear()
if name:
for cat, pkg, is_inst in self.db.get_cat(name, self.sortPkgListByName):
@@ -938,19 +879,96 @@ class MainWindow (Window):
icon = None
store.append([icon, pkg, cat])
+ def build_version_list (self):
+ store = gtk.ListStore(gtk.gdk.Pixbuf, str, str)
+
+ # build view
+ self.versionList.set_model(store)
+
+ col = gtk.TreeViewColumn(_("Versions"))
+ col.set_property("expand", True)
+
+ self.slotcol = gtk.TreeViewColumn(_("Slot"))
+ self.slotcol.set_property("expand", True)
+
+ # adding the pixbuf
+ cell = gtk.CellRendererPixbuf()
+ col.pack_start(cell, False)
+ col.add_attribute(cell, "pixbuf", 0)
+
+ # adding the package name
+ cell = gtk.CellRendererText()
+ col.pack_start(cell, True)
+ col.add_attribute(cell, "text", 1)
+
+ # adding the slot
+ cell = gtk.CellRendererText()
+ self.slotcol.pack_start(cell, True)
+ self.slotcol.add_attribute(cell, "text", 2)
+
+ self.versionList.append_column(col)
+ self.versionList.append_column(self.slotcol)
+
+ self.versionList.get_selection().connect("changed", self.cb_vers_list_selection)
+
+ def fill_version_list (self, cp, version = None):
+
+ store = self.versionList.get_model()
+ store.clear()
+
+ # this is here for performance reasons
+ # to not query the package with info, we do not need
+ if self.cfg.get_boolean("showSlots", "GUI"):
+ def get_slot(pkg):
+ return pkg.get_package_settings("SLOT")
+
+ self.slotcol.set_visible(True)
+
+ else:
+ def get_slot(*args):
+ return ""
+
+ self.slotcol.set_visible(False)
+
+ packages = system.sort_package_list(system.find_packages(cp, masked=True))
+
+ # append versions
+ for vers, inst, slot in ((x.get_version(), x.is_installed(), get_slot(x)) for x in packages):
+ if inst:
+ icon = self.instPixbuf
+ else:
+ icon = None
+
+ store.append([icon, vers, slot])
+
+ pos = ((0,)) # default
+
+ # activate the first one
+ try:
+ best_version = ""
+ if version:
+ best_version = version
+ else:
+ best_version = system.find_best_match(packages[0].get_cp()).get_version()
+ for i, p in enumerate(packages):
+ if p.get_version() == best_version:
+ pos = (i,)
+ break
+ except AttributeError: # no package found
+ pass
+
+ self.versionList.get_selection().select_path(pos)
+ self.versionList.scroll_to_cell(pos)
+
def refresh_stores (self):
"""
Refreshes the category and package stores.
"""
- store = self.catList.get_model()
- store.clear()
- self.fill_cat_store(store)
+ self.fill_cat_store()
- store = self.pkgList.get_model()
- store.clear()
- try:
- self.fill_pkg_store(store, self.selCatName)
- except AttributeError: # no selCatName -> so no category selected --> ignore
+ if self.selCatName:
+ self.fill_pkg_store(name = self.selCatName)
+ else: # no selCatName -> so no category selected --> ignore
debug("No category selected --> should be no harm.")
def load_session(self, sessionEx = None):
@@ -1012,7 +1030,27 @@ class MainWindow (Window):
for cname, path in ((x[col], x.path) for x in list.get_model()):
if cname == name:
pos = path
+ break
+
+ if self.cfg.get_boolean("collapseCats", "GUI") and \
+ pos == "0" and isinstance(list.get_model(), gtk.TreeStore): # try the new split up
+
+ try:
+ pre, post = name.split("-", 1)
+ except ValueError: # nothing to split
+ pass
+ else:
+ for row in list.get_model():
+ if row[col] == pre: # found first part
+ pos = row.path
+ list.expand_row(pos, False)
+ for cname, path in ((x[col], x.path) for x in row.iterchildren()):
+ if cname == post: # found second
+ pos = ":".join(map(str,path))
+ break
+ break
+ debug("Selecting path '%s'.", pos)
list.get_selection().select_path(pos)
list.scroll_to_cell(pos)
@@ -1066,13 +1104,19 @@ class MainWindow (Window):
elif version > SESSION_VERSION:
raise NewSessionException(version, SESSION_VERSION)
+ def _add (value):
+ if len(value) == 4:
+ self.session.add_handler(value[:3], default = value[3])
+ else:
+ self.session.add_handler(value)
+
# set the simple ones :)
- map(self.session.add_handler,[
+ map(_add,[
([("gtksessionversion", "session")], load_session_version, lambda: SESSION_VERSION),
([("width", "window"), ("height", "window")], lambda w,h: self.window.resize(int(w), int(h)), self.window.get_size),
([("vpanedpos", "window"), ("hpanedpos", "window")], load_paned, save_paned),
- ([("catsel", "window")], load_selection(self.catList, 0), save_cat_selection),
- ([("pkgsel", "window")], load_selection(self.pkgList, 1), save_pkg_selection)
+ ([("catsel", "window")], load_selection(self.catList, 0), save_cat_selection, ["app-portage"]),
+ ([("pkgsel", "window")], load_selection(self.pkgList, 1), save_pkg_selection, ["portato"])
#([("merge", "queue"), ("unmerge", "queue"), ("oneshot", "queue")], load_queue, save_queue),
])
@@ -1107,7 +1151,7 @@ class MainWindow (Window):
debug("Unexpected number of %s returned after search: %d", what, len(pathes))
break
- self.show_package(cp, self.queue, version = version)
+ self.show_package(cp = cp, version = version, queue = self.queue)
def set_uri_hook (self, browser):
"""
@@ -1166,7 +1210,8 @@ class MainWindow (Window):
else:
title = ("%s (%s)") % (_("Console"), title)
- if (len(title) > 60): title = "%s..." % title[:57]
+ tlength = int(self.cfg.get("titlelength", "GUI"))
+ if (len(title) > tlength): title = "%s..." % title[:tlength-3]
self.sysNotebook.set_tab_label_text(self.termHB, title)
return False
@@ -1182,26 +1227,47 @@ class MainWindow (Window):
# get the selected category
store, it = selection.get_selected()
if it:
- self.selCatName = store.get_value(it, 0)
- self.pkgList.get_model().clear()
- self.fill_pkg_store(self.pkgList.get_model(), self.selCatName)
+ if not self.cfg.get_boolean("collapseCats", "GUI"):
+ self.selCatName = store.get_value(it, 0)
+ else:
+ parent = store.iter_parent(it)
+ if parent is None:
+ if store.iter_has_child(it): # this is a split up selector -> do nothing
+ return True
+ else:
+ self.selCatName = store.get_value(it, 0) # this is a non-split up top
+ else:
+ self.selCatName = ("%s-%s" % (store.get_value(parent, 0), store.get_value(it, 0)))
+
+ self.fill_pkg_store(name = self.selCatName)
return True
def cb_pkg_list_selection (self, selection):
"""
Callback for a package-list selection.
- Updates the package info.
+ Updates the version list.
"""
store, it = selection.get_selected()
if it:
- cp = "%s/%s" % (store.get_value(it, 2), store.get_value(it, 1))
- self.show_package(cp, self.queue)
+ self.selCP = "%s/%s" % (store.get_value(it, 2), store.get_value(it, 1))
+ self.fill_version_list(self.selCP)
return True
def cb_pkg_list_header_clicked(self, col):
self.sortPkgListByName = not self.sortPkgListByName
- self.pkgList.get_model().clear()
- self.fill_pkg_store(self.pkgList.get_model(), self.selCatName)
+ self.fill_pkg_store(name = self.selCatName)
+ return True
+
+ def cb_vers_list_selection (self, selection):
+ """
+ Callback for a package-list selection.
+ Updates the version list.
+ """
+ store, it = selection.get_selected()
+ if it:
+ self.selCPV = "%s-%s" % (self.selCP, store.get_value(it, 1))
+ self.show_package(cpv = self.selCPV, queue = self.queue)
+
return True
def cb_queue_row_activated (self, view, path, *args):
@@ -1211,8 +1277,6 @@ class MainWindow (Window):
iterator = store.get_original().get_iter(path)
if store.iter_has_parent(iterator):
package = store.get_value(iterator, store.get_cpv_column())
- cat, name, vers, rev = system.split_cpv(package)
- if rev != "r0": vers = vers+"-"+rev
if store.is_in_emerge(iterator):
type = "install"
@@ -1221,7 +1285,7 @@ class MainWindow (Window):
elif store.is_in_update(iterator):
type = "update"
- self.show_package(cat+"/"+name, queue = self.queue, version = vers, instantChange = True, doEmerge = False, type = type)
+ self.show_package(cpv = package, queue = self.queue, instantChange = True, doEmerge = False, type = type)
return True
def cb_queue_tooltip_queried (self, view, x, y, is_keyboard, tooltip):
@@ -1470,7 +1534,7 @@ class MainWindow (Window):
"""
User wants to open preferences.
"""
- PreferenceWindow(self.window, self.cfg, self.console.set_font_from_string, self.set_uri_hook, self.set_notebook_tabpos)
+ PreferenceWindow(self.window, self.cfg, self.console.set_font_from_string, self.set_uri_hook, self.set_notebook_tabpos, self.fill_cat_store)
return True
def cb_about_clicked (self, *args):
@@ -1599,10 +1663,10 @@ class MainWindow (Window):
self.emergePaused = cb.get_active()
if not self.emergePaused:
self.queue.continue_emerge()
- self.tray.set_from_file(APP_ICON)
+ #self.tray.set_from_file(APP_ICON)
else:
self.queue.stop_emerge()
- self.tray.set_from_file(os.path.join(ICON_DIR, "pausing.png"))
+ #self.tray.set_from_file(os.path.join(ICON_DIR, "pausing.png"))
# block the handlers of the other buttons
# so that calling "set_active" does not call this callback recursivly
diff --git a/portato/gui/windows/preference.py b/portato/gui/windows/preference.py
index 991e7b3..d35666d 100644
--- a/portato/gui/windows/preference.py
+++ b/portato/gui/windows/preference.py
@@ -24,6 +24,7 @@ class PreferenceWindow (AbstractDialog):
# all checkboxes in the window
# widget name -> option name
checkboxes = {
+ "collapseCatCheck" : ("collapseCats", "GUI"),
"consoleUpdateCheck" : ("updateConsole", "GUI"),
"debugCheck" : "debug",
"deepCheck" : "deep",
@@ -56,7 +57,7 @@ class PreferenceWindow (AbstractDialog):
4 : gtk.POS_RIGHT
}
- def __init__ (self, parent, cfg, console_fn, linkbtn_fn, tabpos_fn):
+ def __init__ (self, parent, cfg, console_fn, linkbtn_fn, tabpos_fn, catmodel_fn):
"""Constructor.
@param parent: parent window
@@ -68,7 +69,9 @@ class PreferenceWindow (AbstractDialog):
@param linkbtn_fn: function to call to set the linkbutton behavior
@type linkbtn_fn: function(string)
@param tabpos_fn: function to call to set the tabposition of the notebooks
- @type tabpos_fn: function(gtk.ComboBox,int)"""
+ @type tabpos_fn: function(gtk.ComboBox,int)
+ @param catmodel_fn: function to call to set the model of the cat list (collapsed/not collapsed)
+ @type catmodel_fn: function()"""
AbstractDialog.__init__(self, parent)
@@ -79,6 +82,7 @@ class PreferenceWindow (AbstractDialog):
self.console_fn = console_fn
self.linkbtn_fn = linkbtn_fn
self.tabpos_fn = tabpos_fn
+ self.catmodel_fn = catmodel_fn
# set the bg-color of the hint
hintEB = self.tree.get_widget("hintEB")
@@ -106,6 +110,10 @@ class PreferenceWindow (AbstractDialog):
self.consoleFontBtn = self.tree.get_widget("consoleFontBtn")
self.consoleFontBtn.set_font_name(self.cfg.get("consolefont", section = "GUI"))
+ # the console title length spin button
+ self.titleLengthSpinBtn = self.tree.get_widget("titleLengthSpinBtn")
+ self.titleLengthSpinBtn.set_value(int(self.cfg.get("titlelength", section = "GUI")))
+
# the comboboxes
self.systemTabCombo = self.tree.get_widget("systemTabCombo")
self.pkgTabCombo = self.tree.get_widget("packageTabCombo")
@@ -140,6 +148,8 @@ class PreferenceWindow (AbstractDialog):
self.cfg.set("consolefont", font, section = "GUI")
self.console_fn(font)
+ self.cfg.set("titlelength", str(self.titleLengthSpinBtn.get_value_as_int()), section = "GUI")
+
pkgPos = self.pkgTabCombo.get_active()+1
sysPos = self.systemTabCombo.get_active()+1
@@ -150,6 +160,8 @@ class PreferenceWindow (AbstractDialog):
self.linkbtn_fn(self.cfg.get("browserCmd", section="GUI"))
+ self.catmodel_fn()
+
def cb_ok_clicked(self, button):
"""Saves, writes to config-file and closes the window."""
self._save()