Added pyeix
authorAndrew <andrew@admin.liquid.me.uk>
Tue, 29 Jun 2021 07:13:33 +0000 (08:13 +0100)
committerAndrew <andrew@admin.liquid.me.uk>
Tue, 29 Jun 2021 07:13:33 +0000 (08:13 +0100)
13 files changed:
form.ui [new file with mode: 0644]
pyeix/.eric6project/PyEix.eqj [new file with mode: 0644]
pyeix/.eric6project/PyEix.etj [new file with mode: 0644]
pyeix/PyEix.epj [new file with mode: 0644]
pyeix/PyEix.py [new file with mode: 0755]
pyeix/pyeix [new file with mode: 0755]
pyeix/ui/Ui_mainwindow.py [new file with mode: 0644]
pyeix/ui/__init__.py [new file with mode: 0644]
pyeix/ui/__pycache__/Ui_mainwindow.cpython-39.pyc [new file with mode: 0644]
pyeix/ui/__pycache__/__init__.cpython-39.pyc [new file with mode: 0644]
pyeix/ui/__pycache__/mainwindow.cpython-39.pyc [new file with mode: 0644]
pyeix/ui/mainwindow.py [new file with mode: 0644]
pyeix/ui/mainwindow.ui [new file with mode: 0644]

diff --git a/form.ui b/form.ui
new file mode 100644 (file)
index 0000000..6dba237
--- /dev/null
+++ b/form.ui
@@ -0,0 +1,219 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>460</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="minimumSize">
+   <size>
+    <width>460</width>
+    <height>300</height>
+   </size>
+  </property>
+  <property name="windowTitle">
+   <string>MainWindow</string>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <layout class="QGridLayout" name="gridLayout_2">
+    <item row="0" column="0">
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <item>
+       <widget class="QLineEdit" name="le_search"/>
+      </item>
+      <item>
+       <widget class="QPushButton" name="pb_search">
+        <property name="text">
+         <string>Search</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </item>
+    <item row="1" column="0">
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <item>
+       <widget class="QCheckBox" name="cb_stable">
+        <property name="toolTip">
+         <string>Only match packages with a stable version</string>
+        </property>
+        <property name="text">
+         <string>Stable</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="cb_testing">
+        <property name="toolTip">
+         <string>Only match packages with a testing version</string>
+        </property>
+        <property name="text">
+         <string>Testing</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="cb_installed">
+        <property name="toolTip">
+         <string>Only match installed packages</string>
+        </property>
+        <property name="text">
+         <string>Installed</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="cb_overlay">
+        <property name="toolTip">
+         <string>Only match packages with at least one version in an overlay</string>
+        </property>
+        <property name="text">
+         <string>Overlay</string>
+        </property>
+        <property name="tristate">
+         <bool>false</bool>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </item>
+    <item row="2" column="0">
+     <layout class="QGridLayout" name="gridLayout">
+      <item row="0" column="1">
+       <widget class="QRadioButton" name="rb_decription">
+        <property name="toolTip">
+         <string>Search the description field</string>
+        </property>
+        <property name="text">
+         <string>Description</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="2">
+       <widget class="QRadioButton" name="rb_use_disabled">
+        <property name="toolTip">
+         <string>Search for packages instealled with that use flag diabled</string>
+        </property>
+        <property name="text">
+         <string>Use Disabled</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="0">
+       <widget class="QRadioButton" name="rb_any">
+        <property name="toolTip">
+         <string>Search any field</string>
+        </property>
+        <property name="text">
+         <string>Any</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="3">
+       <widget class="QRadioButton" name="rb_name">
+        <property name="toolTip">
+         <string>Search the name field</string>
+        </property>
+        <property name="text">
+         <string>Name</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="2">
+       <widget class="QRadioButton" name="rb_category">
+        <property name="toolTip">
+         <string>Search the category field</string>
+        </property>
+        <property name="text">
+         <string>Category</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="0">
+       <widget class="QRadioButton" name="rb_iuse">
+        <property name="toolTip">
+         <string>Search for packages that can have that use flag enabled</string>
+        </property>
+        <property name="text">
+         <string>Use flags (IUSE)</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="1">
+       <widget class="QRadioButton" name="rb_use_enabled">
+        <property name="toolTip">
+         <string>Search for packages installed with that use flag enabled</string>
+        </property>
+        <property name="text">
+         <string>Use enabled</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </item>
+    <item row="3" column="0">
+     <widget class="QTreeView" name="tv_results"/>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>460</width>
+     <height>26</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QStatusBar" name="statusbar"/>
+  <action name="action_search">
+   <property name="text">
+    <string>_search</string>
+   </property>
+   <property name="shortcut">
+    <string>Return</string>
+   </property>
+  </action>
+ </widget>
+ <tabstops>
+  <tabstop>le_search</tabstop>
+  <tabstop>pb_search</tabstop>
+  <tabstop>cb_stable</tabstop>
+  <tabstop>cb_testing</tabstop>
+  <tabstop>cb_installed</tabstop>
+  <tabstop>cb_overlay</tabstop>
+  <tabstop>rb_any</tabstop>
+  <tabstop>rb_decription</tabstop>
+  <tabstop>rb_category</tabstop>
+  <tabstop>rb_name</tabstop>
+  <tabstop>rb_iuse</tabstop>
+  <tabstop>rb_use_enabled</tabstop>
+  <tabstop>rb_use_disabled</tabstop>
+  <tabstop>tv_results</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>pb_search</sender>
+   <signal>clicked()</signal>
+   <receiver>action_search</receiver>
+   <slot>trigger()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>410</x>
+     <y>47</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/pyeix/.eric6project/PyEix.eqj b/pyeix/.eric6project/PyEix.eqj
new file mode 100644 (file)
index 0000000..b8d68c0
--- /dev/null
@@ -0,0 +1,10 @@
+{
+  "header": {
+    "comment": "eric user project file for project PyEix",
+    "saved": "2021-06-29, 07:33:06"
+  },
+  "user_data": {
+    "VCSOVERRIDE": "",
+    "VCSSTATUSMONITORINTERVAL": 0
+  }
+}
\ No newline at end of file
diff --git a/pyeix/.eric6project/PyEix.etj b/pyeix/.eric6project/PyEix.etj
new file mode 100644 (file)
index 0000000..befa67c
--- /dev/null
@@ -0,0 +1,23 @@
+{
+  "header": {
+    "comment": "eric tasks file for project PyEix",
+    "warning": "This file was generated automatically, do not edit.",
+    "saved": "2021-06-29, 07:33:06"
+  },
+  "ProjectScanFilter": "",
+  "Tasks": [
+    {
+      "summary": "WARNING: Any manual changes made to this file will be lost when pyuic5 is",
+      "description": "",
+      "priority": 1,
+      "lineno": 7,
+      "completed": false,
+      "created": 1624948329.6457803,
+      "type": 2,
+      "uid": "{d9298fed-a068-4f89-97a0-5fcdd927106e}",
+      "parent_uid": "",
+      "expanded": false,
+      "filename": "/home/andrew/Projects/pyeix/ui/Ui_mainwindow.py"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/pyeix/PyEix.epj b/pyeix/PyEix.epj
new file mode 100644 (file)
index 0000000..2f32eaf
--- /dev/null
@@ -0,0 +1,96 @@
+{
+  "header": {
+    "comment": "eric project file for project PyEix",
+    "copyright": "Copyright (C) 2021 Ralphred, PyEix@liquid.me.uk",
+    "saved": "2021-06-29, 07:33:06"
+  },
+  "project": {
+    "AUTHOR": "Ralphred",
+    "CHECKERSPARMS": {},
+    "DESCRIPTION": "Simple GUI front end to eix",
+    "DOCSTRING": "ericdoc",
+    "DOCUMENTATIONPARMS": {},
+    "EMAIL": "PyEix@liquid.me.uk",
+    "EOL": 0,
+    "FILETYPES": {
+      "*.e4p": "OTHERS",
+      "*.epj": "OTHERS",
+      "*.idl": "INTERFACES",
+      "*.md": "OTHERS",
+      "*.proto": "PROTOCOLS",
+      "*.py": "SOURCES",
+      "*.py3": "SOURCES",
+      "*.pyw": "SOURCES",
+      "*.pyw3": "SOURCES",
+      "*.qm": "TRANSLATIONS",
+      "*.qrc": "RESOURCES",
+      "*.rst": "OTHERS",
+      "*.ts": "TRANSLATIONS",
+      "*.txt": "OTHERS",
+      "*.ui": "FORMS",
+      "GNUmakefile": "OTHERS",
+      "Makefile": "OTHERS",
+      "README": "OTHERS",
+      "README.*": "OTHERS",
+      "makefile": "OTHERS"
+    },
+    "FORMS": [
+      "ui/mainwindow.ui"
+    ],
+    "HASH": "ea418876ac01b612acd0a2860033e175bbb2bedb",
+    "IDLPARAMS": {
+      "DefinedNames": [],
+      "IncludeDirs": [],
+      "UndefinedNames": []
+    },
+    "INTERFACES": [],
+    "LEXERASSOCS": {},
+    "MAINSCRIPT": "PyEix",
+    "MAKEPARAMS": {
+      "MakeEnabled": false,
+      "MakeExecutable": "",
+      "MakeFile": "",
+      "MakeParameters": "",
+      "MakeTarget": "",
+      "MakeTestOnly": true
+    },
+    "MIXEDLANGUAGE": false,
+    "OTHERS": [],
+    "OTHERTOOLSPARMS": {},
+    "PACKAGERSPARMS": {},
+    "PROGLANGUAGE": "Python3",
+    "PROJECTTYPE": "PyQt5",
+    "PROJECTTYPESPECIFICDATA": {},
+    "PROTOCOLS": [],
+    "RCCPARAMS": {
+      "CompressLevel": 0,
+      "CompressionDisable": false,
+      "CompressionThreshold": 70,
+      "PathPrefix": ""
+    },
+    "RESOURCES": [],
+    "SOURCES": [
+      "__init__.py",
+      "ui/__init__.py",
+      "ui/Ui_mainwindow.py",
+      "ui/mainwindow.py",
+      "PyEix.py"
+    ],
+    "SPELLEXCLUDES": "",
+    "SPELLLANGUAGE": "",
+    "SPELLWORDS": "",
+    "TRANSLATIONEXCEPTIONS": [],
+    "TRANSLATIONPATTERN": "",
+    "TRANSLATIONS": [],
+    "TRANSLATIONSBINPATH": "",
+    "UICPARAMS": {
+      "Package": "",
+      "PackagesRoot": "",
+      "RcSuffix": ""
+    },
+    "VCS": "None",
+    "VCSOPTIONS": {},
+    "VCSOTHERDATA": {},
+    "VERSION": "0.1"
+  }
+}
\ No newline at end of file
diff --git a/pyeix/PyEix.py b/pyeix/PyEix.py
new file mode 100755 (executable)
index 0000000..617831d
--- /dev/null
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+from PyQt5 import QtWidgets
+from ui.mainwindow import MainWindow
+
+if __name__ == "__main__":
+    import sys
+    app = QtWidgets.QApplication(sys.argv)
+    ui = MainWindow()
+    ui.show()
+    sys.exit(app.exec_())
diff --git a/pyeix/pyeix b/pyeix/pyeix
new file mode 100755 (executable)
index 0000000..59b79fe
--- /dev/null
@@ -0,0 +1,519 @@
+#!/usr/bin/env python
+#pyqt front end to some eix search functions
+
+from PyQt5 import QtCore, QtWidgets
+from PyQt5.QtWidgets import QMainWindow
+from PyQt5.QtGui import QStandardItemModel,QStandardItem
+import sys, subprocess, re
+
+class Ui_MainWindow(object):
+    def setupUi(self, MainWindow):
+        MainWindow.setObjectName("MainWindow")
+        MainWindow.resize(938, 483)
+        MainWindow.setMinimumSize(QtCore.QSize(460, 300))
+        self.centralwidget = QtWidgets.QWidget(MainWindow)
+        self.centralwidget.setObjectName("centralwidget")
+        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
+        self.gridLayout.setObjectName("gridLayout")
+        self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
+        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
+        self.le_search = QtWidgets.QLineEdit(self.centralwidget)
+        self.le_search.setObjectName("le_search")
+        self.horizontalLayout_2.addWidget(self.le_search)
+        self.pb_search = QtWidgets.QPushButton(self.centralwidget)
+        self.pb_search.setObjectName("pb_search")
+        self.horizontalLayout_2.addWidget(self.pb_search)
+        self.gridLayout.addLayout(self.horizontalLayout_2, 0, 0, 1, 1)
+        self.horizontalLayout = QtWidgets.QHBoxLayout()
+        self.horizontalLayout.setObjectName("horizontalLayout")
+        self.cb_stable = QtWidgets.QCheckBox(self.centralwidget)
+        self.cb_stable.setObjectName("cb_stable")
+        self.horizontalLayout.addWidget(self.cb_stable)
+        self.cb_testing = QtWidgets.QCheckBox(self.centralwidget)
+        self.cb_testing.setObjectName("cb_testing")
+        self.horizontalLayout.addWidget(self.cb_testing)
+        self.cb_installed = QtWidgets.QCheckBox(self.centralwidget)
+        self.cb_installed.setObjectName("cb_installed")
+        self.horizontalLayout.addWidget(self.cb_installed)
+        self.cb_overlay = QtWidgets.QCheckBox(self.centralwidget)
+        self.cb_overlay.setTristate(False)
+        self.cb_overlay.setObjectName("cb_overlay")
+        self.horizontalLayout.addWidget(self.cb_overlay)
+        self.gridLayout.addLayout(self.horizontalLayout, 1, 0, 1, 1)
+        self.horizontalLayout_6 = QtWidgets.QHBoxLayout()
+        self.horizontalLayout_6.setObjectName("horizontalLayout_6")
+        self.rb_any = QtWidgets.QRadioButton(self.centralwidget)
+        self.rb_any.setObjectName("rb_any")
+        self.horizontalLayout_6.addWidget(self.rb_any)
+        self.rb_decription = QtWidgets.QRadioButton(self.centralwidget)
+        self.rb_decription.setObjectName("rb_decription")
+        self.horizontalLayout_6.addWidget(self.rb_decription)
+        self.rb_category = QtWidgets.QRadioButton(self.centralwidget)
+        self.rb_category.setObjectName("rb_category")
+        self.horizontalLayout_6.addWidget(self.rb_category)
+        self.rb_name = QtWidgets.QRadioButton(self.centralwidget)
+        self.rb_name.setObjectName("rb_name")
+        self.horizontalLayout_6.addWidget(self.rb_name)
+        self.gridLayout.addLayout(self.horizontalLayout_6, 2, 0, 1, 1)
+        self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
+        self.horizontalLayout_5.setObjectName("horizontalLayout_5")
+        self.rb_iuse = QtWidgets.QRadioButton(self.centralwidget)
+        self.rb_iuse.setObjectName("rb_iuse")
+        self.horizontalLayout_5.addWidget(self.rb_iuse)
+        self.rb_use_enabled = QtWidgets.QRadioButton(self.centralwidget)
+        self.rb_use_enabled.setObjectName("rb_use_enabled")
+        self.horizontalLayout_5.addWidget(self.rb_use_enabled)
+        self.rb_use_disabled = QtWidgets.QRadioButton(self.centralwidget)
+        self.rb_use_disabled.setObjectName("rb_use_disabled")
+        self.horizontalLayout_5.addWidget(self.rb_use_disabled)
+        self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
+        self.horizontalLayout_4.setObjectName("horizontalLayout_4")
+        self.l_res_count = QtWidgets.QLabel(self.centralwidget)
+        self.l_res_count.setObjectName("l_res_count")
+        self.horizontalLayout_4.addWidget(self.l_res_count)
+        self.horizontalLayout_5.addLayout(self.horizontalLayout_4)
+        self.gridLayout.addLayout(self.horizontalLayout_5, 3, 0, 1, 1)
+        self.tv_results = QtWidgets.QTreeView(self.centralwidget)
+        self.tv_results.setObjectName("tv_results")
+        self.gridLayout.addWidget(self.tv_results, 4, 0, 1, 1)
+        self.line = QtWidgets.QFrame(self.centralwidget)
+        self.line.setFrameShape(QtWidgets.QFrame.HLine)
+        self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
+        self.line.setObjectName("line")
+        self.gridLayout.addWidget(self.line, 5, 0, 1, 1)
+        self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
+        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
+        self.pb_expand_all = QtWidgets.QPushButton(self.centralwidget)
+        self.pb_expand_all.setObjectName("pb_expand_all")
+        self.horizontalLayout_3.addWidget(self.pb_expand_all)
+        self.pb_expand_pkg = QtWidgets.QPushButton(self.centralwidget)
+        self.pb_expand_pkg.setObjectName("pb_expand_pkg")
+        self.horizontalLayout_3.addWidget(self.pb_expand_pkg)
+        self.pb_collapse = QtWidgets.QPushButton(self.centralwidget)
+        self.pb_collapse.setObjectName("pb_collapse")
+        self.horizontalLayout_3.addWidget(self.pb_collapse)
+        self.pb_updatedb = QtWidgets.QPushButton(self.centralwidget)
+        self.pb_updatedb.setObjectName("pb_updatedb")
+        self.horizontalLayout_3.addWidget(self.pb_updatedb)
+        self.le_command = QtWidgets.QLineEdit(self.centralwidget)
+        self.le_command.setEnabled(False)
+        self.le_command.setObjectName("le_command")
+        self.horizontalLayout_3.addWidget(self.le_command)
+        self.gridLayout.addLayout(self.horizontalLayout_3, 6, 0, 1, 1)
+        MainWindow.setCentralWidget(self.centralwidget)
+        self.menubar = QtWidgets.QMenuBar(MainWindow)
+        self.menubar.setGeometry(QtCore.QRect(0, 0, 938, 26))
+        self.menubar.setObjectName("menubar")
+        MainWindow.setMenuBar(self.menubar)
+        self.statusbar = QtWidgets.QStatusBar(MainWindow)
+        self.statusbar.setObjectName("statusbar")
+        MainWindow.setStatusBar(self.statusbar)
+
+        self.retranslateUi(MainWindow)
+        QtCore.QMetaObject.connectSlotsByName(MainWindow)
+        MainWindow.setTabOrder(self.le_search, self.pb_search)
+        MainWindow.setTabOrder(self.pb_search, self.cb_stable)
+        MainWindow.setTabOrder(self.cb_stable, self.cb_testing)
+        MainWindow.setTabOrder(self.cb_testing, self.cb_installed)
+        MainWindow.setTabOrder(self.cb_installed, self.cb_overlay)
+        MainWindow.setTabOrder(self.cb_overlay, self.rb_any)
+        MainWindow.setTabOrder(self.rb_any, self.rb_decription)
+        MainWindow.setTabOrder(self.rb_decription, self.rb_category)
+        MainWindow.setTabOrder(self.rb_category, self.rb_name)
+        MainWindow.setTabOrder(self.rb_name, self.rb_iuse)
+        MainWindow.setTabOrder(self.rb_iuse, self.rb_use_enabled)
+        MainWindow.setTabOrder(self.rb_use_enabled, self.rb_use_disabled)
+        MainWindow.setTabOrder(self.rb_use_disabled, self.tv_results)
+
+    def retranslateUi(self, MainWindow):
+        _translate = QtCore.QCoreApplication.translate
+        MainWindow.setWindowTitle(_translate("MainWindow", "PyEix"))
+        self.pb_search.setText(_translate("MainWindow", "Search"))
+        self.cb_stable.setToolTip(_translate("MainWindow", "Only match packages with a stable version"))
+        self.cb_stable.setText(_translate("MainWindow", "Stable"))
+        self.cb_testing.setToolTip(_translate("MainWindow", "Only match packages with a testing version"))
+        self.cb_testing.setText(_translate("MainWindow", "Testing"))
+        self.cb_installed.setToolTip(_translate("MainWindow", "Only match installed packages"))
+        self.cb_installed.setText(_translate("MainWindow", "Installed"))
+        self.cb_overlay.setToolTip(_translate("MainWindow", "Only match packages with at least one version in an overlay"))
+        self.cb_overlay.setText(_translate("MainWindow", "Overlay"))
+        self.rb_any.setToolTip(_translate("MainWindow", "Search any field"))
+        self.rb_any.setText(_translate("MainWindow", "Any"))
+        self.rb_decription.setToolTip(_translate("MainWindow", "Search the description field"))
+        self.rb_decription.setText(_translate("MainWindow", "Description"))
+        self.rb_category.setToolTip(_translate("MainWindow", "Search the category field"))
+        self.rb_category.setText(_translate("MainWindow", "Category"))
+        self.rb_name.setToolTip(_translate("MainWindow", "Search the name field"))
+        self.rb_name.setText(_translate("MainWindow", "Name"))
+        self.rb_iuse.setToolTip(_translate("MainWindow", "Search for packages that can have that use flag enabled"))
+        self.rb_iuse.setText(_translate("MainWindow", "Use flags (IUSE)"))
+        self.rb_use_enabled.setToolTip(_translate("MainWindow", "Search for packages installed with that use flag enabled"))
+        self.rb_use_enabled.setText(_translate("MainWindow", "Use enabled"))
+        self.rb_use_disabled.setToolTip(_translate("MainWindow", "Search for packages instealled with that use flag diabled"))
+        self.rb_use_disabled.setText(_translate("MainWindow", "Use Disabled"))
+        self.l_res_count.setText(_translate("MainWindow", "           Results: "))
+        self.pb_expand_all.setText(_translate("MainWindow", "Expand All"))
+        self.pb_expand_pkg.setText(_translate("MainWindow", "Expand Pkgs"))
+        self.pb_collapse.setText(_translate("MainWindow", "Collapse"))
+        self.pb_updatedb.setToolTip(_translate("MainWindow", "<html><head/><body><p>Update eix\'s database (uses sudo)</p></body></html>"))
+        self.pb_updatedb.setText(_translate("MainWindow", "Update DB"))
+        self.le_command.setText(_translate("MainWindow", "eix"))
+
+class Category:
+    def __init__(self):
+        self.UID=1
+        self.PUID=0
+        self.Name=''
+        self.Packages=[]
+
+class Package:
+    def __init__(self):
+        self.UID=0
+        self.PUID=0
+        self.Name=''
+        self.Description=''
+        self.Homepage=''
+        self.Installed=[]
+        self.Available=[]
+
+class Installed:
+    def __init__(self):
+        self.UID=0
+        self.PUID=0
+        self.Version=''
+        self.Use=''
+        self.Homepage='Installed ->'
+
+class Available:
+    def __init__(self):
+        self.UID=0
+        self.PUID=0
+        self.Version=''
+        self.Use=''
+        self.Homepage='Available ->'
+
+class Result:
+    def __init__(self):
+        self.UID=0 
+        self.PUID=0
+        self.Category=''
+        self.Name='' 
+        self.Description=''
+        self.Homepage='' 
+        self.Version='' 
+        self.Use=''
+
+class MainWindow(QMainWindow, Ui_MainWindow):
+    def __init__(self, parent=None):
+        super(MainWindow, self).__init__(parent)
+        self.setupUi(self)
+        self.cb_option={
+            'cb_stable':[self.cb_stable,'--stable'],
+            'cb_testing':[self.cb_testing,'--testing'],
+            'cb_installed':[self.cb_installed,'--installed'],
+            'cb_overlay':[self.cb_overlay,'--overlay'],
+            }
+        self.rb_option={
+            'rb_decription':[self.rb_decription,'--description'], 
+            'rb_use_disabled':[self.rb_use_disabled,'--installed-without-use'],  
+            'rb_any':[self.rb_any,'--any'], 
+            'rb_name':[self.rb_name,'--name'], 
+            'rb_category':[self.rb_category,'--category'], 
+            'rb_iuse':[self.rb_iuse,'--use'], 
+            'rb_use_enabled':[self.rb_use_enabled,'--installed-with-use'], 
+            }
+        self.find={
+            'Category':[re.compile('^\[[0-9I]\] [A-z0-9]|^\* [A-z0-9]'), self.getCat, 0], 
+            'Name':[re.compile('^\[[0-9I]\] [A-z0-9]|^\* [A-z0-9]'), self.getName, 1], 
+            'Description':[re.compile('Description:'), self.getDesc, 2], 
+            'Homepage':[re.compile('Homepage:'), self.getHome, 3], 
+            'Installed':[re.compile('Installed versions:'), self.getInstVers, 4],
+            'Installed_use':[re.compile('Installed versions:'), self.getIuse, 5], 
+            'Available':[re.compile('Available versions:'), self.getAvailVers, 6],
+            'Available_use':[re.compile('\{.*\}'), self.getAuse, 7],
+            'avail_ver_single':re.compile('(\)|[0-9]|c|\]) [0-9~\*\[]'),
+            'avail_ver_multi':re.compile('([0-9]|c) [0-9~\*\[]'),
+            }
+        self.cats=0
+
+    def on_le_search_returnPressed(self):
+        self.on_pb_search_released()
+    
+    def on_pb_expand_pkg_released(self):
+        model=self.tv_results.model()
+        for a in range(0,self.cats+1):
+            self.tv_results.expand(model.createIndex(a,1))
+
+    def on_pb_expand_all_released(self):
+        self.tv_results.expandAll()
+
+    def on_pb_collapse_released(self):
+        self.tv_results.collapseAll()
+        
+    def on_pb_search_released(self):
+        options=['eix','-n']
+        for rb in self.rb_option:
+            if self.rb_option[rb][0].isChecked():
+                options.append(self.rb_option[rb][1])
+                break
+        for cb in self.cb_option:
+            if self.cb_option[cb][0].isChecked():
+                options.append(self.cb_option[cb][1])
+        terms=re.sub(' ','|',self.le_search.text())
+        options.append(terms)
+        self.le_command.setText(' '.join(options))
+        self.doSearch(options)
+        
+    def doSearch(self, options):
+        process=subprocess.Popen(options,encoding='utf-8',stdout=subprocess.PIPE, env={'EIX_LIMIT':'0', 'HOME':'$HOME'})
+        results=[]
+        result=[]
+        in_result=False
+        starter=re.compile('^\[[0-9I]\] [A-z0-9]|^\* [A-z0-9]')
+        overlay=re.compile('^\[[0-9]\] "')
+        while True:
+            output = process.stdout.readline()
+            if output == '' and process.poll() is not None:
+                break
+            if starter.match(output):
+                in_result=True
+            elif output=='\n':
+                in_result=False
+            elif overlay.match(output) and not in_result:
+                list=output.split(' ')
+                result=['* Overlays/%s: %s'%(list[1][1:-1],list[0]),'Description: %s'%list[2]]
+                in_result=False
+            if output and in_result:
+                result.append(output.strip())
+            elif result and not in_result:
+                results.append(result)
+                result=[]
+        model = self.createResultsModel(self)
+        uid=1
+        cats=[]
+        self.l_res_count.setText('Results: %s'%len(results))
+        for result in results:
+            cats,uid=self.formatResult(cats,uid,result)
+        ex_cats=self.sortResults(cats)
+        self.addResults(model,ex_cats) 
+        self.cats=len(cats)
+        self.tv_results.setModel(model)
+            
+    def formatResult(self,cats,uid,result):
+        cat=None
+        in_avail=False      
+        for field in result:
+            if self.find['Category'][0].search(field):
+                cat_name=self.find['Category'][1](field)
+                for pcat in cats:
+                    if pcat.Name==cat_name:
+                        cat=pcat
+                        break
+                if not cat:
+                    cat=Category()
+                    cat.Name=cat_name
+                    cat.UID=uid
+                    cats.append(cat)
+                    uid+=1
+                pkg=Package()
+                pkg.Name=self.find['Name'][1](field)
+                pkg.UID=uid
+                uid+=1
+                pkg.PUID=cat.UID
+                cat.Packages.append(pkg)
+                continue
+            if self.find['Description'][0].search(field):
+                in_avail=False                
+                pkg.Description=self.find['Description'][1](field)
+                continue
+            if self.find['Homepage'][0].search(field):
+                in_avail=False                
+                pkg.Homepage=self.find['Homepage'][1](field)
+                continue
+            if self.find['Installed'][0].search(field):
+                in_avail=False
+                for installed,use in self.find['Installed'][1](field):
+                    inst=Installed()
+                    inst.Version=installed
+                    inst.Use='Use flags: %s'%use
+                    inst.PUID=pkg.UID
+                    inst.UID=uid
+                    uid+=1
+                    pkg.Installed.append(inst)
+                continue
+            if self.find['Available'][0].search(field):
+                in_avail=True               
+                versions=self.find['Available'][1](field,self.find['avail_ver_single'])
+                for version in versions:
+                    if version=='':continue
+                    avail=Available()
+                    avail.Version=version
+                    avail.PUID=pkg.UID
+                    avail.UID=uid
+                    avail.Use='Use flags: %s'%self.getAuse(field)
+                    uid+=1 
+                    pkg.Available.append(avail)
+                if self.find['Available_use'][0].search(field):
+                    in_avail=False
+                    use=self.find['Available_use'][1](field)
+                    if use:
+                        for avail in pkg.Available:
+                            avail.Use='Use flags: %s'%use
+                continue
+            if self.find['Available_use'][0].search(field):
+                in_avail=False
+                use=self.find['Available_use'][1](field,)
+                if use:
+                    for avail in pkg.Available:
+                        avail.Use='Use flags: %s'%use
+                continue
+            if in_avail:
+                versions=self.find['Available'][1](field,self.find['avail_ver_multi'])
+                for version in versions:
+                    avail=Available()
+                    avail.Version=version
+                    avail.PUID=pkg.UID
+                    avail.UID=uid
+                    uid+=1 
+                    pkg.Available.append(avail)
+
+        return cats,uid    
+
+    def sortResults(self, results):
+        sorted=[]
+        for cat in results:
+            result=Result()
+            result.UID=cat.UID
+            result.Category=cat.Name
+            sorted.append(result)
+            for pkg in cat.Packages:
+                result=Result()
+                result.Name=pkg.Name
+                result.UID=pkg.UID
+                result.PUID=pkg.PUID
+                result.Description=pkg.Description
+                result.Homepage=pkg.Homepage
+                sorted.append(result)
+                for inst in pkg.Installed:
+                    result=Result()
+                    result.UID=inst.UID
+                    result.PUID=inst.PUID
+                    result.Name=inst.Homepage
+                    result.Description=inst.Version
+                    result.Homepage=inst.Use
+                    sorted.append(result)
+                for avail in pkg.Available:
+                    if avail.Version[0]=='(' and avail.Version[len(avail.Version)-1]==')': continue
+                    result=Result()
+                    result.UID=avail.UID
+                    result.PUID=avail.PUID
+                    result.Name=avail.Homepage
+                    result.Description=avail.Version
+                    result.Homepage=avail.Use
+                    sorted.append(result)
+        return sorted
+                
+    def getName(self, str):
+        return str.split('/')[1]
+
+    def getCat(self, str):
+        return str.split(' ')[1].split('/')[0]
+    
+    def getAvailVers(self,str,RE):
+        result=[]
+        use=self.getAuse(str)
+        if use: str=str[:str.find('{')]
+        str=self.clean(str)    
+        match=RE.search(str)
+        while match:
+            ver=str[:match.start()+1]
+            result.append(ver)
+            str=str[match.end()-1:]
+            match=RE.search(str)
+        result.append(str)
+        return result
+    
+    def getInstVers(self, str):
+        result=[]
+        str=re.sub('Installed versions: *','',str)
+        match=re.search('\) [0-9]',str)
+        while match:
+            ver=str[:match.start()+1]
+            use=self.getIuse(ver)
+            if use: ver=ver[:ver.rfind('(')]
+            ver=self.clean(ver)
+            result.append([ver,use])
+            str=str[match.end()-1:]
+            match=re.search('\) [0-9]',str)
+        use=self.getIuse(str)
+        if use: str=str[:str.rfind('(')]
+        str=self.clean(str)
+        result.append([str,use])
+        return result
+
+    def getHome(self, str):
+        t=self.find['Homepage'][0].match(str)
+        home=str[t.end()+1:].strip()
+        return home
+
+    def getDesc(self, str):
+        t=self.find['Description'][0].match(str)
+        desc=str[t.end()+1:].strip()
+        return desc
+        
+    def getIuse(self, str):
+        iuse=''
+        match=re.search('\)\([A-z0-9\-]',str)
+        if match:
+            iuse=str[match.end()-1:str.rfind(')')]
+        return iuse
+
+    def getAuse(self, str):
+        t=self.find['Available_use'][0].search(str)
+        if t:
+            return str[t.start()+1:t.end()-1]
+        else:
+            return ''
+
+    def clean(self,str):
+        strip={ '\^[a-z]{1,3}':'','\*l':'','\(~\)':'~','Available versions: *':'',
+                '\(([0-9]{2}:){2}[0-9]{2} ([0-9]{2}/){2}[0-9]{2}\)':''}
+        for RE in strip:
+            str=re.sub(RE,strip[RE],str)
+        return str
+    
+    def createResultsModel(self,parent):
+        headers=['Category','Name','Description','Homepage' ]
+        model = QStandardItemModel()
+        model.setHorizontalHeaderLabels(headers)
+        return model
+
+    def addResults(self,model,results):
+        items={}
+        for result in results:
+            if result.PUID==0:
+                parent=model.invisibleRootItem()
+            else:
+                parent=items[result.PUID]
+            try:
+                parent.appendRow([  QStandardItem(result.Category), 
+                                    QStandardItem(result.Name), 
+                                    QStandardItem(result.Description), 
+                                    QStandardItem(result.Homepage),
+                                ])
+            except:
+                print(result.Category,result.Name,result.Description,result.Homepage)
+                sys.exit()
+            items[result.UID] = parent.child(parent.rowCount()-1)
+        return model
+
+    def on_pb_updatedb_released(self):
+        child=subprocess.Popen(['sudo','eix-update'])
+        child.wait()
+        sys.argv[0]
+
+if __name__ == "__main__":
+    app = QtWidgets.QApplication(sys.argv)
+    ui = MainWindow()
+    ui.show()
+    sys.exit(app.exec_())
diff --git a/pyeix/ui/Ui_mainwindow.py b/pyeix/ui/Ui_mainwindow.py
new file mode 100644 (file)
index 0000000..10ae172
--- /dev/null
@@ -0,0 +1,175 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file '/home/andrew/Projects/pyeix/ui/mainwindow.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.1
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again.  Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore,QtWidgets
+
+
+class Ui_MainWindow(object):
+    def setupUi(self, MainWindow):
+        MainWindow.setObjectName("MainWindow")
+        MainWindow.resize(938, 483)
+        MainWindow.setMinimumSize(QtCore.QSize(460, 300))
+        self.centralwidget = QtWidgets.QWidget(MainWindow)
+        self.centralwidget.setObjectName("centralwidget")
+        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
+        self.gridLayout.setObjectName("gridLayout")
+        self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
+        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
+        self.le_search = QtWidgets.QLineEdit(self.centralwidget)
+        self.le_search.setObjectName("le_search")
+        self.horizontalLayout_2.addWidget(self.le_search)
+        self.pb_search = QtWidgets.QPushButton(self.centralwidget)
+        self.pb_search.setObjectName("pb_search")
+        self.horizontalLayout_2.addWidget(self.pb_search)
+        self.gridLayout.addLayout(self.horizontalLayout_2, 0, 0, 1, 1)
+        self.horizontalLayout = QtWidgets.QHBoxLayout()
+        self.horizontalLayout.setObjectName("horizontalLayout")
+        self.cb_stable = QtWidgets.QCheckBox(self.centralwidget)
+        self.cb_stable.setObjectName("cb_stable")
+        self.horizontalLayout.addWidget(self.cb_stable)
+        self.cb_testing = QtWidgets.QCheckBox(self.centralwidget)
+        self.cb_testing.setObjectName("cb_testing")
+        self.horizontalLayout.addWidget(self.cb_testing)
+        self.cb_installed = QtWidgets.QCheckBox(self.centralwidget)
+        self.cb_installed.setObjectName("cb_installed")
+        self.horizontalLayout.addWidget(self.cb_installed)
+        self.cb_overlay = QtWidgets.QCheckBox(self.centralwidget)
+        self.cb_overlay.setTristate(False)
+        self.cb_overlay.setObjectName("cb_overlay")
+        self.horizontalLayout.addWidget(self.cb_overlay)
+        self.gridLayout.addLayout(self.horizontalLayout, 1, 0, 1, 1)
+        self.horizontalLayout_6 = QtWidgets.QHBoxLayout()
+        self.horizontalLayout_6.setObjectName("horizontalLayout_6")
+        self.rb_any = QtWidgets.QRadioButton(self.centralwidget)
+        self.rb_any.setObjectName("rb_any")
+        self.horizontalLayout_6.addWidget(self.rb_any)
+        self.rb_decription = QtWidgets.QRadioButton(self.centralwidget)
+        self.rb_decription.setObjectName("rb_decription")
+        self.horizontalLayout_6.addWidget(self.rb_decription)
+        self.rb_category = QtWidgets.QRadioButton(self.centralwidget)
+        self.rb_category.setObjectName("rb_category")
+        self.horizontalLayout_6.addWidget(self.rb_category)
+        self.rb_name = QtWidgets.QRadioButton(self.centralwidget)
+        self.rb_name.setObjectName("rb_name")
+        self.horizontalLayout_6.addWidget(self.rb_name)
+        self.gridLayout.addLayout(self.horizontalLayout_6, 2, 0, 1, 1)
+        self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
+        self.horizontalLayout_5.setObjectName("horizontalLayout_5")
+        self.rb_iuse = QtWidgets.QRadioButton(self.centralwidget)
+        self.rb_iuse.setObjectName("rb_iuse")
+        self.horizontalLayout_5.addWidget(self.rb_iuse)
+        self.rb_use_enabled = QtWidgets.QRadioButton(self.centralwidget)
+        self.rb_use_enabled.setObjectName("rb_use_enabled")
+        self.horizontalLayout_5.addWidget(self.rb_use_enabled)
+        self.rb_use_disabled = QtWidgets.QRadioButton(self.centralwidget)
+        self.rb_use_disabled.setObjectName("rb_use_disabled")
+        self.horizontalLayout_5.addWidget(self.rb_use_disabled)
+        self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
+        self.horizontalLayout_4.setObjectName("horizontalLayout_4")
+        self.l_res_count = QtWidgets.QLabel(self.centralwidget)
+        self.l_res_count.setObjectName("l_res_count")
+        self.horizontalLayout_4.addWidget(self.l_res_count)
+        self.horizontalLayout_5.addLayout(self.horizontalLayout_4)
+        self.gridLayout.addLayout(self.horizontalLayout_5, 3, 0, 1, 1)
+        self.tv_results = QtWidgets.QTreeView(self.centralwidget)
+        self.tv_results.setObjectName("tv_results")
+        self.gridLayout.addWidget(self.tv_results, 4, 0, 1, 1)
+        self.line = QtWidgets.QFrame(self.centralwidget)
+        self.line.setFrameShape(QtWidgets.QFrame.HLine)
+        self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
+        self.line.setObjectName("line")
+        self.gridLayout.addWidget(self.line, 5, 0, 1, 1)
+        self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
+        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
+        self.pb_expand_all = QtWidgets.QPushButton(self.centralwidget)
+        self.pb_expand_all.setObjectName("pb_expand_all")
+        self.horizontalLayout_3.addWidget(self.pb_expand_all)
+        self.pb_expand_pkg = QtWidgets.QPushButton(self.centralwidget)
+        self.pb_expand_pkg.setObjectName("pb_expand_pkg")
+        self.horizontalLayout_3.addWidget(self.pb_expand_pkg)
+        self.pb_collapse = QtWidgets.QPushButton(self.centralwidget)
+        self.pb_collapse.setObjectName("pb_collapse")
+        self.horizontalLayout_3.addWidget(self.pb_collapse)
+        self.pb_updatedb = QtWidgets.QPushButton(self.centralwidget)
+        self.pb_updatedb.setObjectName("pb_updatedb")
+        self.horizontalLayout_3.addWidget(self.pb_updatedb)
+        self.le_command = QtWidgets.QLineEdit(self.centralwidget)
+        self.le_command.setEnabled(False)
+        self.le_command.setObjectName("le_command")
+        self.horizontalLayout_3.addWidget(self.le_command)
+        self.gridLayout.addLayout(self.horizontalLayout_3, 6, 0, 1, 1)
+        MainWindow.setCentralWidget(self.centralwidget)
+        self.menubar = QtWidgets.QMenuBar(MainWindow)
+        self.menubar.setGeometry(QtCore.QRect(0, 0, 938, 26))
+        self.menubar.setObjectName("menubar")
+        MainWindow.setMenuBar(self.menubar)
+        self.statusbar = QtWidgets.QStatusBar(MainWindow)
+        self.statusbar.setObjectName("statusbar")
+        MainWindow.setStatusBar(self.statusbar)
+
+        self.retranslateUi(MainWindow)
+        QtCore.QMetaObject.connectSlotsByName(MainWindow)
+        MainWindow.setTabOrder(self.le_search, self.pb_search)
+        MainWindow.setTabOrder(self.pb_search, self.cb_stable)
+        MainWindow.setTabOrder(self.cb_stable, self.cb_testing)
+        MainWindow.setTabOrder(self.cb_testing, self.cb_installed)
+        MainWindow.setTabOrder(self.cb_installed, self.cb_overlay)
+        MainWindow.setTabOrder(self.cb_overlay, self.rb_any)
+        MainWindow.setTabOrder(self.rb_any, self.rb_decription)
+        MainWindow.setTabOrder(self.rb_decription, self.rb_category)
+        MainWindow.setTabOrder(self.rb_category, self.rb_name)
+        MainWindow.setTabOrder(self.rb_name, self.rb_iuse)
+        MainWindow.setTabOrder(self.rb_iuse, self.rb_use_enabled)
+        MainWindow.setTabOrder(self.rb_use_enabled, self.rb_use_disabled)
+        MainWindow.setTabOrder(self.rb_use_disabled, self.tv_results)
+
+    def retranslateUi(self, MainWindow):
+        _translate = QtCore.QCoreApplication.translate
+        MainWindow.setWindowTitle(_translate("MainWindow", "PyEix"))
+        self.pb_search.setText(_translate("MainWindow", "Search"))
+        self.cb_stable.setToolTip(_translate("MainWindow", "Only match packages with a stable version"))
+        self.cb_stable.setText(_translate("MainWindow", "Stable"))
+        self.cb_testing.setToolTip(_translate("MainWindow", "Only match packages with a testing version"))
+        self.cb_testing.setText(_translate("MainWindow", "Testing"))
+        self.cb_installed.setToolTip(_translate("MainWindow", "Only match installed packages"))
+        self.cb_installed.setText(_translate("MainWindow", "Installed"))
+        self.cb_overlay.setToolTip(_translate("MainWindow", "Only match packages with at least one version in an overlay"))
+        self.cb_overlay.setText(_translate("MainWindow", "Overlay"))
+        self.rb_any.setToolTip(_translate("MainWindow", "Search any field"))
+        self.rb_any.setText(_translate("MainWindow", "Any"))
+        self.rb_decription.setToolTip(_translate("MainWindow", "Search the description field"))
+        self.rb_decription.setText(_translate("MainWindow", "Description"))
+        self.rb_category.setToolTip(_translate("MainWindow", "Search the category field"))
+        self.rb_category.setText(_translate("MainWindow", "Category"))
+        self.rb_name.setToolTip(_translate("MainWindow", "Search the name field"))
+        self.rb_name.setText(_translate("MainWindow", "Name"))
+        self.rb_iuse.setToolTip(_translate("MainWindow", "Search for packages that can have that use flag enabled"))
+        self.rb_iuse.setText(_translate("MainWindow", "Use flags (IUSE)"))
+        self.rb_use_enabled.setToolTip(_translate("MainWindow", "Search for packages installed with that use flag enabled"))
+        self.rb_use_enabled.setText(_translate("MainWindow", "Use enabled"))
+        self.rb_use_disabled.setToolTip(_translate("MainWindow", "Search for packages instealled with that use flag diabled"))
+        self.rb_use_disabled.setText(_translate("MainWindow", "Use Disabled"))
+        self.l_res_count.setText(_translate("MainWindow", "           Results: "))
+        self.pb_expand_all.setText(_translate("MainWindow", "Expand All"))
+        self.pb_expand_pkg.setText(_translate("MainWindow", "Expand Pkgs"))
+        self.pb_collapse.setText(_translate("MainWindow", "Collapse"))
+        self.pb_updatedb.setToolTip(_translate("MainWindow", "<html><head/><body><p>Update eix\'s database (uses sudo)</p></body></html>"))
+        self.pb_updatedb.setText(_translate("MainWindow", "Update DB"))
+        self.le_command.setText(_translate("MainWindow", "eix"))
+
+
+if __name__ == "__main__":
+    import sys
+    app = QtWidgets.QApplication(sys.argv)
+    MainWindow = QtWidgets.QMainWindow()
+    ui = Ui_MainWindow()
+    ui.setupUi(MainWindow)
+    MainWindow.show()
+    sys.exit(app.exec_())
diff --git a/pyeix/ui/__init__.py b/pyeix/ui/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/pyeix/ui/__pycache__/Ui_mainwindow.cpython-39.pyc b/pyeix/ui/__pycache__/Ui_mainwindow.cpython-39.pyc
new file mode 100644 (file)
index 0000000..e43e4ab
Binary files /dev/null and b/pyeix/ui/__pycache__/Ui_mainwindow.cpython-39.pyc differ
diff --git a/pyeix/ui/__pycache__/__init__.cpython-39.pyc b/pyeix/ui/__pycache__/__init__.cpython-39.pyc
new file mode 100644 (file)
index 0000000..c26c6e5
Binary files /dev/null and b/pyeix/ui/__pycache__/__init__.cpython-39.pyc differ
diff --git a/pyeix/ui/__pycache__/mainwindow.cpython-39.pyc b/pyeix/ui/__pycache__/mainwindow.cpython-39.pyc
new file mode 100644 (file)
index 0000000..91e0fdc
Binary files /dev/null and b/pyeix/ui/__pycache__/mainwindow.cpython-39.pyc differ
diff --git a/pyeix/ui/mainwindow.py b/pyeix/ui/mainwindow.py
new file mode 100644 (file)
index 0000000..211fd1c
--- /dev/null
@@ -0,0 +1,367 @@
+# -*- coding: utf-8 -*-
+
+'''
+Module implementing MainWindow.
+'''
+from PyQt5.QtWidgets import QMainWindow
+from PyQt5.QtGui import QStandardItemModel,QStandardItem
+import sys, subprocess, re
+from .Ui_mainwindow import Ui_MainWindow
+
+class Category:
+    def __init__(self):
+        self.UID=1
+        self.PUID=0
+        self.Name=''
+        self.Packages=[]
+
+class Package:
+    def __init__(self):
+        self.UID=0
+        self.PUID=0
+        self.Name=''
+        self.Description=''
+        self.Homepage=''
+        self.Installed=[]
+        self.Available=[]
+
+class Installed:
+    def __init__(self):
+        self.UID=0
+        self.PUID=0
+        self.Version=''
+        self.Use=''
+        self.Homepage='Installed ->'
+
+class Available:
+    def __init__(self):
+        self.UID=0
+        self.PUID=0
+        self.Version=''
+        self.Use=''
+        self.Homepage='Available ->'
+
+class Result:
+    def __init__(self):
+        self.UID=0 
+        self.PUID=0
+        self.Category=''
+        self.Name='' 
+        self.Description=''
+        self.Homepage='' 
+        self.Version='' 
+        self.Use=''
+
+class MainWindow(QMainWindow, Ui_MainWindow):
+    def __init__(self, parent=None):
+        super(MainWindow, self).__init__(parent)
+        self.setupUi(self)
+        self.cb_option={
+            'cb_stable':[self.cb_stable,'--stable'],
+            'cb_testing':[self.cb_testing,'--testing'],
+            'cb_installed':[self.cb_installed,'--installed'],
+            'cb_overlay':[self.cb_overlay,'--overlay'],
+            }
+        self.rb_option={
+            'rb_decription':[self.rb_decription,'--description'], 
+            'rb_use_disabled':[self.rb_use_disabled,'--installed-without-use'],  
+            'rb_any':[self.rb_any,'--any'], 
+            'rb_name':[self.rb_name,'--name'], 
+            'rb_category':[self.rb_category,'--category'], 
+            'rb_iuse':[self.rb_iuse,'--use'], 
+            'rb_use_enabled':[self.rb_use_enabled,'--installed-with-use'], 
+            }
+        self.find={
+            'Category':[re.compile('^\[[0-9I]\] [A-z0-9]|^\* [A-z0-9]'), self.getCat, 0], 
+            'Name':[re.compile('^\[[0-9I]\] [A-z0-9]|^\* [A-z0-9]'), self.getName, 1], 
+            'Description':[re.compile('Description:'), self.getDesc, 2], 
+            'Homepage':[re.compile('Homepage:'), self.getHome, 3], 
+            'Installed':[re.compile('Installed versions:'), self.getInstVers, 4],
+            'Installed_use':[re.compile('Installed versions:'), self.getIuse, 5], 
+            'Available':[re.compile('Available versions:'), self.getAvailVers, 6],
+            'Available_use':[re.compile('\{.*\}'), self.getAuse, 7],
+            'avail_ver_single':re.compile('(\)|[0-9]|c|\]) [0-9~\*\[]'),
+            'avail_ver_multi':re.compile('([0-9]|c) [0-9~\*\[]'),
+            }
+        self.cats=0
+
+    def on_le_search_returnPressed(self):
+        self.on_pb_search_released()
+    
+    def on_pb_expand_pkg_released(self):
+        model=self.tv_results.model()
+        for a in range(0,self.cats+1):
+            self.tv_results.expand(model.createIndex(a,1))
+
+    def on_pb_expand_all_released(self):
+        self.tv_results.expandAll()
+
+    def on_pb_collapse_released(self):
+        self.tv_results.collapseAll()
+        
+    def on_pb_search_released(self):
+        options=['eix','-n']
+        for rb in self.rb_option:
+            if self.rb_option[rb][0].isChecked():
+                options.append(self.rb_option[rb][1])
+                break
+        for cb in self.cb_option:
+            if self.cb_option[cb][0].isChecked():
+                options.append(self.cb_option[cb][1])
+        terms=re.sub(' ','|',self.le_search.text())
+        options.append(terms)
+        self.le_command.setText(' '.join(options))
+        self.doSearch(options)
+        
+    def doSearch(self, options):
+        process=subprocess.Popen(options,encoding='utf-8',stdout=subprocess.PIPE, env={'EIX_LIMIT':'0', 'HOME':'$HOME'})
+        results=[]
+        result=[]
+        in_result=False
+        starter=re.compile('^\[[0-9I]\] [A-z0-9]|^\* [A-z0-9]')
+        overlay=re.compile('^\[[0-9]\] "')
+        while True:
+            output = process.stdout.readline()
+            if output == '' and process.poll() is not None:
+                break
+            if starter.match(output):
+                in_result=True
+            elif output=='\n':
+                in_result=False
+            elif overlay.match(output) and not in_result:
+                list=output.split(' ')
+                result=['* Overlays/%s: %s'%(list[1][1:-1],list[0]),'Description: %s'%list[2]]
+                in_result=False
+            if output and in_result:
+                result.append(output.strip())
+            elif result and not in_result:
+                results.append(result)
+                result=[]
+        model = self.createResultsModel(self)
+        uid=1
+        cats=[]
+        self.l_res_count.setText('Results: %s'%len(results))
+        for result in results:
+            cats,uid=self.formatResult(cats,uid,result)
+        ex_cats=self.sortResults(cats)
+        self.addResults(model,ex_cats) 
+        self.cats=len(cats)
+        self.tv_results.setModel(model)
+            
+    def formatResult(self,cats,uid,result):
+        cat=None
+        in_avail=False      
+        for field in result:
+            if self.find['Category'][0].search(field):
+                cat_name=self.find['Category'][1](field)
+                for pcat in cats:
+                    if pcat.Name==cat_name:
+                        cat=pcat
+                        break
+                if not cat:
+                    cat=Category()
+                    cat.Name=cat_name
+                    cat.UID=uid
+                    cats.append(cat)
+                    uid+=1
+                pkg=Package()
+                pkg.Name=self.find['Name'][1](field)
+                pkg.UID=uid
+                uid+=1
+                pkg.PUID=cat.UID
+                cat.Packages.append(pkg)
+                continue
+            if self.find['Description'][0].search(field):
+                in_avail=False                
+                pkg.Description=self.find['Description'][1](field)
+                continue
+            if self.find['Homepage'][0].search(field):
+                in_avail=False                
+                pkg.Homepage=self.find['Homepage'][1](field)
+                continue
+            if self.find['Installed'][0].search(field):
+                in_avail=False
+                for installed,use in self.find['Installed'][1](field):
+                    inst=Installed()
+                    inst.Version=installed
+                    inst.Use='Use flags: %s'%use
+                    inst.PUID=pkg.UID
+                    inst.UID=uid
+                    uid+=1
+                    pkg.Installed.append(inst)
+                continue
+            if self.find['Available'][0].search(field):
+                in_avail=True               
+                versions=self.find['Available'][1](field,self.find['avail_ver_single'])
+                for version in versions:
+                    if version=='':continue
+                    avail=Available()
+                    avail.Version=version
+                    avail.PUID=pkg.UID
+                    avail.UID=uid
+                    avail.Use='Use flags: %s'%self.getAuse(field)
+                    uid+=1 
+                    pkg.Available.append(avail)
+                if self.find['Available_use'][0].search(field):
+                    in_avail=False
+                    use=self.find['Available_use'][1](field)
+                    if use:
+                        for avail in pkg.Available:
+                            avail.Use='Use flags: %s'%use
+                continue
+            if self.find['Available_use'][0].search(field):
+                in_avail=False
+                use=self.find['Available_use'][1](field,)
+                if use:
+                    for avail in pkg.Available:
+                        avail.Use='Use flags: %s'%use
+                continue
+            if in_avail:
+                versions=self.find['Available'][1](field,self.find['avail_ver_multi'])
+                for version in versions:
+                    avail=Available()
+                    avail.Version=version
+                    avail.PUID=pkg.UID
+                    avail.UID=uid
+                    uid+=1 
+                    pkg.Available.append(avail)
+
+        return cats,uid    
+
+    def sortResults(self, results):
+        sorted=[]
+        for cat in results:
+            result=Result()
+            result.UID=cat.UID
+            result.Category=cat.Name
+            sorted.append(result)
+            for pkg in cat.Packages:
+                result=Result()
+                result.Name=pkg.Name
+                result.UID=pkg.UID
+                result.PUID=pkg.PUID
+                result.Description=pkg.Description
+                result.Homepage=pkg.Homepage
+                sorted.append(result)
+                for inst in pkg.Installed:
+                    result=Result()
+                    result.UID=inst.UID
+                    result.PUID=inst.PUID
+                    result.Name=inst.Homepage
+                    result.Description=inst.Version
+                    result.Homepage=inst.Use
+                    sorted.append(result)
+                for avail in pkg.Available:
+                    if avail.Version[0]=='(' and avail.Version[len(avail.Version)-1]==')': continue
+                    result=Result()
+                    result.UID=avail.UID
+                    result.PUID=avail.PUID
+                    result.Name=avail.Homepage
+                    result.Description=avail.Version
+                    result.Homepage=avail.Use
+                    sorted.append(result)
+        return sorted
+                
+                
+    def getName(self, str):
+        return str.split('/')[1]
+
+    def getCat(self, str):
+        return str.split(' ')[1].split('/')[0]
+    
+    def getAvailVers(self,str,RE):
+        result=[]
+        use=self.getAuse(str)
+        if use: str=str[:str.find('{')]
+        str=self.clean(str)        
+        match=RE.search(str)
+        while match:
+            ver=str[:match.start()+1]
+            result.append(ver)
+            str=str[match.end()-1:]
+            match=RE.search(str)
+        result.append(str)
+        return result
+    
+    def getInstVers(self, str):
+        result=[]
+        str=re.sub('Installed versions: *','',str)
+        match=re.search('\) [0-9]',str)
+        while match:
+            ver=str[:match.start()+1]
+            use=self.getIuse(ver)
+            if use: ver=ver[:ver.rfind('(')]
+            ver=self.clean(ver)
+            result.append([ver,use])
+            str=str[match.end()-1:]
+            match=re.search('\) [0-9]',str)
+        use=self.getIuse(str)
+        if use: str=str[:str.rfind('(')]
+        str=self.clean(str)
+        result.append([str,use])
+        return result
+
+    def getHome(self, str):
+        t=self.find['Homepage'][0].match(str)
+        home=str[t.end()+1:].strip()
+        return home
+
+    def getDesc(self, str):
+        t=self.find['Description'][0].match(str)
+        desc=str[t.end()+1:].strip()
+        return desc
+        
+    def getIuse(self, str):
+        iuse=''
+        match=re.search('\)\([A-z0-9\-]',str)
+        if match:
+            iuse=str[match.end()-1:str.rfind(')')]
+        return iuse
+
+    def getAuse(self, str):
+        t=self.find['Available_use'][0].search(str)
+        if t:
+            return str[t.start()+1:t.end()-1]
+        else:
+            return ''
+
+    def clean(self,str):
+        strip={ '\^[a-z]{1,3}':'','\*l':'','\(~\)':'~','Available versions: *':'',
+                '\(([0-9]{2}:){2}[0-9]{2} ([0-9]{2}/){2}[0-9]{2}\)':''}
+        for RE in strip:
+            str=re.sub(RE,strip[RE],str)
+        return str
+    
+    def createResultsModel(self,parent):
+        headers=['Category','Name','Description','Homepage' ]
+        model = QStandardItemModel()
+        model.setHorizontalHeaderLabels(headers)
+        return model
+
+    def addResults(self,model,results):
+        #headers=['Category','Name','Description','Homepage' ]
+        items={}
+        for result in results:
+            if result.PUID==0:
+                parent=model.invisibleRootItem()
+            else:
+                parent=items[result.PUID]
+            try:
+                parent.appendRow([  QStandardItem(result.Category), 
+                                    QStandardItem(result.Name), 
+                                    QStandardItem(result.Description), 
+                                    QStandardItem(result.Homepage),
+                                ])
+            except:
+                print(result.Category,result.Name,result.Description,result.Homepage)
+                sys.exit()
+            items[result.UID] = parent.child(parent.rowCount()-1)
+
+        #for index in headers:
+        #    model.setData(model.index(0,self.find[index][2]),results[index])
+        return model
+
+    def on_pb_updatedb_released(self):
+        child=subprocess.Popen(['sudo','eix-update'])
+        child.wait()
+        sys.argv[0]
diff --git a/pyeix/ui/mainwindow.ui b/pyeix/ui/mainwindow.ui
new file mode 100644 (file)
index 0000000..e81d648
--- /dev/null
@@ -0,0 +1,264 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>938</width>
+    <height>483</height>
+   </rect>
+  </property>
+  <property name="minimumSize">
+   <size>
+    <width>460</width>
+    <height>300</height>
+   </size>
+  </property>
+  <property name="windowTitle">
+   <string>PyEix</string>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <layout class="QGridLayout" name="gridLayout">
+    <item row="0" column="0">
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <item>
+       <widget class="QLineEdit" name="le_search"/>
+      </item>
+      <item>
+       <widget class="QPushButton" name="pb_search">
+        <property name="text">
+         <string>Search</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </item>
+    <item row="1" column="0">
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <item>
+       <widget class="QCheckBox" name="cb_stable">
+        <property name="toolTip">
+         <string>Only match packages with a stable version</string>
+        </property>
+        <property name="text">
+         <string>Stable</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="cb_testing">
+        <property name="toolTip">
+         <string>Only match packages with a testing version</string>
+        </property>
+        <property name="text">
+         <string>Testing</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="cb_installed">
+        <property name="toolTip">
+         <string>Only match installed packages</string>
+        </property>
+        <property name="text">
+         <string>Installed</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="cb_overlay">
+        <property name="toolTip">
+         <string>Only match packages with at least one version in an overlay</string>
+        </property>
+        <property name="text">
+         <string>Overlay</string>
+        </property>
+        <property name="tristate">
+         <bool>false</bool>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </item>
+    <item row="2" column="0">
+     <layout class="QHBoxLayout" name="horizontalLayout_6">
+      <item>
+       <widget class="QRadioButton" name="rb_any">
+        <property name="toolTip">
+         <string>Search any field</string>
+        </property>
+        <property name="text">
+         <string>Any</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QRadioButton" name="rb_decription">
+        <property name="toolTip">
+         <string>Search the description field</string>
+        </property>
+        <property name="text">
+         <string>Description</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QRadioButton" name="rb_category">
+        <property name="toolTip">
+         <string>Search the category field</string>
+        </property>
+        <property name="text">
+         <string>Category</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QRadioButton" name="rb_name">
+        <property name="toolTip">
+         <string>Search the name field</string>
+        </property>
+        <property name="text">
+         <string>Name</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </item>
+    <item row="3" column="0">
+     <layout class="QHBoxLayout" name="horizontalLayout_5">
+      <item>
+       <widget class="QRadioButton" name="rb_iuse">
+        <property name="toolTip">
+         <string>Search for packages that can have that use flag enabled</string>
+        </property>
+        <property name="text">
+         <string>Use flags (IUSE)</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QRadioButton" name="rb_use_enabled">
+        <property name="toolTip">
+         <string>Search for packages installed with that use flag enabled</string>
+        </property>
+        <property name="text">
+         <string>Use enabled</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QRadioButton" name="rb_use_disabled">
+        <property name="toolTip">
+         <string>Search for packages instealled with that use flag diabled</string>
+        </property>
+        <property name="text">
+         <string>Use Disabled</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout_4">
+        <item>
+         <widget class="QLabel" name="l_res_count">
+          <property name="text">
+           <string>           Results: </string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </item>
+    <item row="4" column="0">
+     <widget class="QTreeView" name="tv_results"/>
+    </item>
+    <item row="5" column="0">
+     <widget class="Line" name="line">
+      <property name="orientation">
+       <enum>Qt::Horizontal</enum>
+      </property>
+     </widget>
+    </item>
+    <item row="6" column="0">
+     <layout class="QHBoxLayout" name="horizontalLayout_3">
+      <item>
+       <widget class="QPushButton" name="pb_expand_all">
+        <property name="text">
+         <string>Expand All</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="pb_expand_pkg">
+        <property name="text">
+         <string>Expand Pkgs</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="pb_collapse">
+        <property name="text">
+         <string>Collapse</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="pb_updatedb">
+        <property name="toolTip">
+         <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Update eix's database (uses sudo)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+        </property>
+        <property name="text">
+         <string>Update DB</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLineEdit" name="le_command">
+        <property name="enabled">
+         <bool>false</bool>
+        </property>
+        <property name="text">
+         <string>eix</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>938</width>
+     <height>26</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <tabstops>
+  <tabstop>le_search</tabstop>
+  <tabstop>pb_search</tabstop>
+  <tabstop>cb_stable</tabstop>
+  <tabstop>cb_testing</tabstop>
+  <tabstop>cb_installed</tabstop>
+  <tabstop>cb_overlay</tabstop>
+  <tabstop>rb_any</tabstop>
+  <tabstop>rb_decription</tabstop>
+  <tabstop>rb_category</tabstop>
+  <tabstop>rb_name</tabstop>
+  <tabstop>rb_iuse</tabstop>
+  <tabstop>rb_use_enabled</tabstop>
+  <tabstop>rb_use_disabled</tabstop>
+  <tabstop>tv_results</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+ <slots>
+  <slot>on_pb_search_clicked()</slot>
+ </slots>
+</ui>