summaryrefslogtreecommitdiffstats
path: root/build_tools/larch7/larch0/gui/front
diff options
context:
space:
mode:
Diffstat (limited to 'build_tools/larch7/larch0/gui/front')
-rw-r--r--build_tools/larch7/larch0/gui/front/docviewer.py68
-rw-r--r--build_tools/larch7/larch0/gui/front/editor.py115
-rw-r--r--build_tools/larch7/larch0/gui/front/logview.py94
-rw-r--r--build_tools/larch7/larch0/gui/front/mainwindow.py132
-rw-r--r--build_tools/larch7/larch0/gui/front/page_installation.py188
-rw-r--r--build_tools/larch7/larch0/gui/front/page_larchify.py248
-rw-r--r--build_tools/larch7/larch0/gui/front/page_medium.py320
-rw-r--r--build_tools/larch7/larch0/gui/front/page_mediumprofile.py87
-rw-r--r--build_tools/larch7/larch0/gui/front/page_project.py203
-rw-r--r--build_tools/larch7/larch0/gui/front/uim.py1327
10 files changed, 0 insertions, 2782 deletions
diff --git a/build_tools/larch7/larch0/gui/front/docviewer.py b/build_tools/larch7/larch0/gui/front/docviewer.py
deleted file mode 100644
index a0af083..0000000
--- a/build_tools/larch7/larch0/gui/front/docviewer.py
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/usr/bin/env python
-#
-# docviewer.py
-#
-# (c) Copyright 2009-2010 Michael Towers (larch42 at googlemail dot com)
-#
-# This file is part of the larch project.
-#
-# larch is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# larch is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with larch; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-#
-#----------------------------------------------------------------------------
-# 2010.06.24
-
-
-import os
-
-
-class DocViewer:
- def __init__(self):
- self.index = self._getPage('index.html')
- self.homepath = None
- ui.widgetlist(fss('fetch_layout', 'docviewer.uim'))
-
- ui.connectlist(
- ('doc:hide*clicked', self._hide),
- ('doc:back*clicked', self._back),
- ('doc:forward*clicked', self._forward),
- ('doc:home*clicked', self.gohome),
- ('doc:parent*clicked', self.goto),
- (':docs*clicked', self._show),
- )
-
- def _show(self):
- ui.runningtab(3)
-
- def _hide(self):
- ui.runningtab()
-
- def _back(self):
- ui.command('doc:content.prev')
-
- def _forward(self):
- ui.command('doc:content.next')
-
- def _getPage(self, page):
- return fss('get_docs_url', page)
-
- def gohome(self, home=None):
- if home:
- self.homepath = self._getPage(home)
- self.goto(self.homepath)
-
- def goto(self, path=None):
- if not path:
- path = self.index
- ui.command('doc:content.setUrl', path)
diff --git a/build_tools/larch7/larch0/gui/front/editor.py b/build_tools/larch7/larch0/gui/front/editor.py
deleted file mode 100644
index 649f55c..0000000
--- a/build_tools/larch7/larch0/gui/front/editor.py
+++ /dev/null
@@ -1,115 +0,0 @@
-#!/usr/bin/env python
-#
-# editor.py
-#
-# (c) Copyright 2009-2010 Michael Towers (larch42 at googlemail dot com)
-#
-# This file is part of the larch project.
-#
-# larch is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# larch is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with larch; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-#
-#----------------------------------------------------------------------------
-# 2010.06.24
-
-class Editor:
- def __init__(self):
- ui.widgetlist(fss('fetch_layout', 'editor.uim'))
- ui.connectlist(
- ('edit:ok*clicked', self.ok),
- ('edit:cancel*clicked', self.cancel),
- ('edit:revert*clicked', self.dorevert),
- ('edit:copy*clicked', self.copy),
- ('edit:cut*clicked', self.cut),
- ('edit:paste*clicked', self.paste),
- ('edit:undo*clicked', self.undo),
- ('edit:redo*clicked', self.redo),
- )
-
- def start(self, title, endcall, text='', revert=None):
- ui.command('edit:title.markup', ['h3', title])
- self.endcall = endcall
- self.revert = revert
- try:
- self.text0 = revert() if text == None else text
- except:
- run_error("BUG: Editor - no revert function?")
- ui.command('edit:content.text', self.text0)
- ui.runningtab(4)
-
- def ok(self):
- self.endcall(ui.command('edit:content.get'))
- ui.runningtab()
-
- def cancel(self):
- ui.runningtab()
-
- def dorevert(self):
- if self.revert:
- self.text0 = self.revert()
- ui.command('edit:content.text', self.text0)
-
- def copy(self):
- ui.command('edit:content.copy')
-
- def cut(self):
- ui.command('edit:content.cut')
-
- def paste(self):
- ui.command('edit:content.paste')
-
- def undo(self):
- ui.command('edit:content.undo')
-
- def redo(self):
- ui.command('edit:content.redo')
-
- def edit(self, fname, source=None, label=None, filter=None):
- """Files (<fname> and <source>) can be either an absolute path or else
- relative to the profile directory, the application base directory
- or the working directory. Relative paths are determined by the
- prefixes 'profile:', 'base:' or 'working:'.
- If the file <fname> already exists its contents will be taken as the
- starting point, otherwise the file <source>, which may also be an
- empty string, will be read in.
- Whichever file is available its contents can be filtered by an
- optional 'filter' function, which takes the file contents as a
- string as argument and returns the transformed contents as another
- string.
- """
- def revert():
- """If a file is addressed by 'source' revert to its contents,
- if source is "", clear the contents, otherwise revert to the
- contents as they were before entering the editor.
- """
- return textsrc if source != None else text0
-
- def endfile(text):
- t = text.encode("utf8")
- if t and (t[-1] != "\n"):
- t += "\n"
- fss('savefile', fname, text)
-
- if source != None:
- textsrc = "" if source == "" else fss('readfile', source,
- filter=filter)
- # Read the file, if it exists, else return None
- text0 = fss('readfile', fname, filter=filter, trap=False)
- if text0 == None:
- assert source != None # The file must be present
- text0 = textsrc
- if not label:
- label = ui.command('editor_data.get', 'msg_dflt') % fname
- self.start(label, endfile, text0, revert)
-
diff --git a/build_tools/larch7/larch0/gui/front/logview.py b/build_tools/larch7/larch0/gui/front/logview.py
deleted file mode 100644
index b9d2ac3..0000000
--- a/build_tools/larch7/larch0/gui/front/logview.py
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/usr/bin/env python
-#
-# logview.py
-#
-# (c) Copyright 2009-2010 Michael Towers (larch42 at googlemail dot com)
-#
-# This file is part of the larch project.
-#
-# larch is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# larch is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with larch; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-#
-#----------------------------------------------------------------------------
-# 2010.07.09
-
-import locale
-# Try to work around problems when the system encoding is not utf8
-encoding = locale.getdefaultlocale()[1]
-if encoding == "UTF8":
- encoding = None
-
-#TODO: progress bar?
-class Progress:
- def __init__(self):
- self.active = False
- ui.widgetlist(fss('fetch_layout', 'progress.uim'))
- ui.connect('progress:done*clicked', self._done)
-
- def _done(self):
- self.active = False
- ui.runningtab(0)
-
- def start(self):
- # Set busy cursor on the progress area
- ui.command('progress:page.busycursor', True)
- # Initialize widgets
- ui.command("progress:text.text")
- ui.command("progress:progress.text")
- ui.command("progress:done.enable", False)
- ui.command("progress:cancel.enable", True)
- self.active = True
- ui.runningtab(1)
-
- def end(self, auto=False):
- ui.command("progress:cancel.enable", False)
- ui.command("progress:done.enable", True)
- # Clear busy cursor on the progress area
- ui.command('progress:page.busycursor', True)
- ui.command('progress:page.busycursor', False)
- if auto:
- self._done()
-
- def addLine(self, line):
- # Try to work around problems when the system encoding is not utf8
- if encoding:
- line = line.decode(self.encoding, "replace").encode("UTF8")
- ui.command("progress:text.append_and_scroll", line)
- logger.addLine(line)
-
- def set(self, text=""):
- ui.command("progress:progress.text", text)
-
-
-class Logger:
- def __init__(self):
- ui.widgetlist(fss('fetch_layout', 'logger.uim'))
- ui.connectlist(
- ('log:clear*clicked', self.clear),
- ('log:hide*clicked', self._hide),
- (':showlog*clicked', self._show),
- )
-
- def clear(self):
- ui.command('log:text.text')
-
- def addLine(self, line):
- # Try to work around problems when the system encoding is not utf8
- ui.command('log:text.append_and_scroll', line)
-
- def _show(self):
- ui.runningtab(2)
-
- def _hide(self):
- ui.runningtab()
diff --git a/build_tools/larch7/larch0/gui/front/mainwindow.py b/build_tools/larch7/larch0/gui/front/mainwindow.py
deleted file mode 100644
index 407b46a..0000000
--- a/build_tools/larch7/larch0/gui/front/mainwindow.py
+++ /dev/null
@@ -1,132 +0,0 @@
-#!/usr/bin/env python
-#
-# (c) Copyright 2010 Michael Towers (larch42 at googlemail dot com)
-#
-# This file is part of the larch project.
-#
-# larch is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# larch is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with larch; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-#
-#----------------------------------------------------------------------------
-#2010.07.13
-
-import __builtin__
-from uim import Uim, debug
-__builtin__.debug = debug
-
-
-_running = False
-def fss(*args, **kargs):
- while True:
- if _running:
- ui.command(':larch.busy', [], True)
- ok, result = filesystem(*args)
- if _running:
- ui.command(':larch.busy', [], False)
- if ok:
- filter = kargs.get('filter')
- return filter(result) if filter else result
-
- if kargs.get('trap', True):
- ui.command('errorDialog', result)
- # That might return, but the gui should quit (soon?).
- return None
-
-__builtin__.fss = fss
-
-
-
-class Ui(Uim):
- def __init__(self):
- Uim.__init__(self)
-
- def runningtab(self, i=None):
- if (i == None):
- i = 1 if progress.active else 0
- if (i == 0) and hasattr(stage, 'reenter'):
- stage.reenter()
- self.command(':tabs.set', i)
-
- def fileDialog(self, message, startdir=None, create=False,
- dirsonly=False, file=None, bookmarks=None, filter=None):
- return self.command('fileDialog', message, startdir, None,
- dirsonly, create, file, bookmarks, filter)
-
- def enable_installation_page(self, on):
- self.command(':notebook.enableTab', 1, on)
-
- def quit(self):
- """Do any tidying up which may be necessary.
- """
- larchscripts.close()
- Uim.quit()
-
- def data(self, key):
- return self.command('main_page_data.get', key)
-
-__builtin__.ui = Ui()
-
-
-def tab_changed(index):
- __builtin__.stage = pages[index]
- stage.enter()
-ui.connect(':notebook*changed', tab_changed)
-
-
-from page_project import ProjectSettings
-from page_installation import Installation
-from page_larchify import Larchify
-from page_mediumprofile import MediumProfile
-from page_medium import Medium
-
-
-from docviewer import DocViewer
-
-from editor import Editor
-
-from logview import Logger, Progress
-
-
-def run_error(message, title=None):
- ui.command('warningDialog', message, title)
-__builtin__.run_error = run_error
-
-pages = []
-def start():
- pages.append(ProjectSettings())
- pages.append(Installation())
- pages.append(Larchify())
- pages.append(MediumProfile())
- pages.append(Medium())
-
- __builtin__.docviewer = DocViewer()
- __builtin__.edit = Editor().edit
-
- __builtin__.progress = Progress()
- __builtin__.logger = Logger()
-
- MainWindow = fss('fetch_layout', 'page_main.uim')
- ui.widgetlist(MainWindow)
-
- ui.connect('$$$uiclose$$$', ui.quit)
- ui.connect('$$$uiquit$$$', ui.quit)
- ui.connect('$$$cancel$$$', larchscripts.interrupt)
-
- ui.command(':larch.pack')
- # Set up the first gui page (project settings)
- pages[0].setup()
- ui.command(':larch.show')
- _running = True
- ui.run()
-
diff --git a/build_tools/larch7/larch0/gui/front/page_installation.py b/build_tools/larch7/larch0/gui/front/page_installation.py
deleted file mode 100644
index 111e247..0000000
--- a/build_tools/larch7/larch0/gui/front/page_installation.py
+++ /dev/null
@@ -1,188 +0,0 @@
-# page_installation.py - Handler for the installation page
-#
-# (c) Copyright 2010 Michael Towers (larch42 at googlemail dot com)
-#
-# This file is part of the larch project.
-#
-# larch is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# larch is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with larch; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-#
-#----------------------------------------------------------------------------
-# 2010.07.19
-
-class Installation:
- def __init__(self):
- ui.widgetlist(fss('fetch_layout', 'page_installation.uim'))
-
- ui.connectlist(
- (':addedpacks*clicked', self.edit_addedpacks),
- (':vetopacks*clicked', self.edit_vetopacks),
- (':pacmanconf*clicked', self.edit_pacmanconf),
- (':repos*clicked', self.edit_repos),
- (':editmirrorlist*clicked', self.edit_mirrorlist),
- (':cache_change*clicked', self.change_cache),
- (':editrepolist*clicked', self.edit_repolist),
- (':install*clicked', self.install),
- (':sync*clicked', self.dosync),
- (':update*clicked', self.doupdate),
- (':add*clicked', self.doadd),
- (':remove*clicked', self.doremove),
- (':installrepos*toggled', self.installrepo),
- )
-
-
- def enter(self):
- """This is called when the page is entered/selected/shown.
- It performs initializations which depend on the state.
- """
- docviewer.gohome('gui_installation.html')
- # Set package cache display
- ui.command(':cache_show.text', fss('getitem', 'pacman_cache'))
- ui.command(':installrepos.opton', fss('getbool', 'installrepo'))
-
-
- def data(self, key):
- return ui.command('install_page_data.get', key)
-
-
- def edit_addedpacks(self):
- edit('profile:addedpacks') # In profile dir
-
-
- def edit_vetopacks(self):
- # If there is no vetopacks file, start an empty one
- edit('profile:vetopacks', "") # In profile dir
-
-
- def edit_pacmanconf(self):
- edit('profile:pacman.conf.options', # In profile dir
- 'base:data/pacman.conf', # Relative to base_dir
- label=self.data('edit_pc'),
- filter=pacmanoptions)
-
-
- def edit_repos(self):
- """This edits the repository list file for the live system.
- It will be used to construct the /etc/pacman.conf file.
- If the option to specify a different file for the installation
- stage is not enabled (the default), this file will also be used
- for the installation.
- """
- edit('profile:pacman.conf.repos', # In profile dir
- 'base:data/pacman.conf.repos', # Relative to base_dir
- label=self.data('edit_pr'))
-
-
- def edit_mirrorlist(self):
- ml = '/etc/pacman.d/mirrorlist'
- if not fss('isfile', ml):
- ml = 'base:data/mirrorlist' # Relative to base_dir
- edit('working:mirrorlist', ml,
- label=self.data('edit_mli'))
-
-
- def change_cache(self):
- # Is anything more necessary? Do I need to test the path?
- # Would a directory browser be better?
- ok, path = ui.command('textLineDialog',
- self.data('prompt_ncp'),
- None, fss('getitem', 'pacman_cache'))
- if ok:
- self.set_pacman_cache(path)
-
-
- def set_pacman_cache(self, path):
- path = path.strip().rstrip('/')
- fss('setitem', 'pacman_cache', path)
- ui.command(':cache_show.text', path)
-
-
- def edit_repolist(self):
- """This edits the repository list file used for installation,
- if the corresponding option is enabled.
- """
- # Should it be based on the default or on the profile?
- rf = 'profile:pacman.conf.repos'
- if not fss('isfile', rf):
- rf = 'base:data/pacman.conf.repos' # Relative to base_dir
- edit('working:pacman.conf.repos', rf,
- label=self.data('edit_pri'))
-
-
- def installrepo(self, on):
- fss('setbool', 'installrepo', on)
-
-
- def install(self):
- """Start the installation.
- """
- self.archin('install')
-
-
- def dosync(self):
- self.archin('refresh')
-
-
- def doupdate(self):
- f = ui.fileDialog(message=self.data('msg_pu'),
- filter=(self.data('filter_pu'), '*.pkg.tar.*'))
- if f:
- self.archin('update ' + f)
-
-
- def doadd(self):
- ok, plist = ui.command('textLineDialog',
- self.data('prompt_pi'),
- 'pacman -S')
- if ok:
- self.archin('sync ' + plist.strip())
-
-
- def doremove(self):
- ok, plist = ui.command('textLineDialog',
- self.data('prompt_pr'),
- 'pacman -Rs')
- if ok:
- self.archin('remove ' + plist.strip())
-
-
- def archin(self, cmd):
- """This runs the 'archin' script (as root). It doesn't wait for
- completion because the output must be collected and displayed
- while it is running. The display switches the view to the
- progress reporting page. It should probably activate the busy
- cursor too.
- """
- larchscripts.archin(cmd, ui.command(':installrepos.active'))
-
-
-
-def pacmanoptions(text):
- """A filter for pacman.conf to remove the repository info.
- """
- texto = ""
- block = ""
- for line in text.splitlines():
- block += line + "\n"
- if line.startswith("#["):
- break
- if line.startswith("[") and not line.startswith("[options]"):
- break
- if not line.strip():
- texto += block
- block = ""
- return texto
-
-
-
diff --git a/build_tools/larch7/larch0/gui/front/page_larchify.py b/build_tools/larch7/larch0/gui/front/page_larchify.py
deleted file mode 100644
index 9868727..0000000
--- a/build_tools/larch7/larch0/gui/front/page_larchify.py
+++ /dev/null
@@ -1,248 +0,0 @@
-# page_larchify.py - Handler for the project settings page
-#
-# (c) Copyright 2010 Michael Towers (larch42 at googlemail dot com)
-#
-# This file is part of the larch project.
-#
-# larch is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# larch is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with larch; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-#
-#----------------------------------------------------------------------------
-# 2010.07.13
-
-USERINFO = ['pw', 'maingroup', 'uid', 'skel', 'xgroups', 'expert']
-
-class Larchify:
- def __init__(self):
- ui.widgetlist(fss('fetch_layout', 'page_larchify.uim'))
-
- ui.connectlist(
- (':build*clicked', self.build),
- (':ssh*toggled', self.sshtoggle),
- (':locales*clicked', self.locales),
- (':rcconf*clicked', self.rcconf),
- (':initcpio*clicked', self.initcpio),
- (':overlay*clicked', self.overlay),
- (':utable*clicked', self.uedit),
- (':useradd*clicked', self.useradd),
- (':userdel*clicked', self.userdel),
- (':rootpwb*clicked', self.rootpw),
- )
-
- self.userheaders = self.data('uheaders')
-
-
- def data(self, key):
- return ui.command('larchify_page_data.get', key)
-
-
- def enter(self):
- """This is called when the page is entered/selected/shown.
- It performs initializations which depend on the state.
- """
- docviewer.gohome('gui_larchify.html')
-
- # Check that it could possibly be an Arch installation
- idir = fss('get_installation_dir')
- couldBeArch = fss('isdir', ':var/lib/pacman/local')
- ui.command(':build.enable', couldBeArch)
- if not couldBeArch:
- run_error(_("No Arch installation at %s") % idir)
-
- # ssh keys
- sshon = fss('isfile', ':usr/bin/ssh-keygen')
- ui.command(':ssh.enable', sshon)
-
- if fss('isfile', 'profile:nosshkeys'):
- sshon = False
- ui.command(":ssh.set", sshon)
-
- # users table
- idir_normal = idir != '/'
- ui.command(':users.enable', idir_normal)
- if idir_normal:
- # Fetch users information
- fss('newUserinfo')
- self.readuserinfo()
-
- # Root password
- self.showrootpw()
-
- self.reenter()
-
-
- def reenter(self):
- """These also need resetting after a build run.
- """
- # Whether there is an old system.sqf to reuse?
- ossqf = fss('oldsqf')
- if not ossqf:
- ui.command(':oldsquash.set', False)
- ui.command(':oldsquash.enable', ossqf)
-
- # Whether there is a set of old glibc locales to reuse?
- olcl = fss('oldlocales')
- if not olcl:
- ui.command(':oldlocales.set', False)
- ui.command(':oldlocales.enable', olcl)
-
-#TODO: Remove hack if the underlying bug gets fixed
- ui.command(":larchify_advanced.enable_hack")
-
-
- def readuserinfo(self, select=None):
- """'select' should be a username, defaulting to the first entry.
- """
- self.usersel = 0
- self.userlist = []
- i = 0
- for u in fss('allusers'):
- self.userlist.append(self.userinfolist(u))
- if u == select:
- self.usersel = i
- i += 1
- ui.command(':utable.set', self.userlist, self.usersel)
-
-
- def userinfolist(self, user):
- return [user] + fss('getuserinfo', user, USERINFO)
-
-
- def uedit(self, row, column):
- if self.usersel == row:
- uname = self.userlist[row][0]
- ulcell = self.userlist[row][column]
- if column == 4:
- ok, text = self.select_skel(ulcell)
- else:
- ok, text = ui.command('textLineDialog',
- self.userheaders[column] + ':', 'larchify', ulcell)
- text = text.strip()
- if ok:
- try:
- if (column == 0) and (text != ''):
- # Rename the user, by adding a new one and deleting
- # the old
- uname = text
- fss('newuser', uname)
- i = 0
- for f in USERINFO:
- i += 1
- fss('userset', uname, f, self.userlist[row][i])
- if not fss('deluser', ulcell):
- run_error(self.data('rn_error'))
-
- else:
- fss('userset', uname, USERINFO[column-1], text)
- fss('saveusers')
-
- except:
- run_error(self.data('ud_error'))
- self.readuserinfo(uname)
-
- else:
- self.usersel = row
-
-
- def select_skel(self, current):
- # Present a list of available 'skel' folders
- self.skellist = [self.data('def_skel')]
- for f in fss('listskels'):
- self.skellist.append(f.rsplit('/skel_', 1)[1])
- try:
- i = self.skellist.index(current)
- except:
- i = 0
- ok, skeli = ui.command('listDialog', self.data('skel_lbl'),
- self.data('skel_ttl'), self.skellist, i)
- if ok:
- return (True, '' if skeli == self.skellist[0]
- else skeli.split()[0])
- return (False, '')
-
-
- def useradd(self):
- ok, name = ui.command('textLineDialog', self.data('newlogin'))
- if ok:
- name = name.strip()
- if name != '' and fss('newuser', name):
- self.userlist.append(self.userinfolist(name))
- self.usersel = len(self.userlist) -1
- ui.command(':utable.set', self.userlist, self.usersel)
-
-
- def userdel(self):
- if self.usersel >= 0:
- user = self.userlist[self.usersel][0]
- if fss('deluser', user):
- del(self.userlist[self.usersel])
- lu = len(self.userlist)
- if lu:
- if lu <= self.usersel:
- self.usersel -= 1
- ui.command(':utable.set', self.userlist, self.usersel)
-
-
- def showrootpw(self):
- self.rootpw = fss('readfile', 'profile:rootpw', trap=False)
- if self.rootpw == None:
- self.rootpw = ""
- ui.command(':rootpwe.text', self.rootpw)
-
-
- def rootpw(self):
- ok, pw = ui.command('textLineDialog', self.data('newrootpw'),
- "larchify", self.rootpw)
- if ok:
- pw = pw.strip()
- if pw:
- fss('savefile', 'profile:rootpw', pw)
- else:
- fss('rm_rf', 'profile:rootpw')
- self.showrootpw()
-
-
- def sshtoggle(self, on):
- """Whether the system ssh keys are pregenerated
- depends on the presence of the profile file 'nosshkeys'
- (and of course on openssh being installed).
- """
- sshoff = fss('isfile', 'profile:nosshkeys')
- if on:
- if sshoff:
- fss('rm_rf', 'profile:nosshkeys')
- elif not sshoff:
- fss('savefile', 'profile:nosshkeys', "Don't pregenerate ssh keys")
-
-
- def locales(self):
- edit('profile:rootoverlay/etc/locale.gen', 'install:etc/locale.gen')
-
-
- def rcconf(self):
- edit('profile:rootoverlay/etc/rc.conf', 'install:etc/rc.conf')
-
-
- def initcpio(self):
- edit('profile:rootoverlay/etc/mkinitcpio.conf.larch0',
- 'install:etc/mkinitcpio.conf.larch0')
-
-
- def overlay(self):
- fss('browse', 'profile:rootoverlay')
-
-
- def build(self):
- larchscripts.larchify(ui.command(':oldsquash.active'),
- ui.command(':oldlocales.active'))
diff --git a/build_tools/larch7/larch0/gui/front/page_medium.py b/build_tools/larch7/larch0/gui/front/page_medium.py
deleted file mode 100644
index 75f0efe..0000000
--- a/build_tools/larch7/larch0/gui/front/page_medium.py
+++ /dev/null
@@ -1,320 +0,0 @@
-# page_medium.py - Handler for the project settings page
-#
-# (c) Copyright 2010 Michael Towers (larch42 at googlemail dot com)
-#
-# This file is part of the larch project.
-#
-# larch is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# larch is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with larch; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-#
-#----------------------------------------------------------------------------
-# 2010.07.13
-
-"""This page can also handle sources other than the normal larch
-installation. It should convert any larch image into
-another, with different medium and/or different bootloader, so long as the
-bootloader is supported by the source image.
-"""
-
-import os
-BOOTLOADERS = ('grub', 'syslinux')
-
-class Medium:
- def __init__(self):
- ui.widgetlist(fss('fetch_layout', 'page_medium.uim'))
-
- ui.connectlist(
- (':source_larch*toggled', self.src_larch),
- (':source_dev*toggled', self.src_dev),
- (':source_iso*toggled', self.src_iso),
- (':source_path*toggled', self.src_path),
- (':source_select*clicked', self.src_select),
- (':vlabelb*clicked', self.newlabel),
- (':grub*toggled', self.grub),
- (':syslinux*toggled', self.syslinux),
- (':selectpart*clicked', self.choosepartition),
- (':search*toggled', self.searchtoggled),
- (':destination*toggled', self.activate_actions),
- (':make_medium*clicked', self.make),
- (':bootcd*clicked', self.makeboot),
- )
- ui.command(':bootcd.enable', False)
-
-
- def enter(self):
- """This is called when the page is entered/selected/shown.
- It performs initializations which depend on the state.
- """
- self.source = ''
- self.destination = ''
- ui.command(':larchpart.text')
- docviewer.gohome('gui_medium.html')
- if ui.command(':source_larch.active'):
- self.src_larch(True)
- else:
- ui.command(':source_larch.set', True)
- ui.command(':%s.set' % fss('getitem', 'medium_search'), True)
- ui.command(':vlabele.text', fss('get_mediumlabel'))
-
-
- def data(self, key):
- return ui.command('medium_page_data.get', key)
-
-
- def setupbootloader(self, init=False):
- if init:
- self.bootloaders = []
- self.nosave = False
- self.source = ''
- for b in BOOTLOADERS:
- ui.command(':%s.set' % b, False)
- ui.command(':%s.enable' % b, False)
- pbl = fss('getitem', 'medium_btldr')
- for b in self.bootloaders:
- ui.command(':%s.enable' % b, True)
- if self.bootloaders:
- if pbl not in self.bootloaders:
- pbl = self.bootloaders[0]
- ui.command(':%s.set' % pbl, True)
- ui.command(':dosave.set', not self.nosave)
- ui.command(':source_show.text', self.source)
- self.activate_actions()
-
-
- def activate_actions(self, *args):
- # There needs to be a bootloader
- bl = self.get_bootloader()
- bcdok = (ui.command(':source_dev.active')
- and bool(self.source)
- and bool(bl))
- ui.command(':bootcd.enable', bcdok)
- # If using a destination partition, that needs to be available.
- wp = ui.command(':destination.active')
- if wp:
- # If writing to a partition without installing a bootloader
- if ui.command(':nombr.active'):
- bl = True # bootloader not necessary
- dp = bool(self.destination)
- else:
- dp = True
- ui.command(':make_medium.enable', bool(self.source) and bl and dp)
- ui.command(':detection.enable', bcdok or wp)
-
-
- def get_bootloader(self):
- if ui.command(':grub.active'):
- return 'grub'
- if ui.command(':syslinux.active'):
- return 'syslinux'
- return None
-
-
- def _testmedium(self, cc):
- # Runs in background thread ...
- self.bootloaders = []
- if not (cc & 8):
- self.bootloaders.append('syslinux')
- if not (cc & 16):
- self.bootloaders.append('grub')
- self.nosave = bool(cc & 2)
- ui.idle_add(self.setupbootloader, bool(cc & 1))
- return True # return immediately to normal view
-
-
- def src_larch(self, on):
- if on:
- mpath, ok, self.bootloaders, self.nosave = fss('testmedium')
- if ok:
- self.source = mpath
- else:
- self.source = ''
- run_error(self.data('msg_med') % mpath)
- self.setupbootloader()
-
- ui.command(':source_select.enable', not on)
- ui.command(':chroot.set', on)
-
-
- def src_dev(self, on):
- """The source system is on a mountable device, which must be
- selected from a list of available devices (via the Choose button)
- and tested for validity, maybe the presence of larch/system.sqf.
- """
- if on:
- self.setupbootloader(init=True)
-
-
- def src_iso(self, on):
- """The source system is in an 'iso' file, which must be
- selected by browsing the file system (via the Choose button)
- and tested for validity, maybe the presence of larch/system.sqf.
- """
- if on:
- self.setupbootloader(init=True)
-
-
- def src_path(self, on):
- """The source system is in a directory, which must be
- selected by browsing the file system (via the Choose button)
- and tested for validity, maybe the presence of larch/system.sqf.
- """
- if on:
- self.setupbootloader(init=True)
-
-
- def src_select(self):
- """The function of this button varies according to the selected
- source ...
- """
- src = None
- if ui.command(':source_dev.active'):
- part = self.selectpart()
- if part:
- src = part
-
- elif ui.command(':source_iso.active'):
- iso = ui.fileDialog(self.data('iso_src'),
- filter=(self.data('iso_type'), '*.iso'))
- if iso:
- src = iso
-
- elif ui.command(':source_path.active'):
- medium = ui.fileDialog(self.data('medium_src'), dirsonly=True)
- if medium:
- src = medium
-
- if src:
- self.source = src
- larchscripts.testmedium(src, self._testmedium)
-
-
- def grub(self, on):
- if on:
- fss('setitem', 'medium_btldr', 'grub')
-
- def syslinux(self, on):
- if on:
- fss('setitem', 'medium_btldr', 'syslinux')
-
-
- def newlabel(self):
- ok, l = ui.command('textLineDialog',
- self.data('prompt_label'),
- None, fss('getitem', 'medium_label'))
- if ok:
- ui.command(':vlabele.text', fss('set_mediumlabel', l))
-
-
- def choosepartition(self):
- p = self.selectpart(True)
- if p:
- ui.command(':larchpart.text', p)
- self.destination = p
- self.activate_actions()
-
-
- def selectpart(self, write=False):
- # Present a list of available partitions (only unmounted ones
- # are included)
- self.partlist = fss('get_partitions')
- ok, choice = ui.command('listDialog',
- self.data('parts_dst') if write else self.data('parts_src'),
- self.data('parts_t'),
- self.partlist, len(self.partlist) - 1)
- # The partition to be used is fetched from the gui, so there is no
- # need to save it anywhere else.
- if ok:
- return choice.split()[0]
- else:
- return None
-
-
- def searchtoggled(self, on):
- ui.command(':nolarchboot.enable', not on)
-
-
- def make(self):
- """Write the larch medium.
- """
- args = ['-l', ui.command(':vlabele.get')]
- if ui.command(':syslinux.active'):
- args.append('-b')
-
- # Is it standard (using profile, etc.) or copying?
- if ui.command(':source_larch.active'):
- # Normal larch build
- path = ''
- if not ui.command(':chroot.active'):
- args.append('-c')
-
- else:
- # Copying from another larch medium
- path = self.source
- if ui.command(':chroot.active'):
- args.append('-C')
-
- # Write to iso file or to partition?
- if ui.command(':destination.active'):
- # Write to partition
- for db in ('label', 'uuid', 'device', 'search'):
- if ui.command(':%s.active' % db):
- detect = db
- args += ['-d', detect]
- if (detect != 'search') and ui.command(':nolarchboot.active'):
- args.append('-n')
- args.append('-a' if ui.command(':dosave.active') else '-A')
- if ui.command(':noformat.active'):
- args.append('-x')
- if ui.command(':nombr.active'):
- args.append('-m')
- larchscripts.writemedium(path, args,
- os.path.basename(self.destination))
-
- else:
- # Write an 'iso' file
- df = self.isopath()
- if df:
- args += ['-D', df[0], '-o', df[1]]
- larchscripts.writemedium(path, args)
-
-
- def makeboot(self):
- return
- args = ['-l', fss('getbootisolabel')]
- if ui.command(':syslinux.active'):
- args.append('-b')
- path = os.path.basename(self.source)
- if ui.command(':chroot.active'):
- args.append('-C')
- df = self.isopath(bootiso=True)
- if df:
- args += ['-D', df[0], '-o', df[1]]
- larchscripts.writemedium(path, args, 'BOOTISO')
-
-
- def isopath(self, bootiso=False):
- sdir = fss('getisosavedir')
- ifname = fss('getbootisofile' if bootiso else 'getisofile')
- path = ui.fileDialog(self.data('isopath'), startdir=sdir,
- create=True, file=ifname, filter=(self.data('iso_type'), '*.iso'))
- if path:
- f = os.path.basename(path)
- d = os.path.dirname(path)
- if d != sdir:
- fss('setitem', 'isosavedir', d)
- if f != ifname:
- fss('setitem', 'bootisofile' if bootiso else 'isofile', f)
- return (d, f)
-
- return None
diff --git a/build_tools/larch7/larch0/gui/front/page_mediumprofile.py b/build_tools/larch7/larch0/gui/front/page_mediumprofile.py
deleted file mode 100644
index 0ebb769..0000000
--- a/build_tools/larch7/larch0/gui/front/page_mediumprofile.py
+++ /dev/null
@@ -1,87 +0,0 @@
-# page_mediumprofile.py - Handler for the project settings page
-#
-# (c) Copyright 2010 Michael Towers (larch42 at googlemail dot com)
-#
-# This file is part of the larch project.
-#
-# larch is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# larch is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with larch; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-#
-#----------------------------------------------------------------------------
-# 2010.07.14
-
-
-class MediumProfile:
- def __init__(self):
- ui.widgetlist(fss('fetch_layout', 'page_mediumprofile.uim'))
-
- ui.connectlist(
- (':bootlines*clicked', self.editbootlines),
- (':grubtemplate*clicked', self.editgrub),
- (':syslinuxtemplate*clicked', self.editsyslin),
- (':cdroot*clicked', self.browsecdroot),
- (':nosessionsave*toggled', self.nosessionsave),
- )
-
-
- def enter(self):
- """This is called when the page is entered/selected/shown.
- It performs initializations which depend on the state.
- """
- docviewer.gohome('gui_mediumprofile.html')
- ui.command(':nosessionsave.set', fss('isfile', 'profile:nosave'))
-
-
-# def data(self, key):
-# return ui.command('mediumprofile_page_data.get', key)
-
-
- def editbootlines(self):
- edit('profile:bootlines', 'base:data/bootlines')
-
-
- def editgrub(self):
- f0 = 'profile:cd-root/grub0/menu.lst'
- if not fss('isfile', f0):
- f0 = 'base:cd-root/grub0/menu.lst'
- edit('profile:cd-root/grub/menu.lst', f0)
-
-
- def editsyslin(self):
- f0 = 'profile:cd-root/isolinux0/isolinux.cfg'
- if not fss('isfile', f0):
- f0 = 'base:cd-root/isolinux0/isolinux.cfg'
- edit('profile:cd-root/isolinux/isolinux.cfg', f0)
-
-
- def browsecdroot(self):
- fss('browse', 'profile:cd-root')
-
-
- def nosessionsave(self, on):
- """Whether session saving is available is firstly determined by
- the writability of the boot device (assuming the extension
- feature to allow the use of other devices is not being used).
- The standard scripts will also not offer session saving if the
- file larch/nosave is present on the boot medium.
- """
- ns = fss('isfile', 'profile:nosave')
- if on:
- if not ns:
- fss('savefile', 'profile:nosave',
- "Suggestion to disable session saving"
- " (can be overridden)")
- else:
- fss('rm_rf', 'profile:nosave')
-
diff --git a/build_tools/larch7/larch0/gui/front/page_project.py b/build_tools/larch7/larch0/gui/front/page_project.py
deleted file mode 100644
index e9b902d..0000000
--- a/build_tools/larch7/larch0/gui/front/page_project.py
+++ /dev/null
@@ -1,203 +0,0 @@
-# page_project.py - Handler for the project settings page
-#
-# (c) Copyright 2010 Michael Towers (larch42 at googlemail dot com)
-#
-# This file is part of the larch project.
-#
-# larch is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# larch is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with larch; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-#
-#----------------------------------------------------------------------------
-# 2010.07.13
-
-import os
-
-class ProjectSettings:
- def __init__(self):
- ui.widgetlist(fss('fetch_layout', 'page_project.uim'))
-
- ui.connectlist(
- (':choose_profile_combo*changed', self.switch_profile),
- (':profile_rename*clicked', self.rename_profile),
- (':profile_browse*clicked', self.browse_profile),
- (':profile_delete*clicked', self.delete_profile),
- (':profile_save*clicked', self.save_profile),
- (':installation_path_change*clicked', self.new_build_path),
- (':choose_project_combo*changed', self.switch_project),
- (':new_project*clicked', self.get_new_project_name),
- (':project_delete*clicked', self.delete_project),
- )
-
-
- def setup(self):
- # Initialize project combobox
- self.projects = fss('get_projects')
- self.project_name = fss('get_project')
- try:
- pix = self.projects.index(self.project_name)
- except:
- self.switch_project(0)
- return
- ui.command(':choose_project_combo.set', self.projects, pix)
- # Initialize profile combobox
- self.profiles = fss('get_profiles')
- self.profile_name = fss('get_profile')
- try:
- pfix = self.profiles.index(self.profile_name)
- except:
- self.switch_profile(0)
- pfix = 0
- ui.command(':choose_profile_combo.set', self.profiles, pfix)
- # Initialize installation_dir display
- self.set_build_dir(fss('get_installation_dir'))
-
-
- def enter(self):
- """This is called when the page is entered/selected/shown.
- It performs initializations which depend on the state.
- """
- docviewer.gohome('gui_project_settings.html')
-
-
- def data(self, key):
- return ui.command('project_page_data.get', key)
-
-
- def set_build_dir(self, path):
- self.build_dir = path
- ui.command(':installation_path_show.text', self.build_dir)
- ui.enable_installation_page(self.build_dir != '/')
-
-
- def switch_profile(self, index):
- """This has no effect on the display!
- It is assumed that the display is already updated, or will be
- updated later, and that the index is valid, so that the operation
- cannot fail.
- """
- self.profile_name = self.profiles[index]
- fss('set_profile', self.profile_name)
-
-
- def browse_profile(self):
- source = ui.fileDialog(self.data('file_ps'), dirsonly=True,
- bookmarks=fss('get_profile_bookmarks'),
- startdir=fss('getitem', 'profile_browse_dir'))
- if source:
- fss('setitem', 'profile_browse_dir', os.path.dirname(source))
- if os.path.basename(source) in self.profiles:
- if not ui.command('confirmDialog', self.data('prompt_pr')):
- return
- if fss('get_new_profile', source):
- self.setup()
- else:
- run_error(self.data('msg_npd') % source)
-
-
- def rename_profile(self):
- if fss('can_rename_profile'):
- ok, new = ui.command('textLineDialog',
- self.data('prompt_pn'),
- None, self.profile_name)
- if ok:
- new = new.strip()
- if new in self.profiles:
- ui.command('warningDialog', self.data('prompt_pe') % new)
- else:
- fss('rename_profile', new)
- self.setup()
- else:
- ui.command('infoDialog', self.data('msg_pu'))
-
-
- def save_profile(self):
- bookmarks = fss('get_profile_bookmarks')
- startdir = fss('getitem', 'profile_browse_dir')
- path = ui.fileDialog(self.data('file_sp'),
- create=True, file=self.profile_name,
- bookmarks=bookmarks,
- startdir=startdir if startdir else bookmarks[0][0])
- if path:
- fss('setitem', 'profile_browse_dir', os.path.dirname(path))
- ok = fss('save_profile', path, False)
- if ok == False:
- if ui.command('confirmDialog', self.data('prompt_dr')):
- # Force overwrite
- fss('save_profile', path, True)
- elif ok == None:
- run_error(self.data('msg_piu'))
- else:
- self.setup()
-
-
- def delete_profile(self):
- plist = fss('list_free_profiles')
- if plist:
- ok, item = ui.command('listDialog', self.data('prompt_dp'),
- self.data('delprof'), plist)
- if ok:
- if fss('delete_profile', item):
- self.setup()
- else:
- ui.command('infoDialog', self.data('msg_dpff') % item)
- else:
- ui.command('infoDialog', self.data('msg_npf'))
-
-
- def new_build_path(self):
- # Is anything more necessary? Do I need to test or create the path?
- # I don't think so, the installation code does that.
- # If the path is "/", the installation page should be inhibited,
- # but that is handled by 'setup'.
- ok, path = ui.command('textLineDialog',
- self.data('prompt_ip'),
- None, self.build_dir)
- if ok:
- path = fss('set_installation_dir', path)
- if path:
- self.set_build_dir(path)
-
-
- def switch_project(self, index):
- fss('set_project', self.projects[index])
- self.setup()
-
-
- def get_new_project_name(self):
- ok, name = ui.command('textLineDialog',
- self.data('prompt_np'),
- None, self.project_name)
- if ok:
- if name in self.projects:
- run_error(self.data('msg_pe') % name)
- else:
- fss('set_project', name)
- self.setup()
-
-
- def delete_project(self):
- """Pop up a list of eligible project names, the selected one
- will be deleted.
- """
- plist = fss('list_free_projects')
- if plist:
- ok, item = ui.command('listDialog', self.data('prompt_pd'),
- self.data('delproj'), plist)
- if ok:
- fss('delete_project', item)
- self.setup()
- else:
- ui.command('infoDialog', self.data('msg_np'))
-
-
diff --git a/build_tools/larch7/larch0/gui/front/uim.py b/build_tools/larch7/larch0/gui/front/uim.py
deleted file mode 100644
index 71e106b..0000000
--- a/build_tools/larch7/larch0/gui/front/uim.py
+++ /dev/null
@@ -1,1327 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: UTF-8 -*-
-#
-# uim.py
-#
-# (c) Copyright 2010 Michael Towers (larch42 at googlemail dot com)
-#
-# This file is part of the larch project.
-#
-# larch is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# larch is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with larch; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-#
-#----------------------------------------------------------------------------
-# 2010.18.07
-
-#TODO?
-# Fetching of image and icon files via a sort of url-like mechanism, I
-# suppose initially using the 'base:' prefix might be ok.
-# Then the cwd of the gui script would be irrelevant.
-
-#New file dialog for accessing the 'server' end.
-
-
-"""UIM - User Interface Module
-
-The aim is to provide a means of creating graphical user interfaces of
-moderate complexity while abstracting the interface to the actual underlying
-toolkit in such a way that (at least potentially) an alternative toolkit
-could be used.
-[At present this aspect is rather theoretical since only a pyqt based
-version has been written.]
-
-The gui layout is specified as a python data structure, using widget types,
-parameter and signal names independent of the underlying toolkit. All
-widgets are accessible by their tag, which must be specified.
-
-A widget is defined by a call to the 'widget' method of the GuiApp instance.
-The first argument is the widget type, the second is the widget tag, the
-remaining ones must be named, they form the parameters to the constructor.
-If the widget is a 'container' (i.e. if it contains other widgets), it will
-need a 'layout' parameter defining the layout of its contents.
-
-There is also a 'widgetlist' method which accepts a list of widget
-definitions, each definition being itself a list. The first entry in a
-definition is the widget type, the second is the widget tag, the
-third is a dictionary containing all the parameters. For convenience (I'm not
-sure if I will keep this, though) any entries after the dictionary will be
-treated as signal names. These are just added to the parameter dictionary
-with value '' (enabling the signal with its default tag).
-
-Signals have signatures/keys comprising the tag of the emitting widget and
-the signal name (separated by '*'), and this will by default also be the tag
-by which the signal is known for connection purposes. But this can be
-overridden, for example to allow several widgets to emit the same signal.
-In the latter case the widget tag can (optionally) be passed as the first
-argument to the signal handler.
-
-Passing signal names as parameters to a widget constructor enables these
-signals. They can later be disabled, if desired.
-
-Connect and disconnect methods are available, to associate (or dissociate)
-handler functions with (/from) signals.
-"""
-
-import os, sys, traceback, threading
-from PyQt4 import QtGui, QtCore, QtWebKit
-from collections import deque
-#try:
-# import json
-#except:
-# import simplejson as json
-
-#++++++++++++++++++++++++++++++++++++++++++++++++++++
-#TODO
-# Add more widgets
-# Add more attribute handling
-# Add more signal handling
-
-#----------------------------------------------------
-
-def debug(text):
- sys.stderr.write("GUI: %s\n" % text)
- sys.stderr.flush()
-
-
-# Widget Base Classes - essentially used as 'Mixins' >>>>>>>>>>>>>>>>
-class WBase:
- def x__tt(self, text):
- """Set tooltip.
- """
- self.setToolTip(text) #qt
-
- def x__text(self, text=""):
- """Set widget text.
- """
- self.setText(text) #qt
-
- def x__enable(self, on):
- """Enable/Disable widget. on should be True to enable the widget
- (display it in its normal, active state), False to disable it
- (which will normally be paler and non-interactive).
- """
- self.setEnabled(on) #qt
-
- def x__focus(self):
- self.setFocus() #qt
-
- def x__width(self, w):
- """Set the minimum width for the widget.
- """
- self.setMinimumWidth(w) #qt
-
- def x__typewriter(self, on):
- """Use a typewriter (fixed spacing) font.
- """
- if on:
- f = QtGui.QFont(self.font()) #qt
- f.setFamily("Courier") #qt
- self.setFont(f) #qt
-
- def x__busycursor(self, on):
- """Set/clear the busy-cursor for this widget.
- """
- if on:
- self.setCursor(QtCore.Qt.BusyCursor) #qt
- else:
- self.unsetCursor() #qt
-
-
-class BBase:
- """Button mixin.
- """
- def x__icon(self, icon):
- self.setIcon(self.style().standardIcon(icondict[icon])) #qt
-
-#qt
-icondict = { "left" : QtGui.QStyle.SP_ArrowLeft,
- "right" : QtGui.QStyle.SP_ArrowRight,
- "down" : QtGui.QStyle.SP_ArrowDown,
- "up" : QtGui.QStyle.SP_ArrowUp,
- "reload" : QtGui.QStyle.SP_BrowserReload,
- }
-
-class Container:
- """This just adds layout management for widgets which contain
- other widgets.
- """
- def x__layout(self, layout, immediate=False):
- """A layout specifies and organizes the contents of a widget.
- Note that the layouting is not immediately performed by default as
- it is unlikely that all the contained widgets have been defined yet.
- """
- self._layout = layout
- if immediate:
- self.x__pack()
-
- def x__pack(self):
- """A layout call specifies and organizes the contents of a widget.
- The layout can be a layout manager list, or a single widget name
- (or an empty string, which will cause a warning to be issued, but
- may be useful during development).
-
- There are three sorts of thing which can appear in layout manager
- lists (apart from the layout type at the head of the list and an
- optional attribute dict as second item). There can be named
- widgets, there can be further layout managers (specified as lists,
- nested as deeply as you like) and there can be layout widgets,
- like spacers and separators.
-
- A layout widget can have optional arguments, which are separated
- by commas, e.g. 'VLINE,3' passes the argument '3' to the VLINE
- constructor.
- """
- # getattr avoids having to have an __init__() for Container.
- if getattr(self, '_layout', None):
- if self._layout != '$':
- self.setLayout(self.getlayout(self._layout))
- self._layout = '$'
- else:
- debug("No layout set on '%s'" % self.w_name)
-
- def getlayout(self, item):
- if isinstance(item, list):
- try:
- # Create a layout manager instance
- layoutmanager = layout_table[item[0]]()
- assert isinstance(layoutmanager, Layout)
- except:
- gui_error("Unknown layout type: %s" % item[0])
- if (len(item) > 1) and isinstance(item[1], dict):
- dictarg = item[1]
- ilist = item[2:]
- else:
- dictarg = {}
- ilist = item[1:]
- # Build up the list of objects to lay out
- # If the layout manager is a GRID, accept only grid rows ('+')
- if isinstance(layoutmanager, GRID):
- args = []
- rowlen = None
- for i in ilist:
- if isinstance(i, list) and (i[0] == '+'):
- args.append(self.getlayoutlist(i[1:], grid=True))
- if rowlen == None:
- rowlen = len(i)
- elif len(i) != rowlen:
- gui_error("Grid (%s) row lengths unequal"
- % self.w_name)
- else:
- gui_error("Grid (%s) layouts must consist of grid"
- " rows ('+')" % self.w_name)
- else:
- # Otherwise the elements of the argument list can be:
- # A sub-layout
- # A widget
- # A SPACE
- args = self.getlayoutlist(ilist)
- layoutmanager.do_layout(args)
- # Attributes
- for key, val in dictarg:
- handler = "x__" + key
- if hasattr(layoutmanager, handler):
- getattr(layoutmanager, handler)(val)
- return layoutmanager
-
- else:
- # It must be a widget, which will need to be put in a box (qt)
- return self.getlayout(['VBOX', item])
-
- def getlayoutlist(self, items, grid=False):
- objects = []
- for i in items:
- if isinstance(i, list):
- obj = self.getlayout(i)
- else:
- parts = i.split(',')
- i = parts[0]
- args = parts[1:]
- try:
- obj = layout_table[i](*args)
- if not (isinstance(obj, SPACE) # or a separator line
- or isinstance(obj, QtGui.QWidget)): #qt
- assert (grid and isinstance(obj, Span))
- except:
- obj = guiapp.getwidget(i)
- if obj != None:
- if isinstance(obj, Container):
- obj.x__pack()
- else:
- gui_error("Bad item in layout of '%s': '%s'"
- % (self.w_name, i))
- objects.append(obj)
- return objects
-
-
-class XContainer(Container):
- """This is a mixin class for containers which can contain more than
- one layout.
- """
- def x__layout(self, layout):
- gui_error("An extended container (%s) has no 'layout' method"
- % self.w_name)
-
-
-class TopLevel(Container):
- def x__show(self):
- self.set_visible()
-
- def set_visible(self, on=True):
- self.setVisible(on) #qt
-
- def x__size(self, w_h):
- w, h = [int(i) for i in w_h.split("_")]
- self.resize(w, h) #qt
-
- def x__icon(self, iconpath):
- guiapp.setWindowIcon(QtGui.QIcon(iconpath)) #qt
-
- def x__title(self, text):
- self.setWindowTitle(text) #qt
-
- def x__getSize(self):
- s = self.size() #qt
- return "%d_%d" % (s.width(), s.height()) #qt
-
- def x__getScreenSize(self):
- dw = guiapp.desktop() #qt
- geom = dw.screenGeometry(self) #qt
- return "%d_%d" % (geom.width(), geom.height()) #qt
-
-#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
-
-class Window(QtGui.QWidget, TopLevel): #qt
- """This is needed to trap window closing events. It also supports
- a 'busy' mechanism.
- """
- def __init__(self):
- QtGui.QWidget.__init__(self) #qt
- self.closesignal = ""
- self.busystate = False
- self.busy_lock = threading.Lock()
-
- def closeEvent(self, event): #qt
- if self.closesignal:
- guiapp.sendsignal(self.closesignal)
- event.ignore() #qt
- return
- QtGui.QWidget.closeEvent(self, event) #qt
-
- def x__closesignal(self, text):
- self.closesignal = text
-
- def x__busy(self, widgets, on, busycursor=True):
- """This activates (or deactivates, for on=False) a 'busy' mechanism,
- which can be one or both of the following:
- Make the application's cursor change to the 'busy cursor'.
- Disable a group of widgets.
- There is a lock to prevent the busy state from being set when it
- is already active.
- """
- # I couldn't get the following calls to work:
- # w.setCursor(QtCore.Qt.BusyCursor)
- # w.unsetCursor()
- self.busy_lock.acquire()
- if on:
- if self.busystate:
- debug("*ERROR* Attempt to set busy state twice")
- self.busy_lock.release()
- return
- self.busycursor = busycursor
- if busycursor:
- guiapp.setOverrideCursor(QtCore.Qt.BusyCursor) #qt
- else:
- if not self.busystate:
- debug("*ERROR* Attempt to release busy state twice")
- self.busy_lock.release()
- return
- if self.busycursor:
- guiapp.restoreOverrideCursor() #qt
- self.busystate = on
- self.busy_lock.release()
- for wn in widgets:
- w = guiapp.getwidget(wn)
- if w:
- w.setEnabled(not on) #qt
- else:
- debug("*ERROR* No widget '%s'" % wn)
-
-
-class Dialog(QtGui.QDialog, TopLevel):
- def __init__(self):
- QtGui.QDialog.__init__(self) #qt
-
- def x__showmodal(self):
- return self.exec_() == QtGui.QDialog.Accepted #qt
-
-
-class DialogButtons(QtGui.QDialogButtonBox): #qt
- def __init__(self):
- return
-
- def x__buttons(self, args):
- """This keyword argument MUST be present.
- """
- buttons = 0
- for a in args:
- try:
- b = getattr(QtGui.QDialogButtonBox, a) #qt
- assert isinstance(b, int) #qt
- buttons |= b #qt
- except:
- gui_warning("Unknown Dialog button: %s" % a)
- QtGui.QDialogButtonBox.__init__(self, buttons) #qt
-
- def x__dialog(self, dname):
- """This must be set or else the dialog buttons won't do anything.
- """
- self._dialog = guiapp.getwidget(dname)
- self.connect(self, QtCore.SIGNAL("clicked(QAbstractButton *)"), #qt
- self._clicked) #qt
-
- def _clicked(self, button): #qt
- if self.buttonRole(button) == self.AcceptRole: #qt
- self._dialog.accept() #qt
- else:
- self._dialog.reject() #qt
-
-
-def textLineDialog(label=None, title=None, text="", pw=False):
- if label == None:
- label = "Enter the value here:"
- if title == None:
- title = "Enter Information"
- if pw:
- echo = QtGui.QLineEdit.Password #qt
- else:
- echo = QtGui.QLineEdit.Normal #qt
- result, ok = QtGui.QInputDialog.getText(None, #qt
- title, label, echo, text) #qt
- return (ok, unicode(result))
-
-
-def listDialog(label=None, title=None, items=[], current=0):
- if label == None:
- label = "Choose one of the entries"
- if title == None:
- title = "Select an item"
- item, ok = QtGui.QInputDialog.getItem(None, title, label, items,
- current, editable=False) #qt
- return (ok, unicode(item))
-
-
-def confirmDialog(message, title=None):
- if title == None:
- title = "Confirmation"
- return (QtGui.QMessageBox.question(None, title, message, #qt
- QtGui.QMessageBox.Yes | QtGui.QMessageBox.Cancel) == #qt
- QtGui.QMessageBox.Yes) #qt
-
-
-def infoDialog(message, title=None):
- if title == None:
- title = "Information"
- QtGui.QMessageBox.information(None, title, message) #qt
-
-
-#+++++++++++++++++++++++++++
-# Error handling
-def gui_error(message, title=None):
- if title == None:
- title = "Error"
- QtGui.QMessageBox.critical(None, title, message) #qt
- guiapp.exit(1) #qt
-
-def gui_warning(message, title=None):
- if title == None:
- title = "Warning"
- QtGui.QMessageBox.warning(None, title, message) #qt
-
-def onexcept(text):
- debug(traceback.format_exc())
- gui_error(text, "Exception")
-#---------------------------
-
-fileDialogDir = "/"
-def fileDialog(message, start=None, title=None, dir=False, create=False,
- file=None, urls=None, filter=None):
- # filter is a list: first a textual description, then acceptable glob filenames
- global fileDialogDir
- if not start:
- start = fileDialogDir
- dlg = QtGui.QFileDialog(None, message, start) #qt
- if title:
- dlg.setWindowTitle(title) #qt
- dlg.setReadOnly(not create) #qt
- if dir:
- dlg.setFileMode(dlg.Directory) #qt
- elif not create:
- dlg.setFileMode(dlg.ExistingFile) #qt
- if filter:
- dlg.setNameFilter("%s (%s)" % (filter[0], " ".join(filter[1:]))) #qt
-
- if urls:
- urlsqt = [ QtCore.QUrl.fromLocalFile(u[0]) for u in urls ] #qt
- urlsqt.append(QtCore.QUrl.fromLocalFile(
- QtGui.QDesktopServices.storageLocation(
- QtGui.QDesktopServices.HomeLocation)))
-
- dlg.setSidebarUrls(urlsqt) #qt
-
- if file:
- dlg.selectFile(file)
-
- if dlg.exec_():
- path = str(dlg.selectedFiles()[0]).strip()
- if os.path.isdir(path):
- fileDialogDir = path
- elif os.path.isfile(path):
- fileDialogDir = os.path.dirname(path)
- return path
- else:
- return ""
-
-
-class Stack(QtGui.QStackedWidget, XContainer): #qt
- def __init__(self):
- QtGui.QStackedWidget.__init__(self) #qt
- self.x_twidgets = []
-
- def x__pages(self, pages):
- self.x_twidgets = pages
-
- def x__pack(self):
- for name in self.x_twidgets:
- w = guiapp.getwidget(name)
- w.x__pack()
- self.addWidget(w) #qt
-
- def x__set(self, index=0):
- self.setCurrentIndex(index) #qt
-
-
-class Notebook(QtGui.QTabWidget, XContainer): #qt
- def __init__(self):
- QtGui.QTabWidget.__init__(self) #qt
- self.x_tabs = []
- self.x_twidgets = []
-
- def x__changed(self, name=''):
- guiapp.signal(self, 'changed', name, 'currentChanged(int)') #qt
-
- def x__tabs(self, tabs):
- self.x_twidgets = tabs
-
- def x__pack(self):
- for name, title in self.x_twidgets:
- w = guiapp.getwidget(name)
- w.x__pack()
- self.addTab(w, title) #qt
- self.x_tabs.append([name, w])
-
- def x__set(self, index=0):
- self.setCurrentIndex(index) #qt
-
- def x__enableTab(self, index, on):
- self.setTabEnabled(index, on) #qt
-
-
-class Page(QtGui.QWidget, Container): #qt
- def __init__(self):
- QtGui.QWidget.__init__(self) #qt
-
- def x__enable(self, on):
- """Enable/Disable widget. on should be True to enable the widget
- (display it in its normal, active state), False to disable it
- (which will normally be paler and non-interactive).
- """
- self.setEnabled(on) #qt
-
-
-class Frame(QtGui.QGroupBox, WBase, Container): #qt
- def __init__(self):
- QtGui.QGroupBox.__init__(self) #qt
- self._text = None
-
- def x__text(self, text):
- self._text = text
- self.setTitle(text) #qt
-
-# A hack to improve spacing
- def setLayout(self, layout):
- topgap = 10 if self._text else 0
- layout.setContentsMargins(0, topgap, 0, 0) #qt
- QtGui.QGroupBox.setLayout(self, layout)
-
-
-class OptionalFrame(Frame): #qt
- def __init__(self): #qt
- Frame.__init__(self) #qt
- self.setCheckable(True) #qt
- self.setChecked(False) #qt
-
- def x__toggled(self, name=''):
- guiapp.signal(self, 'toggled', name, 'toggled(bool)') #qt
-
- def x__opton(self, on):
- self.setChecked(on) #qt
-
-#TODO: Is this still needed? (I think it's a qt bug)
- def x__enable_hack(self): #qt
- if not self.isChecked(): #qt
- self.setChecked(True) #qt
- self.setChecked(False) #qt
-
- def x__active(self):
- return self.isChecked() #qt
-
-
-def read_markup(markup):
- def read_markup0(mlist):
- text = ''
- for i in mlist:
- text += read_markup(i) if isinstance(i, list) else i
- return text
- tag = markup[0]
- if tag == '':
- return read_markup0(markup[1:])
- elif tag in ('h1', 'h2', 'h3', 'h4', 'p', 'em', 'strong'):
- return '<%s>%s</%s>' % (tag, read_markup0(markup[1:]), tag)
- elif tag == 'color':
- return '<span style="color:%s;">%s</span>' % (markup[1],
- read_markup0(markup[2:]))
- return "Markup parse error"
-
-
-class Label(QtGui.QLabel, WBase): #qt
- def __init__(self):
- QtGui.QLabel.__init__(self) #qt
-
- def x__markup(self, markup):
- self.setText(read_markup(markup)) #qt
-
- def x__image(self, path):
- self.setPixmap(QtGui.QPixmap(path)) #qt
-
- def x__align(self, pos):
- if pos == "center":
- a = QtCore.Qt.AlignCenter #qt
- else:
- a = QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter #qt
- self.setAlignment(a) #qt
-
-
-class Button(QtGui.QPushButton, WBase, BBase): #qt
- def __init__(self):
- QtGui.QPushButton.__init__(self) #qt
-
- def x__clicked(self, name=''):
- guiapp.signal(self, 'clicked', name, 'clicked()') #qt
-
-
-class ToggleButton(QtGui.QPushButton, WBase, BBase): #qt
- def __init__(self):
- QtGui.QPushButton.__init__(self) #qt
- self.setCheckable(True) #qt
-
- def x__toggled(self, name=''):
- guiapp.signal(self, 'toggled', name, 'toggled(bool)') #qt
-
- def x__set(self, on):
- self.setChecked(on) #qt
-
-
-class CheckBox(QtGui.QCheckBox, WBase): #qt
- def __init__(self):
- QtGui.QCheckBox.__init__(self) #qt
-
- def x__toggled(self, name=''):
- # A bit of work is needed to get True/False state #qt
- # instead of 0/1/2 #qt
- guiapp.signal(self, 'toggled', name,
- 'toggled(bool)', self.s_toggled) #qt
-
- def s_toggled(self, state): #qt
- """Convert the argument to True/False.
- """ #qt
- return (state != QtCore.Qt.Unchecked,) #qt
-
- def x__set(self, on):
- self.setCheckState(2 if on else 0) #qt
-
- def x__active(self):
- return self.checkState() != QtCore.Qt.Unchecked #qt
-
-
-class RadioButton(QtGui.QRadioButton, WBase): #qt
- def __init__(self):
- QtGui.QPushButton.__init__(self) #qt
-
- def x__toggled(self, name=''):
- guiapp.signal(self, 'toggled', name, 'toggled(bool)') #qt
-
- def x__set(self, on):
- self.setChecked(on) #qt
-
- def x__active(self):
- return self.isChecked() #qt
-
-
-class ComboBox(QtGui.QComboBox, WBase): #qt
- def __init__(self):
- QtGui.QComboBox.__init__(self) #qt
-
- def x__changed(self, name=''):
- guiapp.signal(self, 'changed', name, 'currentIndexChanged(int)') #qt
-
- def x__changedstr(self, name=''):
- guiapp.signal(self, 'changedstr', name,
- 'currentIndexChanged(const QString &)') #qt
-
- def x__set(self, items, index=0):
- self.blockSignals(True)
- self.clear() #qt
- if items:
- self.addItems(items) #qt
- self.setCurrentIndex(index) #qt
- self.blockSignals(False)
-
-
-class ListChoice(QtGui.QListWidget, WBase): #qt
- def __init__(self):
- QtGui.QListWidget.__init__(self) #qt
-
- def x__changed(self, name=''):
- guiapp.signal(self, 'changed', name, 'currentRowChanged(int)') #qt
-
- def x__set(self, items, index=0):
- self.blockSignals(True)
- self.clear() #qt
- if items:
- self.addItems(items) #qt
- self.setCurrentRow(index) #qt
- self.blockSignals(False)
-
-
-class List(QtGui.QTreeWidget, WBase): #qt
- # Only using top-level items of the tree
- def __init__(self):
- QtGui.QTreeWidget.__init__(self) #qt
- self.mode = ""
- self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) #qt
- self.setRootIsDecorated(False) #qt
- self._hcompact = False # used for scheduling header-compaction
-
- def x__select(self, name=''):
- guiapp.signal(self, 'select', name,
- 'itemSelectionChanged()', self.s_select) #qt
-
- def x__clicked(self, name=''):
- guiapp.signal(self, 'clicked', name,
- 'itemClicked(QTreeWidgetItem *,int)', self.s_clicked) #qt
-
- def s_select(self):
- # Signal a selection change, passing the new selection list (indexes)
- s = [self.indexOfTopLevelItem(i) for i in self.selectedItems()] #qt
- if self.mode == "Single":
- return s
- else:
- return (s,)
-
- def s_clicked(self, item, col): #qt
- """This is intended for activating a user-defined editing function.
- Tests showed that this is called after the selection is changed, so
- if using this signal, use it only in 'Single' selection mode and
- use this, not 'select' to record selection changes. Clicking on the
- selected row should start editing the cell, otherwise just change
- the selection.
- """
- ix = self.indexOfTopLevelItem(item) #qt
- return (ix, col)
-
- def x__selectionmode(self, sm):
- self.mode = sm
- if sm == "None":
- self.setSelectionMode(QtGui.QAbstractItemView.NoSelection) #qt
- elif sm == "Single":
- self.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) #qt
- else:
- self.mode = ""
- self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) #qt
-
- def x__headers(self, headers): #qt
- self.setHeaderLabels(headers) #qt
- if self._hcompact:
- self._compact()
-
- def x__set(self, items, index=0): #qt
- # Note that each item must be a tuple/list containing
- # entries for each column.
- self.clear() #qt
- c = 0
- for i in items:
- item = QtGui.QTreeWidgetItem(self, i) #qt
- self.addTopLevelItem(item) #qt
- if c == index:
- self.setCurrentItem(item)
- c += 1
- if self._hcompact:
- self._compact()
-
- def x__compact(self, on=True):
- self._hcompact = on
- if on:
- self._compact()
-
- def _compact(self):
- for i in range(self.columnCount()): #qt
- self.resizeColumnToContents(i) #qt
-
-
-class LineEdit(QtGui.QLineEdit, WBase): #qt
- def __init__(self):
- QtGui.QLineEdit.__init__(self) #qt
-
- def x__enter(self, name=''):
- guiapp.signal(self, 'enter', name, 'returnPressed()') #qt
-
- def x__changed(self, name=''):
- guiapp.signal(self, 'changed', name, 'textEdited(const QString &)') #qt
-
- def x__get(self):
- return unicode(self.text()) #qt
-
- def x__ro(self, ro):
- self.setReadOnly(ro) #qt
-
- def x__pw(self, star):
- self.setEchoMode(QtGui.QLineEdit.Password if star == "+" #qt
- else QtGui.QLineEdit.NoEcho if star == "-" #qt
- else QtGui.QLineEdit.Normal) #qt
-
-
-class CheckList(QtGui.QWidget, WBase): #qt
- def __init__(self):
- QtGui.QWidget.__init__(self) #qt
- self.box = QtGui.QVBoxLayout(self) #qt
- self.title = None
- if text: #qt
- l.addWidget(QtGui.QLabel(text)) #qt
- self.widget = QtGui.QListWidget() #qt
- l.addWidget(self.widget) #qt
-
- def x__title(self, text):
- if self.title:
- self.title.setText(text) #qt
- else:
- self.title = QtGui.QLabel(text) #qt
- self.box.insertWidget(0, self.title) #qt
-
- def x__checked(self, index):
- return (self.widget.item(index).checkState() == #qt
- QtCore.Qt.Checked) #qt
-
- def x__set(self, items):
- self.widget.blockSignals(True) #qt
- self.widget.clear() #qt
- if items:
- for s, c in items:
- wi = QtGui.QListWidgetItem(s, self.widget) #qt
- wi.setCheckState(QtCore.Qt.Checked if c #qt
- else QtCore.Qt.Unchecked) #qt
- self.blockSignals(False) #qt
-
-
-class TextEdit(QtGui.QTextEdit, WBase): #qt
- def __init__(self):
- QtGui.QTextEdit.__init__(self) #qt
-
- def x__ro(self, ro):
- self.setReadOnly(ro) #qt
-
- def x__append_and_scroll(self, text):
- self.append(text) #qt
- self.ensureCursorVisible() #qt
-
- def x__get(self):
- return unicode(self.toPlainText()) #qt
-
- def x__undo(self):
- QtGui.QTextEdit.undo(self) #qt
-
- def x__redo(self):
- QtGui.QTextEdit.redo(self) #qt
-
- def x__copy(self):
- QtGui.QTextEdit.copy(self) #qt
-
- def x__cut(self):
- QtGui.QTextEdit.cut(self) #qt
-
- def x__paste(self):
- QtGui.QTextEdit.paste(self) #qt
-
-
-class HtmlView(QtWebKit.QWebView, WBase): #qt
- def __init__(self):
- QtWebKit.QWebView.__init__(self) #qt
-
- def x__html(self, content):
- self.setHtml(content) #qt
-
- def x__setUrl(self, url):
- self.load(QtCore.QUrl(url)) #qt
-
- def x__prev(self):
- self.back() #qt
-
- def x__next(self):
- self.forward() #qt
-
-
-class SpinBox(QtGui.QDoubleSpinBox, WBase): #qt
- def __init__(self):
- QtGui.QDoubleSpinBox.__init__(self) #qt
- self.step = None
-
- def x__changed(self, name=''):
- guiapp.signal(self, 'changed', name, 'valueChanged(double)') #qt
-
- def x__min(self, min):
- self.setMinimum(min)
-
- def x__max(self, max):
- self.setMaximum(max)
-
- def x__decimals(self, dec):
- self.setDecimals(dec)
- if not self.step:
- self.setSingleStep(10**(-dec))
-
- def x__step(self, step):
- self.setSingleStep(step)
-
- def x__value(self, val):
- self.setValue(val)
-
-
-class ProgressBar(QtGui.QProgressBar, WBase): #qt
- def __init__(self):
- QtGui.QProgressBar.__init__(self) #qt
-
- def x__set(self, value):
- self.setValue(value) #qt
-
- def x__max(self, max):
- self.setMaximum(max) #qt
-
-
-
-# Layout classes
-class Layout:
- """A mixin base class for all layout widgets.
- """
- pass
-
-boxmargin=3
-class _BOX(Layout):
- def do_layout(self, items):
- self.setContentsMargins(boxmargin, boxmargin, boxmargin, boxmargin) #qt
- for wl in items:
- if isinstance(wl, QtGui.QWidget): #qt
- self.addWidget(wl) #qt
- elif isinstance(wl, SPACE): #qt
- if wl.size: #qt
- self.addSpacing(wl.size) #qt
- self.addStretch() #qt
- elif isinstance(wl, Layout): #qt
- self.addLayout(wl) #qt
- else: #qt
- gui_error("Invalid Box entry: %s" % repr(wl))
-
-
-class VBOX(QtGui.QVBoxLayout, _BOX): #qt
- def __init__(self):
- QtGui.QVBoxLayout.__init__(self) #qt
-
-
-class HBOX(QtGui.QHBoxLayout, _BOX): #qt
- def __init__(self):
- QtGui.QHBoxLayout.__init__(self) #qt
-
-
-class GRID(QtGui.QGridLayout, Layout): #qt
- def __init__(self):
- QtGui.QGridLayout.__init__(self) #qt
-
- def do_layout(self, rows):
- y = -1
- for row in rows:
- y += 1
- x = -1
- for wl in row:
- x += 1
- if isinstance(wl, Span):
- continue
- # Determine the row and column spans
- x1 = x + 1
- while (x1 < len(row)) and isinstance(row[x1], CSPAN):
- x1 += 1
- y1 = y + 1
- while (y1 < len(rows)) and isinstance(rows[y1][x], RSPAN):
- y1 += 1
-
- if isinstance(wl, QtGui.QWidget): #qt
- self.addWidget(wl, y, x, y1-y, x1-x) #qt
- elif isinstance(wl, Layout):
- self.addLayout(wl, y, x, y1-y, x1-x) #qt
- elif isinstance(wl, SPACE):
- self.addItem(QtGui.QSpacerItem(wl.size, wl.height),
- y, x, y1-y, x1-x) #qt
- else:
- gui_error("Invalid entry in Grid layout: %s" % repr(wl))
-
-
-class SPACE:
- """Can be used in boxes and grids. In boxes only size is of interest,
- and it also means vertical size in the case of a vbox. In grids size
- is the width.
- """
- def __init__(self, size_width='0', height='0'): #qt
- self.size = int(size_width) #qt
- self.height = int(height) #qt
-
-
-class Span:
- """Class to group special grid layout objects together - it doesn't
- actually do anything itself, but is used for checking object types.
- """
- pass
-
-
-class CSPAN(Span):
- """Column-span layout item. It doesn't do anything itself, but it is used
- by the Grid layout constructor.
- """
- pass
-
-
-class RSPAN(Span):
- """Row-span layout item. It doesn't do anything itself, but it is used
- by the Grid layout constructor.
- """
- pass
-
-
-class HLINE(QtGui.QFrame): #qt
- def __init__(self, pad=None):
- QtGui.QFrame.__init__(self) #qt
- self.setFrameShape(QtGui.QFrame.HLine) #qt
- if pad:
- self.setFixedHeight(1 + 2*int(pad)) #qt
-
-
-class VLINE(QtGui.QFrame): #qt
- def __init__(self, pad=None):
- QtGui.QFrame.__init__(self) #qt
- self.setFrameShape(QtGui.QFrame.VLine) #qt
- if pad:
- self.setFixedWidth(1 + 2*int(pad)) #qt
-
-
-class DATA:
- """This is not really a widget, it just holds a dictionary of
- potentially internationalized messages.
- """
- def x__messages(self, mdict):
- self.messages = mdict
-
- def x__get(self, key):
- return self.messages.get(key)
-
-
-class Uim(QtGui.QApplication):
- """This class represents an application gui, possibly with more than
- one top level window.
- """
- timers = [] # timer objects
-
- def __init__(self):
- global guiapp
- guiapp = self
- self.eno = QtCore.QEvent.registerEventType() #qt
- QtGui.QApplication.__init__(self, []) #qt
- self.setQuitOnLastWindowClosed(False) #qt
-
- self.widgets = {} # all widgets, key = widget tag
- self.signal_dict = {} # signal connections, key = signature
-
- # callback list for event loop: (callback, arglist) pairs:
- self.idle_calls = deque()
-
-
- def event(self, e):
- if e.type() == self.eno:
- # Process item from list
- cb, a = self.idle_calls.popleft()
- cb(*a)
- return True
- else:
- return QtGui.QApplication.event(self, e) #qt
-
-
- def run(self):
- self.exec_() #qt
-
-
-# def quit(self):
-# self.quit() #qt
-
-
- def addwidget(self, fullname, wo):
- if self.widgets.has_key(fullname):
- gui_error("Attempted to define widget '%s' twice." % fullname)
- self.widgets[fullname] = wo
-
-
- def getwidget(self, w):
- widget = self.widgets.get(w)
- if widget == None:
- gui_warning("Unknown widget: %s" % w)
- return widget
-
-
- def show(self, windowname):
- self.getwidget(windowname).setVisible()
-
-
- def command(self, cmdtext, *args):
- cmd = specials_table.get(cmdtext)
- if not cmd:
- w, m = cmdtext.split(".")
- wo = self.getwidget(w)
- cmd = getattr(wo, 'x__' + m)
- return cmd(*args)
-
-
- def widget(self, wtype, wname, args):
- wobj = widget_table[wtype]()
- wobj.w_name = wname
-
- # Attributes
- for key, val in args.iteritems():
- handler = "x__" + key
- if hasattr(wobj, handler):
- getattr(wobj, handler)(val)
-# Unrecognized attributes are ignored ...
-
- self.addwidget(wname, wobj)
-
-
- def widgetlist(self, wlist):
- for w in wlist:
- # Add simple signals
- for s in w[3:]:
- w[2][s] = ''
- self.widget(w[0], w[1], w[2])
-
-
- def signal(self, source, signal, name=None, xsignal=None, convert=None):
- """Enable or disable a signal.
- Signal.signals is a dictionary of enabled signals.
- The key is constructed from the widget name and the formal signal name.
- The name of the signal which actually gets generated will be the
- same as the key unless the 'name' parameter is set. See the
- 'Signal' class for further details.
- If 'name' is None (not ''!), the signal will be disabled.
- """
- widsig = source.w_name + '*' + signal
- if name == None:
- s = Signal.signals.get(widsig)
- if not s:
- gui_error("Can't disable signal '%s' - it's not enabled"
- % widsig)
- s.disconnect() # Probably not necessary in qt
- del(Signal.signals[widsig])
- else:
- if Signal.signals.has_key(widsig):
- gui_error("Signal already connected: %s" % widsig)
- Signal.signals[widsig] = Signal(source, signal, name, xsignal,
- convert)
-
-
- def connect(self, signal, function):
- if self.signal_dict.has_key(signal):
- self.signal_dict[signal].append(function)
- else:
- self.signal_dict[signal] = [function]
-
-
- def connectlist(self, *slotlist):
- for s in slotlist:
- self.connect(*s)
-
-
- def disconnect(self, signal, function):
- try:
- l = self.signal_dict[signal]
- l.remove(function)
- except:
- gui_error("Slot disconnection for signal '%s' failed"
- % signal)
-
-
- def sendsignal(self, name, *args):
- # When there are no slots a debug message is output.
- slots = self.signal_dict.get(name)
- if slots:
- try:
- for slot in slots:
- slot(*args)
- except:
- gui_error("Signal handling error:\n %s"
- % traceback.format_exc())
- else:
- debug("Unhandled signal: %s %s" % (name, repr(args)))
-
-
- def idle_add(self, callback, *args):
- self.idle_calls.append((callback, args))
- e = QtCore.QEvent(self.eno) #qt
- self.postEvent(self, e) #qt
-
-
- def timer(self, callback, period):
- """Start a timer which calls the callback function on timeout.
- Only if the callback returns True will the timer be retriggered.
- """
- Uim.timers.append(Timer(callback, period))
-
-
-class Timer(QtCore.QTimer): #qt
- def __init__(self, timers, callback, period):
- QtCore.QTimer.__init__(self) #qt
- self.x_callback = callback
- self.connect(self, QtCore.SIGNAL("timeout()"), #qt
- self.x_timeout)
- self.start(int(period * 1000)) #qt
-
- def x_timeout(self):
- if not self.x_callback():
- self.stop() #qt
- Uim.timers.remove(self)
-
-
-
-class Signal:
- """Each instance represents a single connection.
- """
- signals = {} # Enabled signals
-
- def __init__(self, source, signal, name, xsignal, convert):
- """'source' is the widget object which initiates the signal.
- 'signal' is the signal name.
- If 'name' is given (not empty), the signal will get this as its name,
- and this name may be used for more than one connection.
- Otherwise the name is built from the name of the source widget and
- the signal type as 'source*signal' and this is unique.
- If 'name' begins with '+' an additional argument, the source
- widget name, will be inserted at the head of the argument list.
- 'xsignal' is a toolkit specific signal descriptor.
- 'convert' is an optional function (default None) - toolkit specific -
- to perform signal argument conversions.
- """
- self.widsig = '%s*%s' % (source.w_name, signal)
- #+ For disconnect?
- self.xsignal = xsignal
- #-
- self.convert = convert # Argument conversion function
- self.tag = name if name else self.widsig
- self.wname = source.w_name if self.tag[0] == '+' else None
- if not source.connect(source, QtCore.SIGNAL(xsignal), #qt
- self.signal):
- gui_error("Couldn't enable signal '%s'" % self.widsig)
-
- def signal(self, *args):
- if self.convert:
- args = self.convert(*args)
- if self.wname:
- guiapp.sendsignal(self.tag, self.wname, *args)
- else:
- guiapp.sendsignal(self.tag, *args)
-
- def disconnect(self):
- w = guiapp.getwidget(self.widsig.split('*')[0])
- w.disconnect(w, QtCore.SIGNAL(self.xsignal), self.signal) #qt
-
-
-
-#+++++++++++++++++++++++++++
-# Catch all unhandled errors.
-def errorTrap(type, value, tb):
- etext = "".join(traceback.format_exception(type, value, tb))
- debug(etext)
- gui_error(etext, "This error could not be handled.")
-
-sys.excepthook = errorTrap
-#---------------------------
-
-widget_table = {
- "DATA": DATA,
- "Window": Window,
- "Dialog": Dialog,
- "DialogButtons": DialogButtons,
- "Notebook": Notebook,
- "Stack": Stack,
- "Page": Page,
- "Frame": Frame,
- "Button": Button,
- "ToggleButton": ToggleButton,
- "RadioButton": RadioButton,
- "CheckBox": CheckBox,
- "Label": Label,
- "CheckList": CheckList,
- "List": List,
- "OptionalFrame": OptionalFrame,
- "ComboBox": ComboBox,
- "ListChoice": ListChoice,
- "LineEdit": LineEdit,
- "TextEdit": TextEdit,
- "HtmlView": HtmlView,
- "SpinBox": SpinBox,
- "ProgressBar": ProgressBar,
-}
-
-specials_table = {
- "textLineDialog": textLineDialog,
- "infoDialog": infoDialog,
- "confirmDialog": confirmDialog,
- "errorDialog": gui_error,
- "warningDialog": gui_warning,
- "fileDialog": fileDialog,
- "listDialog": listDialog,
-}
-
-layout_table = {
- "VBOX": VBOX,
- "HBOX": HBOX,
- "GRID": GRID,
-# "+": GRIDROW,
- "-": CSPAN,
- "|": RSPAN,
- "*": SPACE,
- "VLINE": VLINE,
- "HLINE": HLINE,
-}
-