diff options
Diffstat (limited to 'build_tools/larch7/larch0/gui/front')
-rw-r--r-- | build_tools/larch7/larch0/gui/front/docviewer.py | 68 | ||||
-rw-r--r-- | build_tools/larch7/larch0/gui/front/editor.py | 115 | ||||
-rw-r--r-- | build_tools/larch7/larch0/gui/front/logview.py | 94 | ||||
-rw-r--r-- | build_tools/larch7/larch0/gui/front/mainwindow.py | 132 | ||||
-rw-r--r-- | build_tools/larch7/larch0/gui/front/page_installation.py | 188 | ||||
-rw-r--r-- | build_tools/larch7/larch0/gui/front/page_larchify.py | 248 | ||||
-rw-r--r-- | build_tools/larch7/larch0/gui/front/page_medium.py | 320 | ||||
-rw-r--r-- | build_tools/larch7/larch0/gui/front/page_mediumprofile.py | 87 | ||||
-rw-r--r-- | build_tools/larch7/larch0/gui/front/page_project.py | 203 | ||||
-rw-r--r-- | build_tools/larch7/larch0/gui/front/uim.py | 1327 |
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, -} - |