summaryrefslogtreecommitdiff
path: root/portato/gui
diff options
context:
space:
mode:
Diffstat (limited to 'portato/gui')
-rw-r--r--portato/gui/__init__.py14
-rw-r--r--portato/gui/gtk/__init__.py13
-rw-r--r--portato/gui/gtk/dialogs.py66
-rw-r--r--portato/gui/gtk/glade/geneticone.glade1028
-rw-r--r--portato/gui/gtk/windows.py892
-rw-r--r--portato/gui/gtk/wrapper.py105
-rw-r--r--portato/gui/gui_helper.py608
-rw-r--r--portato/gui/wrapper.py184
8 files changed, 2910 insertions, 0 deletions
diff --git a/portato/gui/__init__.py b/portato/gui/__init__.py
new file mode 100644
index 0000000..6248ece
--- /dev/null
+++ b/portato/gui/__init__.py
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+#
+# File: portato/gui/__init__.py
+# This file is part of the Portato-Project, a graphical portage-frontend.
+#
+# Copyright (C) 2006 René 'Necoro' Neumann
+# This is free software. You may redistribute copies of it under the terms of
+# the GNU General Public License version 2.
+# There is NO WARRANTY, to the extent permitted by law.
+#
+# Written by René 'Necoro' Neumann <necoro@necoro.net>
+
+import gtk
+from gtk import *
diff --git a/portato/gui/gtk/__init__.py b/portato/gui/gtk/__init__.py
new file mode 100644
index 0000000..85938b4
--- /dev/null
+++ b/portato/gui/gtk/__init__.py
@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+#
+# File: portato/gui/gtk/__init__.py
+# This file is part of the Portato-Project, a graphical portage-frontend.
+#
+# Copyright (C) 2006 René 'Necoro' Neumann
+# This is free software. You may redistribute copies of it under the terms of
+# the GNU General Public License version 2.
+# There is NO WARRANTY, to the extent permitted by law.
+#
+# Written by René 'Necoro' Neumann <necoro@necoro.net>
+
+from windows import MainWindow
diff --git a/portato/gui/gtk/dialogs.py b/portato/gui/gtk/dialogs.py
new file mode 100644
index 0000000..68cd629
--- /dev/null
+++ b/portato/gui/gtk/dialogs.py
@@ -0,0 +1,66 @@
+# -*- coding: utf-8 -*-
+#
+# File: portato/gui/gtk/dialogs.py
+# This file is part of the Portato-Project, a graphical portage-frontend.
+#
+# Copyright (C) 2006 René 'Necoro' Neumann
+# This is free software. You may redistribute copies of it under the terms of
+# the GNU General Public License version 2.
+# There is NO WARRANTY, to the extent permitted by law.
+#
+# Written by René 'Necoro' Neumann <necoro@necoro.net>
+
+import gtk
+
+def io_ex_dialog (io_ex):
+ string = io_ex.strerror
+ if io_ex.filename:
+ string = string+": "+io_ex.filename
+
+ dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, string)
+ ret = dialog.run()
+ dialog.destroy()
+ return ret
+
+def blocked_dialog (blocked, blocks):
+ dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, blocked+" is blocked by "+blocks+".\nPlease unmerge the blocking package.")
+ ret = dialog.run()
+ dialog.destroy()
+ return ret
+
+def not_root_dialog ():
+ errorMB = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, "You are not root.")
+ ret = errorMB.run()
+ errorMB.destroy()
+ return ret
+
+def unmask_dialog (cpv):
+ dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, cpv+" seems to be masked.\nDo you want to unmask it and its dependencies?.\n")
+ ret = dialog.run()
+ dialog.destroy()
+ return ret
+
+def nothing_found_dialog ():
+ dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, "Package not found!")
+ ret = dialog.run()
+ dialog.destroy()
+ return ret
+
+def changed_flags_dialog (what = "flags"):
+ hintMB = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK,
+ "You have changed %s. Portato will write these changes into the appropriate files. Please backup them if you think it is necessairy." % what)
+ ret = hintMB.run()
+ hintMB.destroy()
+ return ret
+
+def remove_deps_dialog ():
+ infoMB = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, "You cannot remove dependencies. :)")
+ ret = infoMB.run()
+ infoMB.destroy()
+ return ret
+
+def remove_queue_dialog ():
+ askMB = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, "Do you really want to clear the whole queue?")
+ ret = askMB.run()
+ askMB.destroy()
+ return ret
diff --git a/portato/gui/gtk/glade/geneticone.glade b/portato/gui/gtk/glade/geneticone.glade
new file mode 100644
index 0000000..cf187c7
--- /dev/null
+++ b/portato/gui/gtk/glade/geneticone.glade
@@ -0,0 +1,1028 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--*- mode: xml -*-->
+<glade-interface>
+ <widget class="GtkWindow" id="MainWindow">
+ <property name="border_width">2</property>
+ <property name="window_position">GTK_WIN_POS_CENTER</property>
+ <signal name="destroy" handler="cb_destroy"/>
+ <child>
+ <widget class="GtkVBox" id="mainVB">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkMenuBar" id="menubar">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkMenuItem" id="fileMenu">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_File</property>
+ <property name="use_underline">True</property>
+ <child>
+ <widget class="GtkMenu" id="menu1">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkMenuItem" id="prefItem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Preferences</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="cb_preferences_clicked"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="reloadItem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Reload Portage</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="cb_reload_clicked"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separatormenuitem1">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="closeItem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Close</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="cb_destroy"/>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="emergeMenu">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Emerge</property>
+ <property name="use_underline">True</property>
+ <child>
+ <widget class="GtkMenu" id="menu2">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkMenuItem" id="emergeItem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Emerge</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="cb_emerge_clicked"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="unmergeItem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Unmerge</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="cb_unmerge_clicked"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="updateItem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Update _World</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="cb_update_clicked"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="syncItem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Sync</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="cb_sync_clicked"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="saveFlagsItem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Save _Flags</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="cb_save_flags_clicked"/>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="helpMenu">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_?</property>
+ <property name="use_underline">True</property>
+ <child>
+ <widget class="GtkMenu" id="menu3">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkMenuItem" id="aboutItem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_About</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="cb_about_clicked"/>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="searchHB">
+ <property name="visible">True</property>
+ <property name="border_width">3</property>
+ <child>
+ <widget class="GtkEntry" id="searchEntry">
+ <property name="visible">True</property>
+ <signal name="activate" handler="cb_search_clicked" object="searchEntry"/>
+ </widget>
+ <packing>
+ <property name="padding">5</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="searchButton">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Search</property>
+ <property name="use_underline">True</property>
+ <signal name="clicked" handler="cb_search_clicked" object="searchEntry"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVPaned" id="vpaned">
+ <property name="visible">True</property>
+ <property name="position">300</property>
+ <child>
+ <widget class="GtkFrame" id="listFrame">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <widget class="GtkHBox" id="listHB">
+ <property name="visible">True</property>
+ <property name="spacing">5</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <widget class="GtkScrolledWindow" id="catScroll">
+ <property name="visible">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <child>
+ <widget class="GtkTreeView" id="catList">
+ <property name="visible">True</property>
+ <property name="search_column">0</property>
+ <signal name="cursor_changed" handler="cb_cat_list_selection"/>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="pkgScroll">
+ <property name="visible">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <child>
+ <widget class="GtkTreeView" id="pkgList">
+ <property name="visible">True</property>
+ <property name="search_column">0</property>
+ <signal name="cursor_changed" handler="cb_pkg_list_selection"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <placeholder/>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="resize">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkNotebook" id="notebook">
+ <property name="visible">True</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <widget class="GtkTable" id="PackageTable">
+ <property name="visible">True</property>
+ <property name="n_rows">4</property>
+ <property name="n_columns">2</property>
+ <child>
+ <widget class="GtkHBox" id="checkHB">
+ <property name="visible">True</property>
+ <property name="spacing">1</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <widget class="GtkCheckButton" id="installedCheck">
+ <property name="visible">True</property>
+ <property name="no_show_all">True</property>
+ <property name="label" translatable="yes">Installed</property>
+ <property name="draw_indicator">True</property>
+ <signal name="button_press_event" handler="cb_button_pressed"/>
+ </widget>
+ <packing>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkCheckButton" id="maskedCheck">
+ <property name="visible">True</property>
+ <property name="no_show_all">True</property>
+ <property name="label" translatable="yes">Masked</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="cb_masked_toggled"/>
+ </widget>
+ <packing>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkCheckButton" id="testingCheck">
+ <property name="visible">True</property>
+ <property name="no_show_all">True</property>
+ <property name="label" translatable="yes">Testing</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="cb_testing_toggled"/>
+ </widget>
+ <packing>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </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">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHButtonBox" id="buttonBB">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <property name="layout_style">GTK_BUTTONBOX_SPREAD</property>
+ <child>
+ <widget class="GtkButton" id="pkgEmergeBtn">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Emerge</property>
+ <property name="use_underline">True</property>
+ <signal name="clicked" handler="cb_package_emerge_clicked"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkButton" id="pkgUnmergeBtn">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Unmerge</property>
+ <property name="use_underline">True</property>
+ <signal name="clicked" handler="cb_package_unmerge_clicked"/>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="pkgRevertBtn">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Re_vert</property>
+ <property name="use_underline">True</property>
+ <signal name="clicked" handler="cb_package_revert_clicked"/>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="right_attach">2</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="notInSysLabel">
+ <property name="visible">True</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>
+ </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">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="missingLabel">
+ <property name="visible">True</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">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="descLabel">
+ <property name="visible">True</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">True</property>
+ </widget>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ <property name="y_padding">10</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="comboVB">
+ <property name="visible">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options">GTK_FILL</property>
+ <property name="x_padding">5</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="useListScroll">
+ <property name="visible">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <child>
+ <widget class="GtkTreeView" id="useList">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_padding">5</property>
+ <property name="y_padding">5</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Package</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="queueHB">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkScrolledWindow" id="queueScroll">
+ <property name="visible">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <child>
+ <widget class="GtkTreeView" id="queueList">
+ <property name="visible">True</property>
+ <property name="headers_visible">False</property>
+ <property name="enable_search">False</property>
+ <signal name="button_press_event" handler="cb_queue_right_click"/>
+ <signal name="row_activated" handler="cb_row_activated"/>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkVButtonBox" id="queueBB">
+ <property name="visible">True</property>
+ <property name="homogeneous">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_SPREAD</property>
+ <child>
+ <widget class="GtkButton" id="emergeBtn">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">E_merge</property>
+ <property name="use_underline">True</property>
+ <signal name="clicked" handler="cb_emerge_clicked"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkButton" id="unmergeBtn">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Unmerge</property>
+ <property name="use_underline">True</property>
+ <signal name="clicked" handler="cb_unmerge_clicked"/>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="updateBtn">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Update _World</property>
+ <property name="use_underline">True</property>
+ <signal name="clicked" handler="cb_update_clicked"/>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="removeBtn">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Remove</property>
+ <property name="use_underline">True</property>
+ <signal name="clicked" handler="cb_remove_clicked"/>
+ </widget>
+ <packing>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">5</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ <property name="tab_expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Queue</property>
+ <property name="single_line_mode">True</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ <property name="position">1</property>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="termHB">
+ <property name="visible">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ <property name="tab_expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Console</property>
+ <property name="single_line_mode">True</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ <property name="position">2</property>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkAlignment" id="alignment4">
+ <property name="visible">True</property>
+ <property name="top_padding">5</property>
+ <child>
+ <widget class="GtkLabel" id="statusLabel">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="label" translatable="yes">Portato - A Portage GUI</property>
+ <property name="single_line_mode">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <widget class="GtkWindow" id="AboutWindow">
+ <property name="title" translatable="yes">About</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="default_width">1</property>
+ <property name="default_height">1</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="skip_taskbar_hint">True</property>
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkLabel" id="aboutLabel">
+ <property name="visible">True</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkButton" id="okBtn">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_OK</property>
+ <property name="use_underline">True</property>
+ <signal name="clicked" handler="close"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <widget class="GtkWindow" id="SearchWindow">
+ <property name="title" translatable="yes">Search</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="default_width">1</property>
+ <property name="default_height">1</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="skip_taskbar_hint">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <widget class="GtkWindow" id="PreferenceWindow">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Preferences</property>
+ <property name="modal">True</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="skip_taskbar_hint">True</property>
+ <child>
+ <widget class="GtkVBox" id="mainVB">
+ <property name="visible">True</property>
+ <property name="spacing">5</property>
+ <child>
+ <widget class="GtkFrame" id="generalFrame">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="left_padding">12</property>
+ <child>
+ <widget class="GtkCheckButton" id="debugCheck">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Debug</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;General Options&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkFrame" id="syncFrame">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment5">
+ <property name="visible">True</property>
+ <property name="bottom_padding">5</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">5</property>
+ <child>
+ <widget class="GtkHBox" id="syncHB">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkLabel" id="syncLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Sync command: </property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="syncCommandEdit">
+ <property name="visible">True</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Sync Options&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkFrame" id="updateFrame">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment2">
+ <property name="visible">True</property>
+ <property name="left_padding">12</property>
+ <child>
+ <widget class="GtkVBox" id="updateVB">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkCheckButton" id="deepCheck">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">--deep</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkCheckButton" id="newUseCheck">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">--newuse</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Update World Options&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkFrame" id="keywordFrame">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment3">
+ <property name="visible">True</property>
+ <property name="bottom_padding">5</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">5</property>
+ <child>
+ <widget class="GtkTable" id="keywordTable">
+ <property name="visible">True</property>
+ <property name="n_rows">10</property>
+ <property name="n_columns">2</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="useFileEdit">
+ <property name="visible">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>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="useEditLabel">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">File name to use, if package.use is a directory: </property>
+ <property name="single_line_mode">True</property>
+ </widget>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkCheckButton" id="usePerVersionCheck">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Add only exact version to package.use</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkCheckButton" id="testPerVersionCheck">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Add only exact version to package.keywords</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="testEditLabel">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">File name to use, if package.keywords is a directory: </property>
+ <property name="single_line_mode">True</property>
+ </widget>
+ <packing>
+ <property name="top_attach">6</property>
+ <property name="bottom_attach">7</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="testFileEdit">
+ <property name="visible">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">6</property>
+ <property name="bottom_attach">7</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="maskFileEdit">
+ <property name="visible">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">9</property>
+ <property name="bottom_attach">10</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="maskEditLabel">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">File name to use, if package.mask/package.unmask is a directory: </property>
+ <property name="single_line_mode">True</property>
+ </widget>
+ <packing>
+ <property name="top_attach">9</property>
+ <property name="bottom_attach">10</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkCheckButton" id="maskPerVersionCheck">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Add only exact version to package.mask/package.unmask</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="top_attach">8</property>
+ <property name="bottom_attach">9</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEventBox" id="hintEB">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkFrame" id="hintFrame">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">GTK_SHADOW_OUT</property>
+ <child>
+ <widget class="GtkLabel" id="hintLabel">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">&lt;u&gt;You may use the following placeholders:&lt;/u&gt;
+
+&lt;i&gt;$(cat)&lt;/i&gt;: category
+&lt;i&gt;$(pkg)&lt;/i&gt;: package name
+&lt;i&gt;$(cat-1)/$(cat-2)&lt;/i&gt;: first/second part of the category</property>
+ <property name="use_markup">True</property>
+ </widget>
+ </child>
+ <child>
+ <placeholder/>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="useLabel">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="xpad">5</property>
+ <property name="label" translatable="yes">&lt;u&gt;&lt;i&gt;Use-Flags&lt;/i&gt;&lt;/u&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="y_padding">6</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="testLabel">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="xpad">5</property>
+ <property name="label" translatable="yes">&lt;u&gt;&lt;i&gt;Testing Keywords&lt;/i&gt;&lt;/u&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="y_padding">5</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="maskLabel">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="xpad">5</property>
+ <property name="label" translatable="yes">&lt;u&gt;&lt;i&gt;Masking Keywords&lt;/i&gt;&lt;/u&gt;</property>
+ <property name="use_markup">True</property>
+ <property name="single_line_mode">True</property>
+ </widget>
+ <packing>
+ <property name="top_attach">7</property>
+ <property name="bottom_attach">8</property>
+ <property name="y_padding">5</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Use Flag and Keyword Options&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHButtonBox" id="buttonBox">
+ <property name="visible">True</property>
+ <property name="homogeneous">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_SPREAD</property>
+ <child>
+ <widget class="GtkButton" id="okBtn">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_OK</property>
+ <property name="use_underline">True</property>
+ <signal name="clicked" handler="cb_ok_clicked"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkButton" id="cancelBtn">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Cancel</property>
+ <property name="use_underline">True</property>
+ <signal name="clicked" handler="cb_cancel_clicked"/>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <widget class="GtkMenu" id="queuePopup">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkMenuItem" id="oneShotItem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">oneshot</property>
+ <signal name="activate" handler="cb_oneshot_clicked"/>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
diff --git a/portato/gui/gtk/windows.py b/portato/gui/gtk/windows.py
new file mode 100644
index 0000000..f4a37fe
--- /dev/null
+++ b/portato/gui/gtk/windows.py
@@ -0,0 +1,892 @@
+# -*- coding: utf-8 -*-
+#
+# File: portato/gui/gtk/windows.py
+# This file is part of the Portato-Project, a graphical portage-frontend.
+#
+# Copyright (C) 2006 René 'Necoro' Neumann
+# This is free software. You may redistribute copies of it under the terms of
+# the GNU General Public License version 2.
+# There is NO WARRANTY, to the extent permitted by law.
+#
+# Written by René 'Necoro' Neumann <necoro@necoro.net>
+
+# gtk stuff
+import pygtk
+pygtk.require("2.0")
+import gtk
+import gtk.glade
+import gobject
+
+#our backend stuff
+from portato.helper import *
+from portato.constants import CONFIG_LOCATION, VERSION, DATA_DIR
+from portato import backend
+from portato.backend import flags
+from portato.backend.exceptions import *
+
+# more GUI stuff
+from portato.gui.gui_helper import Database, Config, EmergeQueue
+from dialogs import *
+from wrapper import GtkTree, GtkConsole
+
+# for the terminal
+import vte
+
+# other
+from portage_util import unique_array
+
+class Window:
+ def __init__ (self):
+ self.tree = gtk.glade.XML(DATA_DIR+"portato.glade", root = self.__class__.__name__)
+ self.tree.signal_autoconnect(self)
+ self.window = self.tree.get_widget(self.__class__.__name__)
+
+ @staticmethod
+ def watch_cursor (func):
+ """This is a decorator for functions being so time consuming, that it is appropriate to show the watch-cursor.
+ @attention: this function relies on the gtk.Window-Object being stored as self.window"""
+ def wrapper (self, *args, **kwargs):
+ ret = None
+ def cb_idle():
+ try:
+ ret = func(self, *args, **kwargs)
+ finally:
+ self.window.window.set_cursor(None)
+ return False
+
+ watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
+ self.window.window.set_cursor(watch)
+ gobject.idle_add(cb_idle)
+ return ret
+ return wrapper
+
+class AbstractDialog (Window):
+ """A class all our dialogs get derived from. It sets useful default vars and automatically handles the ESC-Button."""
+
+ def __init__ (self, parent):
+ """Constructor.
+
+ @param parent: the parent window
+ @type parent: gtk.Window"""
+
+ Window.__init__(self)
+
+ # set parent
+ self.window.set_transient_for(parent)
+
+ # catch the ESC-key
+ self.window.connect("key-press-event", self.cb_key_pressed)
+
+ def cb_key_pressed (self, widget, event):
+ """Closes the window if ESC is pressed."""
+ keyname = gtk.gdk.keyval_name(event.keyval)
+ if keyname == "Escape":
+ self.close()
+ return True
+ else:
+ return False
+
+ def close (self, *args):
+ self.window.destroy()
+
+class AboutWindow (AbstractDialog):
+ """A window showing the "about"-informations."""
+
+ def __init__ (self, parent):
+ """Constructor.
+
+ @param parent: the parent window
+ @type parent: gtk.Window"""
+
+ AbstractDialog.__init__(self, parent)
+
+ label = self.tree.get_widget("aboutLabel")
+ label.set_markup("""
+<big><b>Portato v.%s</b></big>
+A Portage-GUI
+
+This software is licensed under the terms of the GPLv2.
+Copyright (C) 2006 René 'Necoro' Neumann &lt;necoro@necoro.net&gt;
+
+<small>Thanks to Fred for support and ideas :P</small>
+""" % VERSION)
+
+ self.window.show_all()
+
+class SearchWindow (AbstractDialog):
+ """A window showing the results of a search process."""
+
+ def __init__ (self, parent, list, jump_to):
+ """Constructor.
+
+ @param parent: parent-window
+ @type parent: gtk.Window
+ @param list: list of results to show
+ @type list: string[]
+ @param jump_to: function to call if "OK"-Button is hit
+ @type jump_to: function(string)"""
+
+ AbstractDialog.__init__(self, parent)
+
+ self.list = list # list to show
+ self.jump_to = jump_to # function to call for jumping
+
+ # combo box
+ self.combo = gtk.combo_box_new_text()
+ for x in list:
+ self.combo.append_text(x)
+ self.combo.set_active(0) # first item
+ self.combo.connect("key-press-event", self.cb_key_pressed_combo)
+
+ self.window.add(self.combo)
+
+ # finished --> show
+ self.window.show_all()
+
+ def cb_key_pressed_combo (self, widget, event):
+ """Emulates a ok-button-click."""
+ keyname = gtk.gdk.keyval_name(event.keyval)
+ if keyname == "Return": # take it as an "OK" if Enter is pressed
+ self.window.destroy()
+ self.jump_to(self.list[self.combo.get_active()])
+ return True
+ else:
+ return False
+
+class PreferenceWindow (AbstractDialog):
+ """Window displaying some preferences."""
+
+ # all checkboxes in the window
+ # widget name -> option name
+ checkboxes = {
+ "debugCheck" : "debug_opt",
+ "deepCheck" : "deep_opt",
+ "newUseCheck" : "newuse_opt",
+ "maskPerVersionCheck" : "maskPerVersion_opt",
+ "usePerVersionCheck" : "usePerVersion_opt",
+ "testPerVersionCheck" : "testingPerVersion_opt"
+ }
+
+ # all edits in the window
+ # widget name -> option name
+ edits = {
+ "maskFileEdit" : "maskFile_opt",
+ "testFileEdit" : "testingFile_opt",
+ "useFileEdit" : "useFile_opt",
+ "syncCommandEdit" : "syncCmd_opt"
+ }
+
+ def __init__ (self, parent, cfg):
+ """Constructor.
+
+ @param parent: parent window
+ @type parent: gtk.Window
+ @param cfg: configuration object
+ @type cfg: gui_helper.Config"""
+
+ AbstractDialog.__init__(self, parent)
+
+ # our config
+ self.cfg = cfg
+
+ # set the bg-color of the hint
+ hintEB = self.tree.get_widget("hintEB")
+ hintEB.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#f3f785"))
+
+ for box in self.checkboxes:
+ self.tree.get_widget(box).\
+ set_active(self.cfg.get_boolean(self.checkboxes[box]))
+
+ for edit in self.edits:
+ self.tree.get_widget(edit).\
+ set_text(self.cfg.get(self.edits[edit]))
+
+ self.window.show_all()
+
+ def _save(self):
+ """Sets all options in the Config-instance."""
+
+ for box in self.checkboxes:
+ self.cfg.set_boolean(self.checkboxes[box], self.tree.get_widget(box).get_active())
+
+ for edit in self.edits:
+ self.cfg.set(self.edits[edit],self.tree.get_widget(edit).get_text())
+
+ def cb_ok_clicked(self, button):
+ """Saves, writes to config-file and closes the window."""
+ self._save()
+ try:
+ self.cfg.write()
+ except IOError, e:
+ io_ex_dialog(e)
+
+ self.window.destroy()
+
+ def cb_cancel_clicked (self, button):
+ """Just closes - w/o saving."""
+ self.window.destroy()
+
+class PackageTable:
+ """A window with data about a specfic package."""
+
+ def __init__ (self, main):
+ """Build up window contents.
+
+ @param main: the main window
+ @type main: MainWindow"""
+
+ self.main = main
+ self.tree = main.tree
+ self.window = main.window
+ self.tree.signal_autoconnect(self)
+
+ # the table
+ self.table = self.tree.get_widget("PackageTable")
+
+ # chechboxes
+ self.installedCheck = self.tree.get_widget("installedCheck")
+ self.maskedCheck = self.tree.get_widget("maskedCheck")
+ self.testingCheck = self.tree.get_widget("testingCheck")
+
+ # labels
+ self.notInSysLabel = self.tree.get_widget("notInSysLabel")
+ self.missingLabel = self.tree.get_widget("missingLabel")
+
+ # buttons
+ self.emergeBtn = self.tree.get_widget("pkgEmergeBtn")
+ self.unmergeBtn = self.tree.get_widget("pkgUnmergeBtn")
+ self.cancelBtn = self.tree.get_widget("pkgCancelBtn")
+
+ # useList
+ self.useListScroll = self.tree.get_widget("useListScroll")
+ self.useList = None
+
+ def update (self, cp, queue = None, version = None, doEmerge = True, instantChange = False):
+ """Updates the table to show the contents for the package.
+
+ @param cp: the selected package
+ @type cp: string (cp)
+ @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: False
+ @param instantChange: if True the changed keywords are updated instantly
+ @type instantChange: boolean"""
+
+ self.cp = cp # category/package
+ self.version = version # version - if not None this is used
+ self.queue = queue
+ self.doEmerge = doEmerge
+ self.instantChange = instantChange
+
+ # packages and installed packages
+ self.packages = backend.sort_package_list(backend.get_all_versions(cp))
+ self.instPackages = backend.sort_package_list(backend.get_all_installed_versions(cp))
+
+ # version-combo-box
+ self.vCombo = self.build_vers_combo()
+ if not self.doEmerge: self.vCombo.set_sensitive(False)
+ vb = self.tree.get_widget("comboVB")
+ children = vb.get_children()
+ if children:
+ for c in children: vb.remove(c)
+ vb.pack_start(self.vCombo)
+
+ # the label (must be here, because it depends on the combo box)
+ desc = self.actual_package().get_env_var("DESCRIPTION").replace("&","&amp;")
+ if not desc:
+ desc = "<no description>"
+ use_markup = False
+ else:
+ desc = "<b>"+desc+"</b>"
+ use_markup = True
+ desc = "<i><u>"+self.actual_package().get_cp()+"</u></i>\n\n"+desc
+ self.descLabel = self.tree.get_widget("descLabel")
+ self.descLabel.set_use_markup(use_markup)
+ self.descLabel.set_label(desc)
+
+ if not self.queue or not self.doEmerge:
+ self.emergeBtn.set_sensitive(False)
+ self.unmergeBtn.set_sensitive(False)
+
+ # current status
+ self.cb_combo_changed(self.vCombo)
+ self.table.show_all()
+
+ def fill_use_list(self, store):
+ """Fills a given ListStore with the use-flag data.
+
+ @param store: the store to fill
+ @type store: gtk.ListStore"""
+
+ pkg = self.actual_package()
+ pkg_flags = pkg.get_all_use_flags()
+ pkg_flags.sort()
+ for use in pkg_flags:
+ if pkg.is_installed() and use in pkg.get_actual_use_flags(): # flags set during install
+ enabled = True
+ elif (not pkg.is_installed()) and use in pkg.get_settings("USE").split() and not flags.invert_use_flag(use) in pkg.get_new_use_flags(): # flags that would be set
+ enabled = True
+ elif use in pkg.get_new_use_flags():
+ enabled = True
+ else:
+ enabled = False
+ store.append([enabled, use, backend.get_use_desc(use, self.cp)])
+
+ return store
+
+ def build_use_list (self):
+ """Builds the useList."""
+ store = gtk.ListStore(bool, str, str)
+ self.fill_use_list(store)
+
+ # build view
+ view = gtk.TreeView(store)
+ cell = gtk.CellRendererText()
+ tCell = gtk.CellRendererToggle()
+ tCell.set_property("activatable", True)
+ tCell.connect("toggled", self.cb_use_flag_toggled, store)
+ view.append_column(gtk.TreeViewColumn("Enabled", tCell, active = 0))
+ view.append_column(gtk.TreeViewColumn("Flags", cell, text = 1))
+ view.append_column(gtk.TreeViewColumn("Description", cell, text = 2))
+
+ if store.iter_n_children(None) == 0: # if there are no nodes in the list ...
+ view.set_child_visible(False) # ... do not show the list
+ else:
+ view.set_child_visible(True)
+ return view
+
+ def build_vers_combo (self):
+ """Creates the combo box with the different versions."""
+ combo = gtk.combo_box_new_text()
+
+ # append versions
+ for s in [x.get_version() for x in self.packages]:
+ combo.append_text(s)
+
+ # activate the first one
+ try:
+ best_version = ""
+ if self.version:
+ best_version = self.version
+ else:
+ best_version = backend.find_best_match(self.packages[0].get_cp(), (self.instPackages != [])).get_version()
+ for i in range(len(self.packages)):
+ if self.packages[i].get_version() == best_version:
+ combo.set_active(i)
+ break
+ except AttributeError: # no package found
+ debug('catched AttributeError => no "best package" found. Selected first one.')
+ combo.set_active(0)
+
+ combo.connect("changed", self.cb_combo_changed)
+
+ return combo
+
+ def actual_package (self):
+ """Returns the actual selected package.
+
+ @returns: the actual selected package
+ @rtype: backend.Package"""
+
+ return self.packages[self.vCombo.get_active()]
+
+ def _update_keywords (self, emerge, update = False):
+ if emerge:
+ try:
+ try:
+ self.queue.append(self.actual_package().get_cpv(), unmerge = False, update = update)
+ except backend.PackageNotFoundException, e:
+ if unmask_dialog(e[0]) == gtk.RESPONSE_YES:
+ self.queue.append(self.actual_package().get_cpv(), unmerge = False, unmask = True, update = update)
+ except BlockedException, e:
+ blocked_dialog(e[0], e[1])
+ else:
+ try:
+ self.queue.append(self.actual_package().get_cpv(), unmerge = True)
+ except backend.PackageNotFoundException, e:
+ masked_dialog(e[0])
+
+ def cb_combo_changed (self, combo):
+ """Callback for the changed ComboBox.
+ It then rebuilds the useList and the checkboxes."""
+
+ # remove old useList
+ w = self.useListScroll.get_child()
+ if w:
+ self.useListScroll.remove(w)
+
+ # build new
+ self.useList = self.build_use_list()
+ self.useListScroll.add(self.useList)
+ pkg = self.actual_package()
+
+ #
+ # rebuild the buttons and checkboxes in all the different manners which are possible
+ #
+ if (not pkg.is_in_system()) or pkg.is_missing_keyword():
+ if not pkg.is_in_system():
+ self.missingLabel.hide()
+ self.notInSysLabel.show()
+ else: # missing keyword
+ self.missingLabel.show()
+ self.notInSysLabel.hide()
+
+ self.installedCheck.hide()
+ self.maskedCheck.hide()
+ self.testingCheck.hide()
+ self.emergeBtn.set_sensitive(False)
+ else:
+ self.missingLabel.hide()
+ self.notInSysLabel.hide()
+ self.installedCheck.show()
+ self.maskedCheck.show()
+ self.testingCheck.show()
+ if self.doEmerge:
+ self.emergeBtn.set_sensitive(True)
+ self.installedCheck.set_active(pkg.is_installed())
+ self.maskedCheck.set_active(pkg.is_masked())
+ if pkg.is_testing(allowed = False) and not pkg.is_testing(allowed=True):
+ self.testingCheck.set_label("<i>(Testing)</i>")
+ self.testingCheck.get_child().set_use_markup(True)
+ else:
+ self.testingCheck.set_label("Testing")
+ self.testingCheck.set_active(pkg.is_testing(allowed = False))
+
+ if self.doEmerge:
+ # set emerge-button-label
+ if not self.actual_package().is_installed():
+ self.emergeBtn.set_label("_Emerge")
+ self.unmergeBtn.set_sensitive(False)
+ else:
+ self.emergeBtn.set_label("R_emerge")
+ self.unmergeBtn.set_sensitive(True)
+
+ self.table.show_all()
+
+ return True
+
+ def cb_button_pressed (self, b, event):
+ """Callback for pressed checkboxes. Just quits the event-loop - no redrawing."""
+ if not isinstance(b, gtk.CellRendererToggle):
+ b.emit_stop_by_name("button-press-event")
+ return True
+
+ def cb_package_revert_clicked (self, button):
+ """Callback for pressed cancel-button. Closes the window."""
+ self.actual_package().remove_new_use_flags()
+ self.actual_package().remove_new_masked()
+ self.actual_package().remove_new_testing()
+ self.cb_combo_changed(self.vCombo)
+ if self.instantChange:
+ self._update_keywords(True, update = True)
+ return True
+
+ def cb_package_emerge_clicked (self, button):
+ """Callback for pressed emerge-button. Adds the package to the EmergeQueue."""
+ if not am_i_root():
+ not_root_dialog()
+ else:
+ self._update_keywords(True)
+ self.main.notebook.set_current_page(self.main.QUEUE_PAGE)
+ return True
+
+ def cb_package_unmerge_clicked (self, button):
+ """Callback for pressed unmerge-button clicked. Adds the package to the UnmergeQueue."""
+ if not am_i_root():
+ not_root_dialog()
+ else:
+ self._update_keywords(False)
+ self.main.notebook.set_current_page(self.main.QUEUE_PAGE)
+ return True
+
+ def cb_testing_toggled (self, button):
+ """Callback for toggled testing-checkbox."""
+ status = button.get_active()
+
+ if self.actual_package().is_testing(allowed = False) == status:
+ return False
+
+ if not self.actual_package().is_testing(allowed = True):
+ self.actual_package().set_testing(False)
+ button.set_label("Testing")
+ button.set_active(True)
+ else:
+ self.actual_package().set_testing(True)
+ if self.actual_package().is_testing(allowed=False):
+ button.set_label("<i>(Testing)</i>")
+ button.get_child().set_use_markup(True)
+ button.set_active(True)
+
+ if self.instantChange:
+ self._update_keywords(True, update = True)
+
+ return True
+
+ def cb_masked_toggled (self, button):
+ """Callback for toggled masking-checkbox."""
+ status = button.get_active()
+ self.actual_package().set_masked(status)
+
+ if self.instantChange:
+ self._update_keywords(True, update = True)
+
+ return True
+
+ def cb_use_flag_toggled (self, cell, path, store):
+ """Callback for a toggled use-flag button."""
+ store[path][0] = not store[path][0]
+ prefix = ""
+ if not store[path][0]:
+ prefix = "-"
+ self.actual_package().set_use_flag(prefix+store[path][1])
+
+ if self.instantChange:
+ self._update_keywords(True, update = True)
+
+ return True
+
+class MainWindow (Window):
+ """Application main window."""
+
+ # NOTEBOOK PAGE CONSTANTS
+ PKG_PAGE = 0
+ QUEUE_PAGE = 1
+ CONSOLE_PAGE = 2
+
+ def __init__ (self):
+ """Build up window"""
+
+ # main window stuff
+ Window.__init__(self)
+ self.window.set_title(("Portato (%s)" % VERSION))
+ mHeight = 800
+ if gtk.gdk.screen_height() <= 800: mHeight = 600
+ self.window.set_geometry_hints (self.window, min_width = 600, min_height = mHeight, max_height = gtk.gdk.screen_height(), max_width = gtk.gdk.screen_width())
+
+ # booleans
+ self.doUpdate = False
+ self.packageInit = True
+
+ # package db
+ self.db = Database()
+ self.db.populate()
+
+ # config
+ try:
+ self.cfg = Config(CONFIG_LOCATION)
+ except IOError, e:
+ io_ex_dialog(e)
+ raise e
+
+ self.cfg.modify_external_configs()
+
+ # set vpaned position
+ vpaned = self.tree.get_widget("vpaned")
+ vpaned.set_position(mHeight/2)
+
+ # cat and pkg list
+ self.catList = self.tree.get_widget("catList")
+ self.pkgList = self.tree.get_widget("pkgList")
+ self.build_cat_list()
+ self.build_pkg_list()
+
+ # queue list
+ self.queueList = self.tree.get_widget("queueList")
+ self.build_queue_list()
+
+ # the terminal
+ term = vte.Terminal()
+ term.set_scrollback_lines(1024)
+ term.set_scroll_on_output(True)
+ term.set_font_from_string("Monospace 11")
+ # XXX why is this not working with the colors
+ term.set_color_background(gtk.gdk.color_parse("white"))
+ term.set_color_foreground(gtk.gdk.color_parse("black"))
+ termHB = self.tree.get_widget("termHB")
+ termScroll = gtk.VScrollbar(term.get_adjustment())
+ termHB.pack_start(term, True, True)
+ termHB.pack_start(termScroll, False)
+
+ # notebook
+ self.notebook = self.tree.get_widget("notebook")
+ self.window.show_all()
+
+ # table
+ self.packageTable = PackageTable(self)
+ self.packageTable.table.hide_all()
+
+ # popup
+ popupTree = gtk.glade.XML(DATA_DIR+"portato.glade", root = "queuePopup")
+ popupTree.signal_autoconnect(self)
+ self.queuePopup = popupTree.get_widget("queuePopup")
+
+ # set emerge queue
+ self.queueTree = GtkTree(self.queueList.get_model())
+ self.queue = EmergeQueue(console = GtkConsole(term), tree = self.queueTree, db = self.db)
+
+ def show_package (self, *args, **kwargs):
+ self.packageTable.update(*args, **kwargs)
+ self.notebook.set_current_page(self.PKG_PAGE)
+
+ def build_queue_list (self):
+ """Builds the queue list."""
+
+ store = gtk.TreeStore(str,str)
+
+ self.queueList.set_model(store)
+
+ cell = gtk.CellRendererText()
+ col = gtk.TreeViewColumn("Queue", cell, text = 0)
+ self.queueList.append_column(col)
+
+ col = gtk.TreeViewColumn("Options", cell, markup = 1)
+ self.queueList.append_column(col)
+
+ def build_cat_list (self):
+ """Builds the category list."""
+
+ store = gtk.ListStore(str)
+
+ # build categories
+ for p in backend.list_categories():
+ store.append([p])
+ # sort them alphabetically
+ store.set_sort_column_id(0, gtk.SORT_ASCENDING)
+
+ self.catList.set_model(store)
+ cell = gtk.CellRendererText()
+ col = gtk.TreeViewColumn("Categories", cell, text = 0)
+ self.catList.append_column(col)
+
+ def build_pkg_list (self, name = None):
+ """Builds the package list.
+
+ @param name: name of the selected catetegory
+ @type name: string"""
+
+ store = gtk.ListStore(str)
+ self.fill_pkg_store(store,name)
+
+ # build view
+ self.pkgList.set_model(store)
+ cell = gtk.CellRendererText()
+ col = gtk.TreeViewColumn("Packages", cell, text = 0)
+ self.pkgList.append_column(col)
+
+ def fill_pkg_store (self, store, name = None):
+ """Fills a given ListStore with the packages in a category.
+
+ @param store: the store to fill
+ @type store: gtk.ListStore
+ @param name: the name of the category
+ @type name: string
+ @returns: the filled store
+ @rtype: gtk.ListStore"""
+
+ if name:
+ for p in self.db.get_cat(name):
+ store.append([p])
+ return store
+
+ def jump_to (self, cp):
+ """Is called when we want to jump to a specific package."""
+ self.show_package(cp, self.queue)
+
+ def cb_cat_list_selection (self, view):
+ """Callback for a category-list selection. Updates the package list with the packages in the category."""
+ # get the selected category
+ sel = view.get_selection()
+ store, it = sel.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)
+ return True
+
+ def cb_pkg_list_selection (self, view):
+ """Callback for a package-list selection. Updates the package info."""
+ sel = view.get_selection()
+ store, it = sel.get_selected()
+ if it:
+ package = store.get_value(it, 0)
+ if package[-1] == '*': package = package[:-1]
+ self.show_package(self.selCatName+"/"+package, self.queue)
+ return True
+
+ def cb_row_activated (self, view, path, *args):
+ """Callback for an activated row in the emergeQueue. Opens a package window."""
+ store = self.queueTree
+ if len(path) > 1:
+ iterator = store.get_original().get_iter(path)
+ if store.is_in_emerge(iterator):
+ package = store.get_value(iterator, 0)
+ cat, name, vers, rev = backend.split_package_name(package)
+ if rev != "r0": vers = vers+"-"+rev
+ self.show_package(cat+"/"+name, queue = self.queue, version = vers, instantChange = True, doEmerge = False)
+ return True
+
+ def cb_emerge_clicked (self, action):
+ """Do emerge."""
+
+ self.notebook.set_current_page(self.CONSOLE_PAGE)
+
+ if len(flags.newUseFlags) > 0:
+ changed_flags_dialog("use flags")
+ flags.write_use_flags()
+
+ if len(flags.new_masked)>0 or len(flags.new_unmasked)>0 or len(flags.newTesting)>0:
+ debug("new masked:",flags.new_masked)
+ debug("new unmasked:", flags.new_unmasked)
+ debug("new testing:", flags.newTesting)
+ changed_flags_dialog("masking keywords")
+ flags.write_masked()
+ flags.write_testing()
+ backend.reload_settings()
+
+ if not self.doUpdate:
+ self.queue.emerge(force=True)
+ else:
+ self.queue.update_world(force=True, newuse = self.cfg.get_boolean("newuse_opt"), deep = self.cfg.get_boolean("deep_opt"))
+ self.doUpdate = False
+
+ def cb_unmerge_clicked (self, button):
+ """Do unmerge."""
+
+ self.notebook.set_current_page(self.CONSOLE_PAGE)
+ self.queue.unmerge(force=True)
+ return True
+
+ @Window.watch_cursor
+ def cb_update_clicked (self, action):
+ if not backend.am_i_root():
+ not_root_dialog()
+
+ else:
+ updating = backend.update_world(newuse = self.cfg.get_boolean("newuse_opt"), deep = self.cfg.get_boolean("deep_opt"))
+
+ debug("updating list:", [(x.get_cpv(), y.get_cpv()) for x,y in updating])
+ try:
+ for pkg, old_pkg in updating:
+ self.queue.append(pkg.get_cpv())
+ except BlockedException, e:
+ blocked_dialog(e[0], e[1])
+ if len(updating): self.doUpdate = True
+ return True
+
+ def cb_remove_clicked (self, button):
+ """Removes a selected item in the (un)emerge-queue if possible."""
+ selected = self.queueList.get_selection()
+
+ if selected:
+ model, iter = selected.get_selected()
+
+ if iter == None: return False
+
+ if not model.iter_parent(iter): # top-level
+ if model.iter_n_children(iter) > 0: # and has children which can be removed :)
+ if remove_queue_dialog() == gtk.RESPONSE_YES :
+ self.queue.remove_children(iter)
+ self.doUpdate = False
+
+ elif model.iter_parent(model.iter_parent(iter)): # this is in the 3rd level => dependency
+ remove_deps_dialog()
+ else:
+ self.queue.remove_children(iter) # remove children first
+ self.queue.remove(iter)
+ self.doUpdate = False
+
+ return True
+
+ def cb_sync_clicked (self, action):
+ if not backend.am_i_root():
+ not_root_dialog()
+ else:
+ self.notebook.set_current_page(self.CONSOLE_PAGE)
+ cmd = self.cfg.get("syncCmd_opt")
+
+ if cmd != "emerge --sync":
+ cmd = cmd.split()
+ self.queue.sync(cmd)
+ else:
+ self.queue.sync()
+
+ def cb_save_flags_clicked (self, action):
+ if not backend.am_i_root():
+ not_root_dialog()
+ else:
+ flags.write_use_flags()
+ flags.write_testing()
+ flags.write_masked()
+
+ @Window.watch_cursor
+ def cb_reload_clicked (self, action):
+ """Reloads the portage settings and the database."""
+ backend.reload_settings()
+ del self.db
+ self.db = Database()
+ self.db.populate()
+
+ @Window.watch_cursor
+ def cb_search_clicked (self, entry):
+ """Do a search."""
+ if entry.get_text() != "":
+ packages = backend.find_all_packages(entry.get_text(), withVersion = False)
+
+ if packages == []:
+ nothing_found_dialog()
+ else:
+ if len(packages) == 1:
+ self.jump_to(packages[0])
+ else:
+ SearchWindow(self.window, packages, self.jump_to)
+
+ def cb_preferences_clicked (self, button):
+ PreferenceWindow(self.window, self.cfg)
+ return True
+
+ def cb_about_clicked (self, button):
+ AboutWindow(self.window)
+ return True
+
+ def cb_queue_right_click (self, queue, event):
+ if event.button == 3:
+ x = int(event.x)
+ y = int(event.y)
+ time = event.time
+ pthinfo = queue.get_path_at_pos(x, y)
+ if pthinfo is not None:
+ path, col, cellx, celly = pthinfo
+ if self.queueTree.is_in_emerge(self.queueTree.get_original().get_iter(path)):
+ queue.grab_focus()
+ queue.set_cursor(path, col, 0)
+ self.queuePopup.popup(None, None, None, event.button, time)
+ return True
+ else:
+ return False
+
+ def cb_oneshot_clicked (self, action):
+ sel = self.queueList.get_selection()
+ store, it = sel.get_selected()
+ if it:
+ package = store.get_value(it, 0)
+ if not self.cfg.get_local(package, "oneshot_opt"):
+ set = True
+ else:
+ set = False
+
+ self.cfg.set_local(package, "oneshot_opt", set)
+ self.queue.append(package, update = True, oneshot = set, forceUpdate = True)
+
+ def cb_destroy (self, widget):
+ """Calls main_quit()."""
+ gtk.main_quit()
+
+ def main (self):
+ """Main."""
+ gobject.threads_init()
+ # now subthreads can run normally, but are not allowed to touch the GUI. If threads should change sth there - use gobject.idle_add().
+ # for more informations on threading and gtk: http://www.async.com.br/faq/pygtk/index.py?req=show&file=faq20.006.htp
+ gtk.main()
diff --git a/portato/gui/gtk/wrapper.py b/portato/gui/gtk/wrapper.py
new file mode 100644
index 0000000..7066acb
--- /dev/null
+++ b/portato/gui/gtk/wrapper.py
@@ -0,0 +1,105 @@
+# -*- coding: utf-8 -*-
+#
+# File: portato/gui/gtk/wrapper.py
+# This file is part of the Portato-Project, a graphical portage-frontend.
+#
+# Copyright (C) 2006 René 'Necoro' Neumann
+# This is free software. You may redistribute copies of it under the terms of
+# the GNU General Public License version 2.
+# There is NO WARRANTY, to the extent permitted by law.
+#
+# Written by René 'Necoro' Neumann <necoro@necoro.net>
+
+from portato.gui.wrapper import Tree, Console
+
+class GtkTree (Tree):
+ """The implementation of the abstract tree."""
+
+ def __init__ (self, tree, col = 0):
+ """Constructor.
+
+ @param tree: original tree
+ @type tree: gtk.TreeStore
+ @param col: the column where the cpv is stored
+ @type col: int"""
+
+ self.tree = tree
+ self.cpv_col = col
+ self.emergeIt = self.append(None, ["Emerge", ""])
+ self.unmergeIt = self.append(None, ["Unmerge", ""])
+
+ def build_append_value (self, cpv, oneshot = False, update = False, version = None):
+ string = ""
+
+ if oneshot:
+ string += "<i>oneshot</i>"
+ if update: string += "; "
+
+ if update:
+ string += "<i>updating</i>"
+ if version != None:
+ string += "<i> from version %s</i>" % version
+
+ return [cpv, string]
+
+ def get_emerge_it (self):
+ return self.emergeIt
+
+ def get_unmerge_it (self):
+ return self.unmergeIt
+
+ def is_in_emerge (self, it):
+ return self.get_path_from_iter(it).split(":")[0] == self.get_path_from_iter(self.emergeIt)
+
+ def is_in_unmerge (self, it):
+ return self.get_path_from_iter(it).split(":")[0] == self.get_path_from_iter(self.unmergeIt)
+
+ def iter_has_parent (self, it):
+ return (self.tree.iter_parent(it) != None)
+
+ def parent_iter (self, it):
+ return self.tree.iter_parent(it)
+
+ def first_child_iter (self, it):
+ return self.tree.iter_children(it)
+
+ def iter_has_children (self, it):
+ return self.tree.iter_has_child(it)
+
+ def next_iter (self, it):
+ return self.tree.iter_next(it)
+
+ def get_value (self, it, column):
+ return self.tree.get_value(it, column)
+
+ def get_path_from_iter (self, it):
+ return self.tree.get_string_from_iter(it)
+
+ def append (self, parent = None, values = None):
+ return self.tree.append(parent, values)
+
+ def remove (self, it):
+ return self.tree.remove(it)
+
+ def get_original (self):
+ return self.tree
+
+ def get_cpv_column (self):
+ return self.cpv_col
+
+class GtkConsole (Console):
+ """The implementation of the abstract Console for GTK."""
+
+ def __init__ (self, console):
+ """Constructor.
+
+ @param console: the original console
+ @type console: vte.Terminal"""
+
+ self.console = console
+
+ def set_pty (self, pty):
+ self.console.set_pty(pty)
+
+ def get_original (self):
+ return self.console
diff --git a/portato/gui/gui_helper.py b/portato/gui/gui_helper.py
new file mode 100644
index 0000000..6cc09a3
--- /dev/null
+++ b/portato/gui/gui_helper.py
@@ -0,0 +1,608 @@
+# -*- coding: utf-8 -*-
+#
+# File: portato/gui/gui_helper.py
+# This file is part of the Portato-Project, a graphical portage-frontend.
+#
+# Copyright (C) 2006 René 'Necoro' Neumann
+# This is free software. You may redistribute copies of it under the terms of
+# the GNU General Public License version 2.
+# There is NO WARRANTY, to the extent permitted by law.
+#
+# Written by René 'Necoro' Neumann <necoro@necoro.net>
+
+# some backend things
+from portato import backend
+from portato.backend import flags
+from portato.helper import *
+
+# parser
+from portato.config_parser import ConfigParser
+
+# the wrapper
+from wrapper import Console, Tree
+
+# some stuff needed
+from subprocess import Popen, PIPE, STDOUT
+from threading import Thread
+import pty
+
+class Config:
+ """Wrapper around a ConfigParser and for additional local configurations."""
+ const = {
+ "main_sec" : "Main",
+ "usePerVersion_opt" : "usePerVersion",
+ "useFile_opt" : "usefile",
+ "maskFile_opt" : "maskfile",
+ "maskPerVersion_opt" : "maskPerVersion",
+ "testingFile_opt" : "keywordfile",
+ "testingPerVersion_opt" : "keywordperversion",
+ "debug_opt" : "debug",
+ "oneshot_opt" : "oneshot",
+ "deep_opt" : "deep",
+ "newuse_opt" : "newuse",
+ "syncCmd_opt" : "synccommand"
+ }
+
+ def __init__ (self, cfgFile):
+ """Constructor.
+
+ @param cfgFile: path to config file
+ @type cfgFile: string"""
+
+ # init ConfigParser
+ self._cfg = ConfigParser(cfgFile)
+
+ # read config
+ self._cfg.parse()
+
+ # local configs
+ self.local = {}
+
+ def get(self, name, section=const["main_sec"], constName = True):
+ """Gets an option.
+
+ @param name: name of the option
+ @type name: string
+ @param section: section to look in; default is Main-Section
+ @type section: string
+ @param constName: If True (the default), the option names are first looked up in the const-dict.
+ @type constName: boolean
+ @return: the option's value
+ @rtype: string"""
+
+ if constName:
+ name = self.const[name]
+
+ return self._cfg.get(name, section)
+
+ def get_boolean(self, name, section=const["main_sec"], constName = True):
+ """Gets a boolean option.
+
+ @param name: name of the option
+ @type name: string
+ @param section: section to look in; default is Main-Section
+ @type section: string
+ @param constName: If True (the default), the option names are first looked up in the const-dict.
+ @type constName: boolean
+ @return: the option's value
+ @rtype: boolean"""
+
+ if constName:
+ name = self.const[name]
+
+ return self._cfg.get_boolean(name, section)
+
+ def modify_flags_config (self):
+ """Sets the internal config of the L{flags}-module.
+ @see: L{flags.set_config()}"""
+
+ flagCfg = {
+ "usefile": self.get("useFile_opt"),
+ "usePerVersion" : self.get_boolean("usePerVersion_opt"),
+ "maskfile" : self.get("maskFile_opt"),
+ "maskPerVersion" : self.get_boolean("maskPerVersion_opt"),
+ "testingfile" : self.get("testingFile_opt"),
+ "testingPerVersion" : self.get_boolean("testingPerVersion_opt")}
+ flags.set_config(flagCfg)
+
+ def modify_debug_config (self):
+ """Sets the external debug-config.
+ @see: L{helper.set_debug()}"""
+ set_debug(self.get_boolean("debug_opt"))
+
+ def modify_external_configs (self):
+ """Convenience function setting all external configs."""
+ self.modify_debug_config()
+ self.modify_flags_config()
+
+ def set_local(self, cpv, name, val):
+ """Sets some local config.
+
+ @param cpv: the cpv describing the package for which to set this option
+ @type cpv: string (cpv)
+ @param name: the option's name
+ @type name: string
+ @param val: the value to set
+ @type val: any"""
+
+ if not cpv in self.local:
+ self.local[cpv] = {}
+
+ self.local[cpv].update({name:val})
+
+ def get_local(self, cpv, name):
+ """Returns something out of the local config.
+
+ @param cpv: the cpv describing the package from which to get this option
+ @type cpv: string (cpv)
+ @param name: the option's name
+ @type name: string
+ @return: value stored for the cpv and name or None if not found
+ @rtype: any"""
+
+ if not cpv in self.local:
+ return None
+ if not name in self.local[cpv]:
+ return None
+
+ return self.local[cpv][name]
+
+ def set(self, name, val, section=const["main_sec"], constName = True):
+ """Sets an option.
+
+ @param name: name of the option
+ @type name: string
+ @param val: value to set the option to
+ @type val: string
+ @param section: section to look in; default is Main-Section
+ @type section: string
+ @param constName: If True (the default), the option names are first looked up in the const-dict.
+ @type constName: boolean"""
+
+ if constName:
+ name = self.const[name]
+
+ self._cfg.set(name, val, section)
+
+ def set_boolean (self, name, val, section=const["main_sec"], constName = True):
+ """Sets a boolean option.
+
+ @param name: name of the option
+ @type name: string
+ @param val: value to set the option to
+ @type val: boolean
+ @param section: section to look in; default is Main-Section
+ @type section: string
+ @param constName: If True (the default), the option names are first looked up in the const-dict.
+ @type constName: boolean"""
+
+ if constName:
+ name = self.const[name]
+
+ self._cfg.set_boolean(name, val, section)
+
+ def write(self):
+ """Writes to the config file and modify any external configs."""
+ self._cfg.write()
+ self.modify_external_configs()
+
+class Database:
+ """An internal database which holds a simple dictionary cat -> [package_list]."""
+
+ def __init__ (self):
+ """Constructor."""
+ self._db = {}
+
+ def populate (self, category = None):
+ """Populates the database.
+
+ @param category: An optional category - so only packages of this category are inserted.
+ @type category: string"""
+
+ # get the lists
+ packages = backend.find_all_packages(name = category, withVersion = False)
+ installed = backend.find_all_installed_packages(name = category, withVersion = False)
+
+ # cycle through packages
+ for p in packages:
+ list = p.split("/")
+ cat = list[0]
+ pkg = list[1]
+ if p in installed:
+ pkg += "*"
+ if not cat in self._db: self._db[cat] = []
+ self._db[cat].append(pkg)
+
+ for key in self._db: # sort alphabetically
+ self._db[key].sort(cmp=cmp, key=str.lower)
+
+ def get_cat (self, cat):
+ """Returns the packages in the category.
+
+ @param cat: category to return the packages from
+ @type cat: string
+ @return: list of packages or []
+ @rtype: string[]"""
+
+ try:
+ return self._db[cat]
+ except KeyError: # cat is in category list - but not in portage
+ debug("Catched KeyError =>", cat, "seems not to be an available category. Have you played with rsync-excludes?")
+ return []
+
+ def reload (self, cat):
+ """Reloads the given category.
+
+ @param cat: category
+ @type cat: string"""
+
+ del self._db[cat]
+ self.populate(cat+"/")
+
+class EmergeQueue:
+ """This class manages the emerge queue."""
+
+ def __init__ (self, tree = None, console = None, db = None):
+ """Constructor.
+
+ @param tree: Tree to append all the items to.
+ @type tree: Tree
+ @param console: Output is shown here.
+ @type console: Console
+ @param db: A database instance.
+ @type db: Database"""
+
+ # the different queues
+ self.mergequeue = [] # for emerge
+ self.unmergequeue = [] # for emerge -C
+ self.oneshotmerge = [] # for emerge --oneshot
+
+ # dictionaries with data about the packages in the queue
+ self.iters = {} # iterator in the tree
+ self.deps = {} # all the deps of the package
+
+ # member vars
+ self.tree = tree
+ if self.tree and not isinstance(self.tree, Tree): raise TypeError, "tree passed is not a Tree-object"
+
+ self.console = console
+ if self.console and not isinstance(self.console, Console): raise TypeError, "console passed is not a Console-object"
+
+ self.db = db
+
+ # our iterators pointing at the toplevels; they are set to None if we do not have a tree
+ if self.tree:
+ self.emergeIt = self.tree.get_emerge_it()
+ self.unmergeIt = self.tree.get_unmerge_it()
+ else:
+ self.emergeIt = self.unmergeIt = None
+
+ def _get_pkg_from_cpv (self, cpv, unmask = False):
+ """Gets a L{backend.Package}-object from a cpv.
+
+ @param cpv: the cpv to get the package for
+ @type cpv: string (cpv)
+ @param unmask: if True we will look for masked packages if we cannot find unmasked ones
+ @type unmask: boolean
+ @return: created package
+ @rtype: backend.Package
+
+ @raises backend.PackageNotFoundException: If no package could be found - normally it is existing but masked."""
+
+ # for the beginning: let us create a package object - but it is not guaranteed, that it actually exists in portage
+ pkg = backend.Package(cpv)
+ masked = not (pkg.is_masked() or pkg.is_testing(allowed=True)) # we are setting this to True in case we have unmasked it already, but portage does not know this
+
+ # and now try to find it in portage
+ pkg = backend.find_packages("="+cpv, masked = masked)
+
+ if pkg: # gotcha
+ pkg = pkg[0]
+
+ elif unmask: # no pkg returned, but we are allowed to unmask it
+ pkg = backend.find_packages("="+cpv, masked = True)[0]
+ if pkg.is_testing(allowed = True):
+ pkg.set_testing(True)
+ if pkg.is_masked():
+ pkg.set_masked()
+
+ else: # no pkg returned - and we are not allowed to unmask
+ raise backend.PackageNotFoundException(cpv)
+
+ return pkg
+
+ def update_tree (self, it, cpv, unmask = False, oneshot = False):
+ """This updates the tree recursivly, or? Isn't it? Bjorn!
+
+ @param it: iterator where to append
+ @type it: Iterator
+ @param cpv: The package to append.
+ @type cpv: string (cat/pkg-ver)
+ @param unmask: True if we are allowed to look for masked packages
+ @type unmask: boolean
+ @param oneshot: True if we want to emerge is oneshot
+ @type oneshot: boolean
+
+ @raises backend.BlockedException: When occured during dependency-calculation.
+ @raises backend.PackageNotFoundException: If no package could be found - normally it is existing but masked."""
+
+ if cpv in self.deps:
+ return # in list already and therefore it's already in the tree too
+
+ update = False
+ uVersion = None
+ try:
+ pkg = self._get_pkg_from_cpv(cpv, unmask)
+ if not pkg.is_installed():
+ old = backend.get_all_installed_versions(pkg.get_cp())
+ if old:
+ old = old[0] # assume we have only one there; FIXME: slotted packages
+ update = True
+ uVersion = old.get_version()
+
+ except backend.PackageNotFoundException, e: # package not found / package is masked -> delete current tree and re-raise the exception
+ if self.tree.iter_has_parent(it):
+ while self.tree.iter_has_parent(it):
+ it = self.tree.parent_iter(it)
+ self.remove_with_children(it)
+ raise e
+
+ # add iter
+ subIt = self.tree.append(it, self.tree.build_append_value(cpv, oneshot = oneshot, update = update, version = uVersion))
+ self.iters.update({cpv: subIt})
+
+ # get dependencies
+ deps = pkg.get_dep_packages() # this might raise a BlockedException
+ self.deps.update({cpv : deps})
+
+ # recursive call
+ for d in deps:
+ try:
+ self.update_tree(subIt, d, unmask)
+ except backend.BlockedException, e: # BlockedException occured -> delete current tree and re-raise exception
+ debug("Something blocked:", e[0])
+ self.remove_with_children(subIt)
+ raise e
+
+ def append (self, cpv, unmerge = False, update = False, forceUpdate = False, unmask = False, oneshot = False):
+ """Appends a cpv either to the merge queue or to the unmerge-queue.
+ Also updates the tree-view.
+
+ @param cpv: Package to add
+ @type cpv: string (cat/pkg-ver)
+ @param unmerge: Set to True if you want to unmerge this package - else False.
+ @type unmerge: boolean
+ @param update: Set to True if a package is going to be updated (e.g. if the use-flags changed).
+ @type update: boolean
+ @param forceUpdate: Set to True if the update should be forced.
+ @type forceUpdate: boolean
+ @param unmask: True if we are allowed to look for masked packages
+ @type unmask: boolean
+ @param oneshot: True if this package should not be added to the world-file.
+ @type oneshot: boolean
+
+ @raises portato.backend.PackageNotFoundException: if trying to add a package which does not exist"""
+
+ if not unmerge: # emerge
+ # insert dependencies
+ pkg = self._get_pkg_from_cpv(cpv, unmask)
+ deps = pkg.get_dep_packages()
+
+ if update:
+ if not forceUpdate and deps == self.deps[cpv]:
+ return # nothing changed - return
+ else:
+ hasBeenInQueue = (cpv in self.mergequeue or cpv in self.oneshotmerge)
+ parentIt = self.tree.parent_iter(self.iters[cpv])
+
+ # delete it out of the tree - but NOT the changed flags
+ self.remove_with_children(self.iters[cpv], removeNewFlags = False)
+
+ if hasBeenInQueue: # package has been in queue before
+ self._queue_append(cpv, oneshot)
+
+ self.update_tree(parentIt, cpv, unmask, oneshot = oneshot)
+ else: # not update
+ self._queue_append(cpv, oneshot)
+ if self.emergeIt:
+ self.update_tree(self.emergeIt, cpv, unmask, oneshot = oneshot)
+
+ else: # unmerge
+ self.unmergequeue.append(cpv)
+ if self.unmergeIt: # update tree
+ self.tree.append(self.unmergeIt, self.tree.build_append_value(cpv))
+
+ def _queue_append (self, cpv, oneshot = False):
+ """Convenience function appending a cpv either to self.mergequeue or to self.oneshotmerge.
+
+ @param cpv: cpv to add
+ @type cpv: string (cpv)
+ @param oneshot: True if this package should not be added to the world-file.
+ @type oneshot: boolean"""
+
+ if not oneshot:
+ self.mergequeue.append(cpv)
+ else:
+ self.oneshotmerge.append(cpv)
+
+ def _update_packages(self, packages, process = None):
+ """This updates the packages-list. It simply makes the db to rebuild the specific category.
+
+ @param packages: The packages which we emerged.
+ @type packages: list of cpvs
+ @param process: The process we have to wait for before we can do our work.
+ @type process: subprocess.Popen"""
+
+ if process: process.wait()
+ for p in packages:
+ if p in ["world", "system"]: continue
+ cat = backend.split_package_name(p)[0] # get category
+ while cat[0] in ["=",">","<","!"]:
+ cat = cat[1:]
+ self.db.reload(cat)
+ debug("Category %s refreshed" % cat)
+
+ def _emerge (self, options, packages, it, command = ["/usr/bin/python","/usr/bin/emerge"]):
+ """Calls emerge and updates the terminal.
+
+ @param options: options to send to emerge
+ @type options: list
+ @param packages: packages to emerge
+ @type packages: list
+ @param it: Iterators which point to these entries whose children will be removed after completion.
+ @type it: Iterator[]
+ @param command: the command to execute - default is "/usr/bin/python /usr/bin/emerge"
+ @type command: string[]"""
+
+ # open tty
+ (master, slave) = pty.openpty()
+ self.console.set_pty(master)
+
+ # start emerge
+ process = Popen(command+options+packages, stdout = slave, stderr = STDOUT, shell = False)
+
+ # start thread waiting for the stop of emerge
+ Thread(target=self._update_packages, args=(packages+self.deps.keys(), process)).start()
+
+ # remove
+ for i in it:
+ self.remove_with_children(i)
+
+ def emerge (self, force = False):
+ """Emerges everything in the merge-queue.
+
+ @param force: If False, '-pv' is send to emerge. Default: False.
+ @type force: boolean"""
+
+ def prepare(queue):
+ """Prepares the list of iterators and the list of packages."""
+ list = []
+ its = []
+ for k in queue:
+ list += ["="+k]
+ its.append(self.iters[k])
+
+ return list, its
+
+ # oneshot-queue
+ if len(self.oneshotmerge) != 0:
+ # prepare package-list for oneshot
+ list, its = prepare(self.oneshotmerge)
+
+ s = ["--oneshot"]
+ if not force: s += ["--verbose", "--pretend"]
+
+ self._emerge(s, list, its)
+
+ # normal queue
+ if len(self.mergequeue) != 0:
+ # prepare package-list
+ list, its = prepare(self.mergequeue)
+
+ s = []
+ if not force: s = ["--verbose", "--pretend"]
+
+ self._emerge(s, list, its)
+
+ def unmerge (self, force = False):
+ """Unmerges everything in the umerge-queue.
+
+ @param force: If False, '-pv' is send to emerge. Default: False.
+ @type force: boolean"""
+
+ if len(self.unmergequeue) == 0: return # nothing in queue
+
+ list = self.unmergequeue[:] # copy the unmerge-queue
+
+ # set options
+ s = ["-C"]
+ if not force: s += ["-pv"]
+
+ self._emerge(s,list, [self.unmergeIt])
+
+ def update_world(self, force = False, newuse = False, deep = False):
+ """Does an update world. newuse and deep are the arguments handed to emerge.
+
+ @param force: If False, '-pv' is send to emerge. Default: False.
+ @type force: boolean"""
+
+ options = ["--update"]
+
+ if newuse: options += ["--newuse"]
+ if deep: options += ["--deep"]
+ if not force: options += ["-pv"]
+
+ self._emerge(options, ["world"], [self.emergeIt])
+
+ def sync (self, command = None):
+ """Calls "emerge --sync".
+
+ @param command: command to execute to sync. If None "emerge --sync" is taken.
+ @type command: string[]"""
+
+ if command == None:
+ self._emerge(["--sync"], [], [])
+ else:
+ self._emerge([],[],[], command = command)
+
+ def remove_with_children (self, it, removeNewFlags = True):
+ """Convenience function which removes all children of an iterator and than the iterator itself.
+
+ @param it: The iter which to remove.
+ @type it: Iterator
+ @param removeNewFlags: True if new flags should be removed; False otherwise. Default: True.
+ @type removeNewFlags: boolean"""
+
+ self.remove_children(it, removeNewFlags)
+ self.remove(it, removeNewFlags)
+
+ def remove_children (self, parentIt, removeNewFlags = True):
+ """Removes all children of a given parent TreeIter recursivly.
+
+ @param parentIt: The iter from which to remove all children.
+ @type parentIt: Iterator
+ @param removeNewFlags: True if new flags should be removed; False otherwise. Default: True.
+ @type removeNewFlags: boolean"""
+
+ childIt = self.tree.first_child_iter(parentIt)
+
+ while childIt:
+ if (self.tree.iter_has_children(childIt)): # recursive call
+ self.remove_children(childIt, removeNewFlags)
+ temp = childIt
+ childIt = self.tree.next_iter(childIt)
+ self.remove(temp, removeNewFlags)
+
+ def remove (self, it, removeNewFlags = True):
+ """Removes a specific item in the tree. This does not remove the top-entries.
+
+ @param it: Iterator which points to the entry we are going to remove.
+ @type it: Iterator
+ @param removeNewFlags: True if new flags should be removed; False otherwise. Default: True.
+ @type removeNewFlags: boolean"""
+
+ if self.tree.iter_has_parent(it): # NEVER remove our top stuff
+ cpv = self.tree.get_value(it, self.tree.get_cpv_column())
+ if self.tree.is_in_emerge(it): # Emerge
+ del self.iters[cpv]
+ try:
+ del self.deps[cpv]
+ except KeyError: # this seems to be removed due to a BlockedException - so no deps here atm ;)
+ debug("Catched KeyError =>", cpv, "seems not to be in self.deps. Should be no harm in normal cases.")
+ try:
+ self.mergequeue.remove(cpv)
+ except ValueError: # this is a dependency - ignore
+ try:
+ self.oneshotmerge.remove(cpv)
+ except ValueError:
+ debug("Catched ValueError =>", cpv, "seems not to be in merge-queue. Should be no harm.")
+
+ if removeNewFlags: # remove the changed flags
+ flags.remove_new_use_flags(cpv)
+ flags.remove_new_masked(cpv)
+ flags.remove_new_testing(cpv)
+
+ else: # in Unmerge
+ self.unmergequeue.remove(cpv)
+
+ self.tree.remove(it)
diff --git a/portato/gui/wrapper.py b/portato/gui/wrapper.py
new file mode 100644
index 0000000..def5c50
--- /dev/null
+++ b/portato/gui/wrapper.py
@@ -0,0 +1,184 @@
+# -*- coding: utf-8 -*-
+#
+# File: portato/gui/wrapper.py
+# This file is part of the Portato-Project, a graphical portage-frontend.
+#
+# Copyright (C) 2006 René 'Necoro' Neumann
+# This is free software. You may redistribute copies of it under the terms of
+# the GNU General Public License version 2.
+# There is NO WARRANTY, to the extent permitted by law.
+#
+# Written by René 'Necoro' Neumann <necoro@necoro.net>
+
+class Tree:
+ """This represents an abstract of a Tree-Widget. It should be used for all operations not in a specific frontend, where a Tree is needed.
+ Each frontend _MUST_ define its own subclass and implement ALL of the methods, otherwise a NotImplementedError will be thrown."""
+
+ def iter_has_parent (self, it):
+ """Returns whether the actual iterator has a parent.
+
+ @param it: the iterator
+ @type it: Iterator
+ @returns: True if it has a parent it, else False.
+ @rtype: boolean"""
+ raise NotImplementedError
+
+ def parent_iter (self, it):
+ """Returns the parent iter.
+
+ @param it: the iterator
+ @type it: Iterator
+ @returns: Parent iterator or None if the current it has no parent.
+ @rtype: Iterator; None"""
+ raise NotImplementedError
+
+ def first_child_iter (self, it):
+ """Returns the first child iter.
+
+ @param it: the iterator
+ @type it: Iterator
+ @returns: First child iterator or None if the current it has no children.
+ @rtype: Iterator; None"""
+ raise NotImplementedError
+
+ def iter_has_children (self, it):
+ """Returns whether the actual iterator has children.
+
+ @param it: the iterator
+ @type it: Iterator
+ @returns: True if it has children, else False.
+ @rtype: boolean"""
+ raise NotImplementedError
+
+ def next_iter (self, it):
+ """Returns the next iter.
+
+ @param it: the iterator
+ @type it: Iterator
+ @returns: Nex iterator or None if the current iter is the last one.
+ @rtype: Iterator; None"""
+ raise NotImplementedError
+
+ def get_value (self, it, column):
+ """Returns the value of the specific column at the given iterator.
+
+ @param it: the iterator
+ @type it: Iterator
+ @param column: the column of the iterator from where to get the value
+ @type column: int
+ @returns: the value
+ @rtype: anything"""
+ raise NotImplementedError
+
+ def get_path_from_iter(self, it):
+ """Returns a string defining the path to the given iterator. In this path all nodes are divided by a colon ':'.
+ For example: 2:4:5 could mean the 6th child of the 5th child of the 3rd element. It might also mean the 5th child of the 4th child of the 2nd element. It does not matter, where counting starts as long as it is consistent.
+
+ @param it: the iterator
+ @type it: Iterator
+ @returns: the path string
+ @rtype: string"""
+ raise NotImplementedError
+
+ def append (self, parent = None, values = None):
+ """Appends some values right after the given parent. If parent is None, it is appended as the first element.
+
+ @param parent: the iterator to append the values right after; if None it symbolizes the top
+ @type parent: Iterator
+ @param values: a list of values which are going to be appended to the tree
+ @type values: list
+ @returns: Iterator pointing to the newly appended stuff
+ @rtype: Iterator"""
+ raise NotImplementedError
+
+ def remove(self, it):
+ """Removes an iterator out of the tree.
+ @attention: The iterator can point to anything hereafter. Do not reuse!
+
+ @param it: iterator to remove
+ @type it: Iterator"""
+ raise NotImplementedError
+
+ def get_original(self):
+ """Returns the original tree-object.
+
+ @returns: original tree-object
+ @rtype: tree-object"""
+ raise NotImplementedError
+
+ #
+ # the "design" part
+ #
+
+ def get_cpv_column (self):
+ """Returns the number of the column where the cpv's are stored.
+
+ @returns: column with cpv's
+ @rtype: int"""
+ raise NotImplementedError
+
+ def is_in_emerge (self, it):
+ """Checks whether an iterator is part of the "Emerge" section.
+
+ @param it: the iterator to check
+ @type it: Iterator
+ @returns: True if the iter is part; False otherwise
+ @rtype: boolean"""
+ raise NotImplementedError
+
+ def is_in_unmerge (self, it):
+ """Checks whether an iterator is part of the "Unmerge" section.
+
+ @param it: the iterator to check
+ @type it: Iterator
+ @returns: True if the iter is part; False otherwise
+ @rtype: boolean"""
+ raise NotImplementedError
+
+ def get_emerge_it (self):
+ """Returns an iterator signaling the top of the emerge section.
+
+ @returns: emerge-iterator
+ @rtype: Iterator"""
+ raise NotImplementedError
+
+ def get_unmerge_it (self):
+ """Returns an iterator signaling the top of the unmerge section.
+
+ @returns: unmerge-iterator
+ @rtype: Iterator"""
+ raise NotImplementedError
+
+ def build_append_value (self, cpv, oneshot = False, update = False, version = None):
+ """Builds the list, which is going to be passed to append.
+
+ @param cpv: the cpv
+ @type cpv: string (cpv)
+ @param oneshot: True if oneshot
+ @type oneshot: boolean
+ @param update: True if this is an update
+ @type update: boolean
+ @param version: the version we update from
+ @type version: string
+
+ @returns: the created list
+ @rtype: list"""
+ raise NotImplementedError
+
+class Console:
+ """This represents the abstract of a console. It should be used for all operations not in a specific frontend, where a console is needed.
+ Each frontend _MUST_ define its own subclass and implement ALL of the methods, otherwise a NotImplementedError will be thrown."""
+
+ def set_pty (self, pty):
+ """This sets the pseudo-terminal where to print the incoming output to.
+
+ @param pty: the terminal to print to
+ @type pty: file-descriptor"""
+ raise NotImplementedError
+
+ def get_original(self):
+ """Returns the original console-object.
+
+ @returns: original console-object
+ @rtype: console-object"""
+ raise NotImplementedError