summaryrefslogtreecommitdiffstats
path: root/build_tools/larch8/larch0/gui/front
diff options
context:
space:
mode:
Diffstat (limited to 'build_tools/larch8/larch0/gui/front')
-rw-r--r--build_tools/larch8/larch0/gui/front/docviewer.py68
-rw-r--r--build_tools/larch8/larch0/gui/front/editor.py115
-rw-r--r--build_tools/larch8/larch0/gui/front/logview.py94
-rw-r--r--build_tools/larch8/larch0/gui/front/mainwindow.py205
-rw-r--r--build_tools/larch8/larch0/gui/front/page_installation.py193
-rw-r--r--build_tools/larch8/larch0/gui/front/page_larchify.py296
-rw-r--r--build_tools/larch8/larch0/gui/front/page_medium.py441
-rw-r--r--build_tools/larch8/larch0/gui/front/page_project.py241
8 files changed, 1653 insertions, 0 deletions
diff --git a/build_tools/larch8/larch0/gui/front/docviewer.py b/build_tools/larch8/larch0/gui/front/docviewer.py
new file mode 100644
index 0000000..de51605
--- /dev/null
+++ b/build_tools/larch8/larch0/gui/front/docviewer.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python2
+#
+# 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/larch8/larch0/gui/front/editor.py b/build_tools/larch8/larch0/gui/front/editor.py
new file mode 100644
index 0000000..202f236
--- /dev/null
+++ b/build_tools/larch8/larch0/gui/front/editor.py
@@ -0,0 +1,115 @@
+#!/usr/bin/env python2
+#
+# 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/larch8/larch0/gui/front/logview.py b/build_tools/larch8/larch0/gui/front/logview.py
new file mode 100644
index 0000000..7e506a5
--- /dev/null
+++ b/build_tools/larch8/larch0/gui/front/logview.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python2
+#
+# 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.08.10
+
+import locale
+# Try to work around problems when the system encoding is not utf8
+encoding = locale.getdefaultlocale()[1]
+
+#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 isinstance(line, str):
+ line = line.decode(encoding, 'replace')
+ 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
+ if isinstance(line, str):
+ line = line.decode(encoding, 'replace')
+ ui.command('log:text.append_and_scroll', line)
+
+ def _show(self):
+ ui.runningtab(2)
+
+ def _hide(self):
+ ui.runningtab()
diff --git a/build_tools/larch8/larch0/gui/front/mainwindow.py b/build_tools/larch8/larch0/gui/front/mainwindow.py
new file mode 100644
index 0000000..8bf2a57
--- /dev/null
+++ b/build_tools/larch8/larch0/gui/front/mainwindow.py
@@ -0,0 +1,205 @@
+#!/usr/bin/env python2
+#
+# (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.10.12
+
+import __builtin__
+from liblarch.suim import Suim, debug
+__builtin__.debug = debug
+
+
+
+def larchcall(script, *args):
+ if script[0] != '*':
+ progress.start() # initialize progress widget
+ ui.setcb(None)
+ else:
+ # This script won't switch to the progress widget, but accepts
+ # a callback to handle the resulting output
+ script = script[1:]
+ ui.setcb(args[0])
+ args = args[1:]
+ fss('larchscript', script, *args)
+
+__builtin__.larchcall = larchcall
+
+
+
+class Ui(Suim):
+ def __init__(self):
+ self.setcb(None)
+ Suim.__init__(self, 'larch', busywidgets=[':larch'])
+
+ self.connect('$$$uiclose$$$', self.quit)
+ self.connect('$$$uiquit$$$', self.quit)
+ self.connect('$$$cancel$$$', self.interrupt)
+ self.progressing = False # used for managing progress display
+
+
+ def sigin(self, signal, *args):
+ self.idle_add(getattr(self, 'sig_' + signal), *args)
+
+
+ def setcb(self, cb):
+ """Set a callback to run when a 'larchscript' sends an output line,
+ or completes.
+ """
+ self._read_cb = cb
+
+
+ def isbusy(self):
+ return self._read_cb != None
+
+
+ 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, filter=None):
+# Actually this should access the file-system via 'fss' ...
+# (that would require a new, custom widget)
+ if dirsonly:
+ return self.command('fileDialog_getdir', message, not create, startdir)
+ if file and startdir:
+ startdir = startdir + '/' + file
+ if create:
+ return self.command('fileDialog_save', message, startdir, filter)
+ return self.command('fileDialog_open', message, startdir, filter)
+
+ def enable_installation_page(self, on):
+ self.command(':notebook.enableTab', 1, on)
+
+ def interrupt(self):
+ fss('larchscript', 'interrupt')
+
+ def quit(self):
+ """Do any tidying up which may be necessary.
+ """
+ fss('larchscript', 'close')
+ Suim.quit(self)
+
+ def data(self, key):
+ return self.command('main_page_data.get', key)
+
+
+ def sig_get_password(self, message):
+ """This is a callback, triggered by signal 'get_password'
+ to ask the user to input the password.
+ """
+ fss('larchscript', 'sendpassword', *ui.command('textLineDialog',
+ message, "larch: pw", "", True))
+
+
+ def sig_line_cb(self, message):
+ """A line has been received from the 'larchscript' (this is a callback,
+ in the main thread).
+ The input lines are filtered for pacman, mksquashfs and mkisofs
+ progress output so that appropriate progress reports can be given.
+ """
+ if message.startswith('>-'):
+ if message.startswith('>-_$$_'):
+ # Informing us of the pid
+ fss('larchscript', 'pid', int(message.rsplit('_', 1)[1]))
+ else:
+ # It is a progress report
+ progress.set(message[2:])
+ self.progressing = True
+ return
+
+ else:
+ if self.progressing:
+ progress.set()
+ self.progressing = False
+
+ progress.addLine(message)
+ if message.startswith('?>'):
+ # a query (yes/no): pop up the query
+ fss('larchscript', 'reply', '??YES' if ui.command(
+ 'confirmDialog', message[2:]) else '??NO')
+ elif self._read_cb:
+ self._read_cb(message)
+
+
+ def sig_end_cb(self, ok):
+ """A callback for the end of a 'larchscript'.
+ The completion code, ok, is ignored.
+ """
+ if self._read_cb:
+ self._read_cb(None)
+ self._read_cb = None
+ self.busy(False)
+ else:
+ progress.end()
+
+
+ def sig_log(self, line):
+ logger.addLine(line)
+
+
+
+
+def tab_changed(index):
+ __builtin__.stage = pages[index]
+ stage.enter()
+
+from page_project import ProjectSettings
+from page_installation import Installation
+from page_larchify import Larchify
+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 = [] # Must be initialized before init() because of calls to tab_changed
+
+def init():
+ pages.append(ProjectSettings())
+ pages.append(Installation())
+ pages.append(Larchify())
+ 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(':notebook*changed', tab_changed)
+
+ ui.command(':larch.pack')
+ # Set up the first gui page (project settings)
+ pages[0].setup()
+ ui.command(':larch.show')
+
diff --git a/build_tools/larch8/larch0/gui/front/page_installation.py b/build_tools/larch8/larch0/gui/front/page_installation.py
new file mode 100644
index 0000000..82d57c5
--- /dev/null
+++ b/build_tools/larch8/larch0/gui/front/page_installation.py
@@ -0,0 +1,193 @@
+# 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.08.12
+
+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),
+ (':updateall*clicked', self.doupdateall),
+ (':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 doupdateall(self):
+ self.archin('updateall')
+
+
+ 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.
+ """
+ larchcall('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/larch8/larch0/gui/front/page_larchify.py b/build_tools/larch8/larch0/gui/front/page_larchify.py
new file mode 100644
index 0000000..a63ecff
--- /dev/null
+++ b/build_tools/larch8/larch0/gui/front/page_larchify.py
@@ -0,0 +1,296 @@
+# 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.10.07
+
+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),
+ (':kernelb*clicked', self.kernelfile),
+ (':kernelmkib*clicked', self.kernelpreset),
+ )
+
+ 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()
+
+ # Kernel info
+ self.showkernel()
+
+ 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.larch',
+ 'install:etc/mkinitcpio.conf.larch')
+
+
+ def overlay(self):
+ fss('browse', 'profile:rootoverlay')
+
+
+ def showkernel(self):
+ if fss('isfile', 'profile:kernel'):
+ ki = fss('readfile', 'profile:kernel')
+ else:
+ ki = fss('readfile', 'base:data/kernel')
+ self.kernel, self.kernelpreset = ki.split()
+ ui.command(':kernele.text', self.kernel)
+ ui.command(':kernelmkie.text', self.kernelpreset)
+
+
+ def kernelfile(self):
+ ok, kf = ui.command('textLineDialog', self.data('kernelf'),
+ "larchify", self.kernel)
+ if ok:
+ kf = kf.strip()
+ if not kf:
+ fss('rm_rf', 'profile:kernel')
+
+ elif (' ' in kf) or not fss('isfile', 'install:boot/' + kf):
+ run_error(_("Invalid kernel binary: %s") % kf)
+ return
+ else:
+ fss('savefile', 'profile:kernel', kf + ' ' + self.kernelpreset)
+ self.showkernel()
+
+
+ def kernelpreset(self):
+ ok, kp = ui.command('textLineDialog', self.data('kernelp'),
+ "larchify", self.kernelpreset)
+ if ok:
+ kp = kp.strip()
+ if not kp:
+ fss('rm_rf', 'profile:kernel')
+
+ elif (' ' in kp) or not fss('isfile',
+ 'install:etc/mkinitcpio.d/%s.preset' % kp):
+ run_error(_("Invalid kernel mkinitcpio preset: %s") % kp)
+ return
+ else:
+ fss('savefile', 'profile:kernel', self.kernel + ' ' + kp)
+ self.showkernel()
+
+
+ def build(self):
+ larchcall('larchify', ui.command(':oldsquash.active'),
+ ui.command(':oldlocales.active'))
diff --git a/build_tools/larch8/larch0/gui/front/page_medium.py b/build_tools/larch8/larch0/gui/front/page_medium.py
new file mode 100644
index 0000000..e63ce13
--- /dev/null
+++ b/build_tools/larch8/larch0/gui/front/page_medium.py
@@ -0,0 +1,441 @@
+# 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.11.28
+
+"""This page takes a directory processed by larchify. It produces a bootable
+larch medium, or, in the case of CD/DVD, an iso image.
+It also handles creation of a boot-iso for an existing larch medium (partition)
+and can copy larch media to different devices.
+"""
+
+import os
+from config import detection_methods, OKFS
+
+
+class Medium:
+ def __init__(self):
+ self.medium = None
+ self.srcmedium = None
+ self.detectionmodes = detection_methods.split('|')
+ ui.widgetlist(fss('fetch_layout', 'page_medium.uim'))
+
+ ui.connectlist(
+ (':vlabelb*clicked', self.newlabel),
+ (':selectpart*clicked', self.choosedest),
+ (':selectsrc*clicked', self.choosesrc),
+ (':persist*toggled', self.persistence),
+ (':ovl_journal*toggled', self.journal),
+ (':mediumtype*changed', self.mediumtype),
+ (':srctype*changed', self.srctype),
+ (':make_medium*clicked', self.make),
+ (':nolarchboot*toggled', self.bootnosearch),
+ (':detection*changed', self.mediumsearch),
+ (':pformat*toggled', self.setpformat),
+ (':bootlines*clicked', self.editbootlines),
+ (':syslinuxtemplate*clicked', self.editsyslin),
+ (':cdroot*clicked', self.browsecdroot),
+ )
+
+
+ def enter(self):
+ """This is called when the page is entered/selected/shown.
+ It performs initialisations which depend on the state.
+ """
+ self.destinationpath = ''
+ self.fsok = None
+ self.source, ok = fss('testlarchify') # check the larchified installation
+ if not ok:
+ run_error(self.data('msg_med') % self.source)
+ self.source = ''
+ self.mediumtype(None)
+ if self.medium != 'medium-boot':
+ self.srctype(None)
+ detect = fss('getitem', 'medium_search')
+ ui.command(':detection.set',
+ [self.data('detectionmodes')[l] for l in self.detectionmodes],
+ self.detectionmodes.index(detect))
+ self.nlbenable(detect)
+ ui.command(':nolarchboot.set', fss('getbool', 'boot_nosearch'))
+ ui.command(':vlabele.text', fss('get_mediumlabel'))
+ ui.command(':ovl_journal.set', fss('getbool', 'journal'))
+ fmt = fss('getbool', 'do_format')
+ ui.command(':pformat.set', fmt )
+ ui.command(':ovl_journal.enable', fmt)
+ ui.command(':persist.set', fss('getbool', 'do_persist'))
+
+ ui.command(':larchpart.text') # clear the destination
+ docviewer.gohome('gui_medium.html')
+
+
+ def data(self, key):
+ return ui.command('medium_page_data.get', key)
+
+
+ def mediumtype(self, index):
+ if (index == None):
+ if self.medium == None:
+ self.medium = self.data('media')[0]
+ else:
+ self.medium = self.data('media')[index]
+
+ if self.medium == 'medium-boot':
+ label = fss('get_bootisolabel')
+ ui.command(':srctype.setindex', self.data('sources').index('device'))
+ ui.command(':srctype.enable', False)
+ ifile = fss('getbootisofile')
+
+ else:
+ label = fss('get_mediumlabel')
+ ui.command(':srctype.enable', True)
+
+ if self.medium == 'medium-iso':
+ ifile = fss('getisofile')
+
+ self.showlabel(label)
+
+ if self.medium == 'medium-w':
+ ui.command(':mediumopts.enable', True)
+ self.setdestinationpath('')
+
+ else:
+ ui.command(':mediumopts.enable', False)
+ idir = fss('getisosavedir')
+ if not fss('isdir', idir):
+ fss('setitem', 'isosavedir', '')
+ idir = fss('getisosavedir')
+ self.setdestinationpath(os.path.join(idir, ifile))
+
+ if index != None:
+ self.enableprofile()
+ self.enablemake()
+
+
+ def srctype(self, index):
+ if (index == None):
+ if self.srcmedium == None:
+ self.srcmedium = self.data('sources')[0]
+ else:
+ self.srcmedium = self.data('sources')[index]
+
+ if self.srcmedium == 'larchified':
+ self.setsourcepath(self.source)
+ ui.command(':selectsrc.enable', False)
+
+ elif self.srcmedium == 'device':
+ self.setsourcepath('') # clear source, it must be selected
+ ui.command(':selectsrc.enable', True)
+
+ elif self.srcmedium == 'isofile':
+ isof = fss('getisofile')
+ isod = fss('getisosavedir')
+ self.pendingpath = os.path.join(isod, isof)
+ ui.command(':selectsrc.enable', True)
+ self.setsourcepath('')
+ self.checklarchsource()
+
+
+ def setsourcepath(self, path):
+ self.sourcepath = path
+ ui.command(':srclocation.text', path)
+ self.enableprofile()
+ self.enablemake()
+
+
+ def choosesrc(self):
+ # 'larchified' should not be possible - it is set on the project page
+ if self.srcmedium == 'device':
+ self.devices = []
+ larchcall('*rootfn', self._cd_line, 'blkid -c dev/null -o list')
+
+ elif self.srcmedium == 'isofile':
+ # Pop up a file browser
+ self.pendingpath = self.isopath(mode='source')
+ self.checklarchsource()
+
+ else:
+ debug('page_medium: Medium.choosesrc / ' + self.srcmedium)
+
+ def _cd_line(self, line):
+ if line == None:
+ # Completed - pop up device chooser
+ ok, choice = ui.command('listDialog',
+ self.data('parts_src'),
+ self.data('parts_t'),
+ self.devices, len(self.devices) - 1)
+ if ok:
+ self.pendingpath = choice.split()[0]
+ ui.idle_add(self.checklarchsource)
+
+ else:
+ l = line.strip()
+ if l.startswith('/dev/'):
+ i = l.find('(not mounted)')
+ if i > 0:
+ ls = l[:i].split(None, 2)
+ if (ls[0] != self.destinationpath) and (len(ls) == 3):
+ self.devices.append('%-10s %s' % (ls[0], ls[2]))
+
+
+ def checklarchsource(self):
+ if self.pendingpath:
+ # check it is really a larch medium
+ self.larchok = False
+ larchcall('*larchmedium', self._cs_line, self.pendingpath)
+
+ def _cs_line(self, line):
+ if line == None:
+ # Completed
+ if self.larchok:
+ self.setsourcepath(self.pendingpath)
+ else:
+ l = line.strip()
+ if l.startswith('##--'):
+ if l.endswith('ok'):
+ self.larchok = True
+
+
+ def enableprofile(self):
+ """Set the enabled state of the medium profile frame,
+ according to the state of the choices.
+ """
+ ui.command(':mediumprofile.enable', (self.medium != 'medium-boot')
+ and (self.srcmedium == 'larchified'))
+
+
+ def enablemake(self):
+ on = bool(self.destinationpath) and bool(self.sourcepath)
+ if self.medium == 'medium-w':
+ formatting = fss('getbool', 'do_format')
+ self.enablepersist(formatting or (self.fsok in OKFS))
+ if (not formatting):
+ if (self.fsok not in OKFS) and (self.fsok != 'vfat'):
+ on = False
+ ui.command(':make_medium.enable', on)
+
+
+ def enablepersist(self, on):
+ ui.command(':persist.enable', on)
+ self.persist_enabled = on
+
+
+ def persistence(self, on):
+ fss('setbool', 'do_persist', on)
+
+
+ def journal(self, on):
+ fss('setbool', 'journal', on)
+
+
+ def mediumsearch(self, option):
+ choice = self.detectionmodes[option]
+ fss('setitem', 'medium_search', choice)
+ self.nlbenable(choice)
+
+
+ def nlbenable(self, choice):
+ ui.command(':nolarchboot.enable', choice != 'search')
+
+
+ def bootnosearch(self, on):
+ fss('setbool', 'boot_nosearch', on)
+
+
+ def setpformat(self, on):
+ fss('setbool', 'do_format', on)
+ ui.command(':ovl_journal.enable', on)
+ self.enablemake()
+
+
+ def editbootlines(self):
+ f0 = 'profile:cd-root/boot0/bootlines'
+ if not fss('isfile', f0):
+ f0 = 'base:cd-root/boot0/bootlines'
+ edit('profile:cd-root/boot/bootlines', 'base:cd-root/boot0/bootlines')
+
+
+ def editsyslin(self):
+ f0 = 'profile:cd-root/boot0/isolinux/isolinux.cfg'
+ if not fss('isfile', f0):
+ f0 = 'base:cd-root/boot0/isolinux/isolinux.cfg'
+ edit('profile:cd-root/boot/isolinux/isolinux.cfg', f0)
+
+
+ def browsecdroot(self):
+ fss('browse', 'profile:cd-root')
+
+
+ def newlabel(self):
+ labelsrc = 'bootiso' if self.medium == 'medium-boot' else 'medium'
+ ok, l = ui.command('textLineDialog',
+ self.data('prompt_label'),
+ None, fss('get_%slabel' % labelsrc))
+ if ok:
+ self.showlabel(fss('set_%slabel' % labelsrc, l))
+
+
+ def showlabel(self, l):
+ ui.command(':vlabele.text', l)
+
+
+ def choosedest(self):
+ if self.medium == 'medium-w':
+ # Present a list of unmounted partitions
+ self.devices = []
+ larchcall('*rootfn', self._sd_line, 'blkid -c /dev/null -o list')
+
+ elif self.medium == 'medium-iso':
+ # Pop up a file browser
+ path = self.isopath(mode='source')
+ if path:
+ self.setdestinationpath(path)
+
+ elif self.medium == 'medium-boot':
+ # Pop up a file browser
+ path = self.isopath(mode='bootiso')
+ if path:
+ self.setdestinationpath(path)
+
+ def _sd_line(self, line):
+ if line == None:
+ nmdevices = []
+ for part in fss('get_partitions'): # ->(dev, size in MiB(int))
+ if part[0] == self.sourcepath:
+ continue
+ found = False
+ for partinfo in self.devices:
+ if partinfo[0] == part[0]:
+ if partinfo[2]:
+ nmdevices.append('%-12s %8d MiB %-10s %s'
+ % (part[0], part[1], partinfo[1], partinfo[2]))
+ found = True
+ break
+ if not found:
+ nmdevices.append('%-12s %-12d MiB' % (part[0], part[1]))
+
+ # Completed - pop up device chooser
+ ok, choice = ui.command('listDialog',
+ self.data('parts_dst'),
+ self.data('parts_t'),
+ nmdevices, len(nmdevices) - 1)
+ if ok:
+ ui.idle_add(self.setdestinationpath, choice.split()[0])
+
+ else:
+ l = line.strip()
+ if l.startswith('/dev/'):
+ i = l.find('(not mounted)')
+ if i > 0:
+ # Try to get label for unmounted devices only
+ ls = l[:i].split(None, 2)
+ if len(ls) < 3:
+ ls.append('-') # signifies 'no label'
+ else:
+ ls = l.split(None, 2)
+ ls[2] = None # mark the partition as mounted
+ self.devices.append(ls)
+
+
+ def setdestinationpath(self, path):
+ ui.command(':larchpart.text', path)
+ self.destinationpath = path
+ if path.startswith('/dev/'):
+ # Check the file-system
+ self.fsok = None
+ larchcall('*rootfn', self._em_line,
+ 'blkid -c /dev/null -o value -s TYPE %s' % path)
+ else:
+ self.enablemake()
+
+ def _em_line(self, line):
+ if line == None:
+ # Completed
+ self.enablemake()
+ else:
+ line = line.strip()
+ if line:
+ self.fsok = line
+
+
+ def isopath(self, mode='dest'):
+ sdir = fss('getisosavedir')
+ ifname = fss('getbootisofile' if mode=='bootiso' else 'getisofile')
+ path = ui.fileDialog(self.data('isoget' if mode=='source' else 'isopath'),
+ startdir=sdir, create=(mode!='source'),
+ 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 mode=='bootiso' else 'isofile', f)
+ return path
+
+ return None
+
+
+ def make(self):
+ """Write the larch medium.
+ """
+ if self.srcmedium == 'larchified':
+ source = None
+ else:
+ source = self.sourcepath
+ if not source:
+ debug("page_medium: make / null source")
+ return
+
+ args = ['-l', ui.command(':vlabele.get')]
+
+ if self.medium == 'medium-boot':
+ # Write a boot iso file
+ args += ['-b', '-o', self.destinationpath]
+ larchcall('writemedium', source, args)
+
+ elif self.medium == 'medium-iso':
+ # Write an 'iso' file
+ args += ['-o', self.destinationpath]
+ larchcall('writemedium', source, args)
+
+ else:
+ # Write to partition
+ # Medium detection options
+ detect = fss('getitem', 'medium_search')
+ args += ['-d', detect]
+ if (detect != 'search') and ui.command(':nolarchboot.active'):
+ args.append('-n')
+ # Formatting
+ if fss('getbool', 'do_format'):
+ # Journalling?
+ if not fss('getbool', 'journal'):
+ args.append('-j')
+ else:
+ args.append('-F')
+ # Set master boot record?
+ if ui.command(':nombr.active'):
+ args.append('-m')
+ # Persistence
+ if fss('getbool', 'do_persist') and self.persist_enabled:
+ args.append('-P')
+ # Add the medium to the argument list
+ args.append(self.destinationpath)
+ larchcall('writemedium', source, args)
diff --git a/build_tools/larch8/larch0/gui/front/page_project.py b/build_tools/larch8/larch0/gui/front/page_project.py
new file mode 100644
index 0000000..cbbda66
--- /dev/null
+++ b/build_tools/larch8/larch0/gui/front/page_project.py
@@ -0,0 +1,241 @@
+# 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.08.15
+
+import os
+
+class ProjectSettings:
+ def __init__(self):
+ ui.widgetlist(fss('fetch_layout', 'page_project.uim'))
+ ui.widgetlist(fss('fetch_layout', 'profile_browse.uim'))
+ ui.command('dialog:profile_browser.pack')
+
+ 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.copy_profile),
+ (':profile_clone*clicked', self.clone_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),
+ ('dpb:example_list*changed', self.dpb_example),
+ ('dpb:browse*clicked', self.dpb_browse),
+ ('dpb:name_s*clicked', self.dpb_source),
+ )
+
+
+ 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):
+ self.example_profile_dir, self.dpb_example_list = fss('get_example_profiles')
+ ui.command('dpb:example_list.set', self.dpb_example_list, -1)
+ if ui.command('dialog:profile_browser.showmodal'):
+ source = ui.command('dpb:source.get')
+ name = ui.command('dpb:name.get')
+ if name in self.profiles:
+ if not ui.command('confirmDialog', self.data('prompt_pr')):
+ return
+ if fss('get_new_profile', source, name):
+ self.setup()
+ else:
+ run_error(self.data('msg_npd') % source)
+
+
+ def dpb_example(self, index):
+ name = self.dpb_example_list[index]
+ ui.command('dpb:source.text', self.example_profile_dir + '/' + name)
+ ui.command('dpb:name.text', name)
+
+
+ def dpb_browse(self):
+ source = ui.fileDialog(self.data('file_ps'), dirsonly=True,
+ startdir=fss('getitem', 'profile_browse_dir'))
+ if source:
+ fss('setitem', 'profile_browse_dir', os.path.dirname(source))
+ ui.command('dpb:source.text', source)
+ ui.command('dpb:name.text', os.path.basename(source))
+ ui.command('dpb:example_list.set', self.dpb_example_list, -1)
+
+
+ def dpb_source(self):
+ ok, name = ui.command('textLineDialog', _("Name for new profile:"), None,
+ os.path.basename(ui.command('dpb:source.get')))
+ if ok:
+ ui.command('dpb:name.text', name)
+
+
+ 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 clone_profile(self):
+ ok, name = ui.command('textLineDialog', self.data('prompt_clone'), self.profile_name)
+ if ok:
+ name = name.strip()
+ self.save_profile(name)
+ fss('set_profile', name)
+ self.setup()
+
+ def copy_profile(self):
+ startdir = fss('getitem', 'profile_browse_dir')
+ path = ui.fileDialog(self.data('file_sp'),
+ create=True, dirsonly=True, file=self.profile_name,
+ startdir=startdir)
+ if path:
+ fss('set_profile_browse_dir', path)
+ self.save_profile(path)
+
+ def save_profile(self, 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'))
+
+