def __init__(self, parent, ID=wx.ID_ANY, title=wx.EmptyString, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE, name=wx.DialogNameStr, allow_custom=False): wx.Dialog.__init__(self, parent, ID, title, pos, size, style=style | wx.RESIZE_BORDER, name=name) self.check_list = CheckList(self) # *** Buttons *** # layout_buttons = BoxSizer(wx.HORIZONTAL) btn_clear = CreateButton(self, btnid.CLEAR) btn_confirm = CreateButton(self, btnid.CONFIRM) btn_cancel = CreateButton(self, btnid.CANCEL) btn_clear.Bind(wx.EVT_BUTTON, self.OnClearList) # FIXME: Correct button order? layout_buttons.Add(btn_clear, 0, wx.LEFT, 5) layout_buttons.AddStretchSpacer(1) layout_buttons.Add(btn_confirm, 0, wx.RIGHT, 5) layout_buttons.Add(btn_cancel, 0, wx.RIGHT, 5) # *** Layout *** # layout_main = BoxSizer(wx.VERTICAL) layout_main.Add(self.check_list, 1, wx.EXPAND | wx.ALL, 5) layout_main.Add(layout_buttons, 0, wx.EXPAND | wx.BOTTOM, 5) if allow_custom: btn_add_custom = wx.Button(self, label=GT(u'Add custom')) btn_add_custom.Bind(wx.EVT_BUTTON, self.OnAddCustom) self.input_add_custom = wx.TextCtrl(self) layout_add_custom = BoxSizer(wx.HORIZONTAL) layout_add_custom.Add(btn_add_custom, 0, lyt.PAD_LR, 5) layout_add_custom.Add(self.input_add_custom, 1, wx.RIGHT, 5) layout_main.Insert(1, layout_add_custom, 0, wx.EXPAND) self.SetSizer(layout_main) self.SetAutoLayout(True) self.Layout() self.CenterOnParent()
def AddButton(self, label, image, btnId=wx.ID_ANY, handler=None): lyt_buttons = self.GetButtonSizer() if lyt_buttons: padding = 0 if len(lyt_buttons.GetChildren()): padding = 5 button = CreateButton(self.GetParent(), btnId, label, image) if button: if handler: button.Bind(wx.EVT_BUTTON, handler) FLAG_TEXT = wx.ALIGN_CENTER_VERTICAL|wx.LEFT lyt_buttons.Add(button, 0, wx.LEFT, padding) if label: lyt_buttons.Add(wx.StaticText(self.GetParent(), label=label), 0, FLAG_TEXT, 5) return button
class Page(WizardPage): ## Constructor # # \param parent # Parent <b><i>wx.Window</i></b> instance def __init__(self, parent): WizardPage.__init__(self, parent, pgid.CHANGELOG) txt_package = wx.StaticText(self, label=GT(u'Package'), name=u'package') self.ti_package = TextArea(self, inputid.PACKAGE, name=txt_package.Name) txt_version = wx.StaticText(self, label=GT(u'Version'), name=u'version') self.ti_version = TextArea(self, inputid.VERSION, name=txt_version.Name) dist_names = GetOSDistNames() txt_dist = wx.StaticText(self, label=GT(u'Distribution'), name=u'dist') if dist_names: self.ti_dist = ComboBox(self, inputid.DIST, choices=dist_names, name=txt_dist.Name) # Use regular text input if could not retrieve distribution names list else: self.ti_dist = TextArea(self, inputid.DIST, name=txt_dist.Name) opts_urgency = ( u'low', u'medium', u'high', u'emergency', ) txt_urgency = wx.StaticText(self, label=GT(u'Urgency'), name=u'urgency') self.sel_urgency = Choice(self, selid.URGENCY, choices=opts_urgency, name=txt_urgency.Name) txt_maintainer = wx.StaticText(self, label=GT(u'Maintainer'), name=u'maintainer') self.ti_maintainer = TextArea(self, inputid.MAINTAINER, name=txt_maintainer.Name) txt_email = wx.StaticText(self, label=GT(u'Email'), name=u'email') self.ti_email = TextArea(self, inputid.EMAIL, name=txt_email.Name) btn_import = CreateButton(self, btnid.IMPORT, GT(u'Import'), u'import', name=u'btn import') txt_import = wx.StaticText( self, label=GT(u'Import information from Control page')) # Changes input self.ti_changes = TextAreaPanel(self, size=(20, 150), name=u'changes') # *** Target installation directory # FIXME: Should this be set by config or project file??? self.pnl_target = FileOTarget(self, u'/usr/share/doc/<package>', name=u'target default', defaultType=CheckBoxESS, customType=PathCtrlESS, pathIds=( chkid.TARGET, inputid.TARGET, )) self.btn_add = CreateButton(self, btnid.ADD, GT(u'Add'), u'add', name=u'btn add') txt_add = wx.StaticText(self, label=GT(u'Insert new changelog entry')) self.chk_indentation = CheckBox(self, label=GT(u'Preserve indentation'), name=u'indent') self.dsp_changes = TextAreaPanelESS(self, inputid.CHANGES, monospace=True, name=u'log') self.dsp_changes.EnableDropTarget() SetPageToolTips(self) # *** Event Handling *** # btn_import.Bind(wx.EVT_BUTTON, self.OnImportFromControl) self.btn_add.Bind(wx.EVT_BUTTON, self.AddInfo) # *** Layout *** # LEFT_BOTTOM = lyt.ALGN_LB LEFT_CENTER = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL RIGHT_CENTER = wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL lyt_info = wx.FlexGridSizer(2, 6) lyt_info.AddGrowableCol(1) lyt_info.AddGrowableCol(3) lyt_info.AddGrowableCol(5) lyt_info.AddMany( ((txt_package, 0, RIGHT_CENTER | wx.RIGHT, 5), (self.ti_package, 1, wx.EXPAND | wx.BOTTOM | wx.RIGHT, 5), (txt_version, 0, RIGHT_CENTER | wx.RIGHT, 5), (self.ti_version, 1, wx.EXPAND | wx.BOTTOM | wx.RIGHT, 5), (txt_dist, 0, RIGHT_CENTER | wx.RIGHT, 5), (self.ti_dist, 1, wx.EXPAND | wx.BOTTOM, 5), (txt_urgency, 0, RIGHT_CENTER | wx.RIGHT, 5), (self.sel_urgency, 1, wx.RIGHT, 5), (txt_maintainer, 0, RIGHT_CENTER | wx.RIGHT, 5), (self.ti_maintainer, 1, wx.EXPAND | wx.RIGHT, 5), (txt_email, 0, RIGHT_CENTER | wx.RIGHT, 5), (self.ti_email, 1, wx.EXPAND))) lyt_details = wx.GridBagSizer() lyt_details.SetCols(3) lyt_details.AddGrowableRow(2) lyt_details.AddGrowableCol(1) lyt_details.Add(btn_import, (0, 0)) lyt_details.Add(txt_import, (0, 1), flag=LEFT_CENTER) lyt_details.Add(wx.StaticText(self, label=GT(u'Changes')), (1, 0), flag=LEFT_BOTTOM) lyt_details.Add(wx.StaticText(self, label=GT(u'Target')), (1, 2), flag=LEFT_BOTTOM) lyt_details.Add(self.ti_changes, (2, 0), (1, 2), wx.EXPAND | wx.RIGHT, 5) lyt_details.Add(self.pnl_target, (2, 2)) lyt_details.Add(self.btn_add, (3, 0), (2, 1)) lyt_details.Add(txt_add, (3, 1), flag=LEFT_BOTTOM | wx.TOP, border=5) lyt_details.Add(self.chk_indentation, (4, 1), flag=LEFT_BOTTOM) lyt_main = BoxSizer(wx.VERTICAL) lyt_main.AddSpacer(10) lyt_main.Add(lyt_info, 0, wx.EXPAND | lyt.PAD_LR, 5) lyt_main.AddSpacer(10) lyt_main.Add(lyt_details, 1, wx.EXPAND | lyt.PAD_LR, 5) lyt_main.Add(wx.StaticText(self, label=u'Changelog Output'), 0, LEFT_BOTTOM | lyt.PAD_LT, 5) lyt_main.Add(self.dsp_changes, 1, wx.EXPAND | lyt.PAD_LR | wx.BOTTOM, 5) self.SetAutoLayout(True) self.SetSizer(lyt_main) self.Layout() ## Formats input text from 'changes' field for new entry in changelog def AddInfo(self, event=None): new_changes = self.ti_changes.GetValue() if TextIsEmpty(new_changes): DetailedMessageDialog( GetMainWindow(), GT(u'Warning'), ICON_WARNING, GT(u'"Changes" section is empty')).ShowModal() self.ti_changes.SetInsertionPointEnd() self.ti_changes.SetFocus() return package = self.ti_package.GetValue() version = self.ti_version.GetValue() dist = self.ti_dist.GetValue() urgency = self.sel_urgency.GetStringSelection() maintainer = self.ti_maintainer.GetValue() email = self.ti_email.GetValue() new_changes = FormatChangelog(new_changes, package, version, dist, urgency, maintainer, email, self.chk_indentation.GetValue()) # Clean up leading & trailing whitespace in old changes old_changes = self.dsp_changes.GetValue().strip(u' \t\n\r') # Only append newlines if log isn't already empty if not TextIsEmpty(old_changes): new_changes = u'{}\n\n\n{}'.format(new_changes, old_changes) # Add empty line to end of log if not new_changes.endswith(u'\n'): new_changes = u'{}\n'.format(new_changes) self.dsp_changes.SetValue(new_changes) # Clear "Changes" text self.ti_changes.Clear() self.ti_changes.SetFocus() ## Exports page's data to file # # \param out_dir # Target directory where file will be written # \out_name # Filename of output file # \compress # If <b><i>True</i></b>, compresses file with gzip def Export(self, out_dir, out_name=wx.EmptyString, compress=False): ret_value = WizardPage.Export(self, out_dir, out_name=out_name) absolute_filename = u'{}/{}'.format(out_dir, out_name).replace(u'//', u'/') CMD_gzip = GetExecutable(u'gzip') if compress and CMD_gzip: commands.getstatusoutput(u'{} -n9 "{}"'.format( CMD_gzip, absolute_filename)) return ret_value ## Export instructions specifically for build phase # # \param stage # Formatted staged directory where file heirarchy is temporarily kept # \return # <b><i>Tuple</i></b> containing a return code & string value of page data def ExportBuild(self, stage): target = self.pnl_target.GetPath() if target == self.pnl_target.GetDefaultPath(): target.replace(u'<package>', GetFieldValue(pgid.CONTROL, inputid.PACKAGE)) stage = ConcatPaths((stage, target)) if not os.path.isdir(stage): os.makedirs(stage) # FIXME: Allow user to set filename self.Export(stage, u'changelog', True) export_summary = GT(u'Changelog export failed') changelog = ConcatPaths((stage, u'changelog.gz')) if os.path.isfile(changelog): export_summary = GT(u'Changelog export to: {}').format(changelog) return (0, export_summary) ## Retrieves changelog text # # The output is a text file that uses sections defined by braces ([, ]) # # \param getModule # If <b><i>True</i></b>, returns a <b><i>tuple</b></i> of the module name # & page data, otherwise return only page data string # \return # <b><i>tuple(str, str)</i></b>: Filename & formatted string of changelog target & body def Get(self, getModule=False): target = self.pnl_target.GetPath() if target == self.pnl_target.GetDefaultPath(): target = u'DEFAULT' body = self.dsp_changes.GetValue() if TextIsEmpty(body): page = None else: page = u'[TARGET={}]\n\n[BODY]\n{}'.format(target, body) if getModule: page = ( __name__, page, ) return page ## Retrieves plain text of the changelog field # # \return # Formatted changelog text def GetChangelog(self): return self.dsp_changes.GetValue() ## Reads & parses page data from a formatted text file # # \param filename # File path to open def ImportFromFile(self, filename): if not os.path.isfile(filename): return dbrerrno.ENOENT clog_data = ReadFile(filename, split=True) sections = {} def parse_section(key, lines): value = u'\n'.join(lines).split(u'\n[')[0] if u'=' in key: key = key.split(u'=') value = (key[-1], value) key = key[0] sections[key] = value # NOTE: This would need to be changed were more sections added to project file for L in clog_data: line_index = clog_data.index(L) if not TextIsEmpty(L) and u'[' in L and u']' in L: L = L.split(u'[')[-1].split(u']')[0] parse_section(L, clog_data[line_index + 1:]) for S in sections: Logger.Debug( __name__, GT(u'Changelog section: "{}", Value:\n{}').format( S, sections[S])) if isinstance(sections[S], (tuple, list)): value_index = 0 for I in sections[S]: Logger.Debug(__name__, GT(u'Value {}: {}').format(value_index, I)) value_index += 1 if S == u'TARGET': Logger.Debug(__name__, u'SECTION TARGET FOUND') if sections[S][0] == u'DEFAULT': Logger.Debug(__name__, u'Using default target') if not self.pnl_target.UsingDefault(): self.pnl_target.Reset() else: Logger.Debug( __name__, GT(u'Using custom target: {}').format(sections[S][0])) self.pnl_target.SetPath(sections[S][0]) continue if S == u'BODY': Logger.Debug(__name__, u'SECTION BODY FOUND') self.dsp_changes.SetValue(sections[S]) continue return 0 ## Checks the page's fields for exporting # # \return # <b><i>False</i></b> if page cannot be exported def IsOkay(self): return not TextIsEmpty(self.dsp_changes.GetValue()) ## Imports select field values from the 'Control' page def OnImportFromControl(self, event=None): fields = ( (self.ti_package, inputid.PACKAGE), (self.ti_version, inputid.VERSION), (self.ti_maintainer, inputid.MAINTAINER), (self.ti_email, inputid.EMAIL), ) for F, FID in fields: field_value = GetFieldValue(pgid.CONTROL, FID) if isinstance(field_value, ErrorTuple): err_msg1 = GT( u'Got error when attempting to retrieve field value') err_msg2 = u'\tError code: {}\n\tError message: {}'.format( field_value.GetCode(), field_value.GetString()) Logger.Error(__name__, u'{}:\n{}'.format(err_msg1, err_msg2)) continue if not TextIsEmpty(field_value): F.SetValue(field_value) ## Sets values of page's fields with given input # # \param data # Text to parse for values def Set(self, data): changelog = data.split(u'\n') target = changelog[0].split(u'<<DEST>>')[1].split(u'<</DEST>>')[0] if target == u'DEFAULT': if not self.pnl_target.UsingDefault(): self.pnl_target.Reset() else: self.pnl_target.SetPath(target) self.dsp_changes.SetValue(u'\n'.join(changelog[1:]))
def __init__(self, parent): WizardPage.__init__(self, parent, pgid.FILES) # *** Left Panel *** # pnl_treeopts = BorderedPanel(self) self.chk_individuals = CheckBoxCFG(pnl_treeopts, label=GT(u'List files individually'), name=u'individually', cfgSect=u'FILES') self.chk_preserve_top = CheckBoxCFG(pnl_treeopts, chkid.TOPLEVEL, GT(u'Preserve top-level directories'), name=u'top-level', cfgSect=u'FILES') self.chk_nofollow_symlink = CheckBoxCFG(pnl_treeopts, chkid.SYMLINK, GT(u'Don\'t follow symbolic links'), defaultValue=True, name=u'nofollow-symlink', cfgSect=u'FILES') self.tree_dirs = DirectoryTreePanel(self, size=(300,20)) # ----- Target path pnl_target = BorderedPanel(self) # choices of destination rb_bin = wx.RadioButton(pnl_target, label=u'/bin', style=wx.RB_GROUP) rb_usrbin = wx.RadioButton(pnl_target, label=u'/usr/bin') rb_usrlib = wx.RadioButton(pnl_target, label=u'/usr/lib') rb_locbin = wx.RadioButton(pnl_target, label=u'/usr/local/bin') rb_loclib = wx.RadioButton(pnl_target, label=u'/usr/local/lib') self.rb_custom = wx.RadioButton(pnl_target, inputid.CUSTOM, GT(u'Custom')) self.rb_custom.Default = True # Start with "Custom" selected self.rb_custom.SetValue(self.rb_custom.Default) # group buttons together # FIXME: Unnecessary??? self.grp_targets = ( rb_bin, rb_usrbin, rb_usrlib, rb_locbin, rb_loclib, self.rb_custom, ) # ----- Add/Remove/Clear buttons btn_add = CreateButton(self, btnid.ADD) btn_remove = CreateButton(self, btnid.REMOVE) btn_clear = CreateButton(self, btnid.CLEAR) self.prev_dest_value = u'/usr/bin' self.ti_target = TextArea(self, defaultValue=self.prev_dest_value, name=u'target') self.btn_browse = CreateButton(self, btnid.BROWSE) btn_refresh = CreateButton(self, btnid.REFRESH) # Display area for files added to list self.lst_files = FileListESS(self, inputid.LIST, name=u'filelist') # *** Event Handling *** # # create an event to enable/disable custom widget for item in self.grp_targets: wx.EVT_RADIOBUTTON(item, wx.ID_ANY, self.OnSetDestination) # Context menu events for directory tree wx.EVT_MENU(self, wx.ID_ADD, self.OnImportFromTree) # Button events btn_add.Bind(wx.EVT_BUTTON, self.OnImportFromTree) btn_remove.Bind(wx.EVT_BUTTON, self.OnRemoveSelected) btn_clear.Bind(wx.EVT_BUTTON, self.OnClearFileList) self.btn_browse.Bind(wx.EVT_BUTTON, self.OnBrowse) btn_refresh.Bind(wx.EVT_BUTTON, self.OnRefreshFileList) # ???: Not sure what these do wx.EVT_KEY_DOWN(self.ti_target, self.GetDestValue) wx.EVT_KEY_UP(self.ti_target, self.CheckDest) # Key events for file list wx.EVT_KEY_DOWN(self.lst_files, self.OnRemoveSelected) self.Bind(wx.EVT_DROP_FILES, self.OnDropFiles) # *** Layout *** # lyt_treeopts = BoxSizer(wx.VERTICAL) lyt_treeopts.AddSpacer(5) lyt_treeopts.Add(self.chk_individuals, 0, lyt.PAD_LR, 5) lyt_treeopts.Add(self.chk_preserve_top, 0, lyt.PAD_LR, 5) lyt_treeopts.Add(self.chk_nofollow_symlink, 0, lyt.PAD_LR, 5) lyt_treeopts.AddSpacer(5) pnl_treeopts.SetSizer(lyt_treeopts) lyt_left = BoxSizer(wx.VERTICAL) lyt_left.AddSpacer(10) lyt_left.Add(wx.StaticText(self, label=GT(u'Directory options')), 0, wx.ALIGN_BOTTOM) lyt_left.Add(pnl_treeopts, 0, wx.EXPAND|wx.ALIGN_LEFT|wx.BOTTOM, 5) lyt_left.Add(self.tree_dirs, 1, wx.EXPAND) lyt_target = wx.GridSizer(3, 2, 5, 5) for item in self.grp_targets: lyt_target.Add(item, 0, lyt.PAD_LR, 5) pnl_target.SetAutoLayout(True) pnl_target.SetSizer(lyt_target) pnl_target.Layout() # Put text input in its own sizer to force expand lyt_input = BoxSizer(wx.HORIZONTAL) lyt_input.Add(self.ti_target, 1, wx.ALIGN_CENTER_VERTICAL) lyt_buttons = BoxSizer(wx.HORIZONTAL) lyt_buttons.Add(btn_add, 0) lyt_buttons.Add(btn_remove, 0) lyt_buttons.Add(btn_clear, 0) lyt_buttons.Add(lyt_input, 1, wx.ALIGN_CENTER_VERTICAL) lyt_buttons.Add(self.btn_browse, 0) lyt_buttons.Add(btn_refresh, 0) lyt_right = BoxSizer(wx.VERTICAL) lyt_right.AddSpacer(10) lyt_right.Add(wx.StaticText(self, label=GT(u'Target'))) lyt_right.Add(pnl_target, 0, wx.TOP, 5) lyt_right.Add(lyt_buttons, 0, wx.EXPAND) lyt_right.Add(self.lst_files, 5, wx.EXPAND|wx.TOP, 5) PROP_LEFT = 0 PROP_RIGHT = 1 lyt_main = wx.FlexGridSizer(1, 2) lyt_main.AddGrowableRow(0) # Directory tree size issues with wx 2.8 if wx.MAJOR_VERSION <= 2: PROP_LEFT = 1 lyt_main.AddGrowableCol(0, 1) lyt_main.AddGrowableCol(1, 2) lyt_main.Add(lyt_left, PROP_LEFT, wx.EXPAND|lyt.PAD_LR|wx.BOTTOM, 5) lyt_main.Add(lyt_right, PROP_RIGHT, wx.EXPAND|lyt.PAD_RB, 5) self.SetAutoLayout(True) self.SetSizer(lyt_main) self.Layout() SetPageToolTips(self)
class Page(WizardPage): ## Constructor # # \param parent # Parent <b><i>wx.Window</i></b> instance def __init__(self, parent): WizardPage.__init__(self, parent, pgid.FILES) # *** Left Panel *** # pnl_treeopts = BorderedPanel(self) self.chk_individuals = CheckBoxCFG(pnl_treeopts, label=GT(u'List files individually'), name=u'individually', cfgSect=u'FILES') self.chk_preserve_top = CheckBoxCFG(pnl_treeopts, chkid.TOPLEVEL, GT(u'Preserve top-level directories'), name=u'top-level', cfgSect=u'FILES') self.chk_nofollow_symlink = CheckBoxCFG(pnl_treeopts, chkid.SYMLINK, GT(u'Don\'t follow symbolic links'), defaultValue=True, name=u'nofollow-symlink', cfgSect=u'FILES') self.tree_dirs = DirectoryTreePanel(self, size=(300,20)) # ----- Target path pnl_target = BorderedPanel(self) # choices of destination rb_bin = wx.RadioButton(pnl_target, label=u'/bin', style=wx.RB_GROUP) rb_usrbin = wx.RadioButton(pnl_target, label=u'/usr/bin') rb_usrlib = wx.RadioButton(pnl_target, label=u'/usr/lib') rb_locbin = wx.RadioButton(pnl_target, label=u'/usr/local/bin') rb_loclib = wx.RadioButton(pnl_target, label=u'/usr/local/lib') self.rb_custom = wx.RadioButton(pnl_target, inputid.CUSTOM, GT(u'Custom')) self.rb_custom.Default = True # Start with "Custom" selected self.rb_custom.SetValue(self.rb_custom.Default) # group buttons together # FIXME: Unnecessary??? self.grp_targets = ( rb_bin, rb_usrbin, rb_usrlib, rb_locbin, rb_loclib, self.rb_custom, ) # ----- Add/Remove/Clear buttons btn_add = CreateButton(self, btnid.ADD) btn_remove = CreateButton(self, btnid.REMOVE) btn_clear = CreateButton(self, btnid.CLEAR) self.prev_dest_value = u'/usr/bin' self.ti_target = TextArea(self, defaultValue=self.prev_dest_value, name=u'target') self.btn_browse = CreateButton(self, btnid.BROWSE) btn_refresh = CreateButton(self, btnid.REFRESH) # Display area for files added to list self.lst_files = FileListESS(self, inputid.LIST, name=u'filelist') # *** Event Handling *** # # create an event to enable/disable custom widget for item in self.grp_targets: wx.EVT_RADIOBUTTON(item, wx.ID_ANY, self.OnSetDestination) # Context menu events for directory tree wx.EVT_MENU(self, wx.ID_ADD, self.OnImportFromTree) # Button events btn_add.Bind(wx.EVT_BUTTON, self.OnImportFromTree) btn_remove.Bind(wx.EVT_BUTTON, self.OnRemoveSelected) btn_clear.Bind(wx.EVT_BUTTON, self.OnClearFileList) self.btn_browse.Bind(wx.EVT_BUTTON, self.OnBrowse) btn_refresh.Bind(wx.EVT_BUTTON, self.OnRefreshFileList) # ???: Not sure what these do wx.EVT_KEY_DOWN(self.ti_target, self.GetDestValue) wx.EVT_KEY_UP(self.ti_target, self.CheckDest) # Key events for file list wx.EVT_KEY_DOWN(self.lst_files, self.OnRemoveSelected) self.Bind(wx.EVT_DROP_FILES, self.OnDropFiles) # *** Layout *** # lyt_treeopts = BoxSizer(wx.VERTICAL) lyt_treeopts.AddSpacer(5) lyt_treeopts.Add(self.chk_individuals, 0, lyt.PAD_LR, 5) lyt_treeopts.Add(self.chk_preserve_top, 0, lyt.PAD_LR, 5) lyt_treeopts.Add(self.chk_nofollow_symlink, 0, lyt.PAD_LR, 5) lyt_treeopts.AddSpacer(5) pnl_treeopts.SetSizer(lyt_treeopts) lyt_left = BoxSizer(wx.VERTICAL) lyt_left.AddSpacer(10) lyt_left.Add(wx.StaticText(self, label=GT(u'Directory options')), 0, wx.ALIGN_BOTTOM) lyt_left.Add(pnl_treeopts, 0, wx.EXPAND|wx.ALIGN_LEFT|wx.BOTTOM, 5) lyt_left.Add(self.tree_dirs, 1, wx.EXPAND) lyt_target = wx.GridSizer(3, 2, 5, 5) for item in self.grp_targets: lyt_target.Add(item, 0, lyt.PAD_LR, 5) pnl_target.SetAutoLayout(True) pnl_target.SetSizer(lyt_target) pnl_target.Layout() # Put text input in its own sizer to force expand lyt_input = BoxSizer(wx.HORIZONTAL) lyt_input.Add(self.ti_target, 1, wx.ALIGN_CENTER_VERTICAL) lyt_buttons = BoxSizer(wx.HORIZONTAL) lyt_buttons.Add(btn_add, 0) lyt_buttons.Add(btn_remove, 0) lyt_buttons.Add(btn_clear, 0) lyt_buttons.Add(lyt_input, 1, wx.ALIGN_CENTER_VERTICAL) lyt_buttons.Add(self.btn_browse, 0) lyt_buttons.Add(btn_refresh, 0) lyt_right = BoxSizer(wx.VERTICAL) lyt_right.AddSpacer(10) lyt_right.Add(wx.StaticText(self, label=GT(u'Target'))) lyt_right.Add(pnl_target, 0, wx.TOP, 5) lyt_right.Add(lyt_buttons, 0, wx.EXPAND) lyt_right.Add(self.lst_files, 5, wx.EXPAND|wx.TOP, 5) PROP_LEFT = 0 PROP_RIGHT = 1 lyt_main = wx.FlexGridSizer(1, 2) lyt_main.AddGrowableRow(0) # Directory tree size issues with wx 2.8 if wx.MAJOR_VERSION <= 2: PROP_LEFT = 1 lyt_main.AddGrowableCol(0, 1) lyt_main.AddGrowableCol(1, 2) lyt_main.Add(lyt_left, PROP_LEFT, wx.EXPAND|lyt.PAD_LR|wx.BOTTOM, 5) lyt_main.Add(lyt_right, PROP_RIGHT, wx.EXPAND|lyt.PAD_RB, 5) self.SetAutoLayout(True) self.SetSizer(lyt_main) self.Layout() SetPageToolTips(self) ## Adds files to file list # # \param dirs # <b><i>dict</i></b>: dict[dir] = [file list] # \param fileCount # Number of explicit files being added to list # \param showDialog # If <b><i>True</i></b>, displays a progress dialog def AddPaths(self, dirs, fileCount=None, showDialog=False): target = self.GetTarget() if fileCount == None: fileCount = 0 for D in dirs: for F in dirs[D]: fileCount += 1 progress = None Logger.Debug(__name__, u'Adding {} files ...'.format(fileCount)) if showDialog: progress = ProgressDialog(GetMainWindow(), GT(u'Adding Files'), maximum=fileCount, style=PD_DEFAULT_STYLE|wx.PD_CAN_ABORT) progress.Show() completed = 0 for D in sorted(dirs): for F in sorted(dirs[D]): if progress and progress.WasCancelled(): progress.Destroy() return False if progress: wx.Yield() progress.Update(completed, GT(u'Adding file {}').format(F)) self.lst_files.AddFile(F, D, target) completed += 1 if progress: wx.Yield() progress.Update(completed) progress.Destroy() return True ## TODO: Doxygen def CheckDest(self, event=None): if TextIsEmpty(self.ti_target.GetValue()): self.ti_target.SetValue(self.prev_dest_value) self.ti_target.SetInsertionPoint(-1) elif self.ti_target.GetValue()[0] != u'/': self.ti_target.SetValue(self.prev_dest_value) self.ti_target.SetInsertionPoint(-1) if event: event.Skip() ## Retrieves information on files to be packaged # # \return # A list of files with their targets formatted for text output def Get(self): # Remove section delimeters & first line which is just an integer return self.GetSaveData().split(u'\n')[2:-1] ## Retrieves target destination set by user input # # TODO: Rename to 'GetTarget' or 'GetInputTarget' def GetDestValue(self, event=None): if not TextIsEmpty(self.ti_target.GetValue()): if self.ti_target.GetValue()[0] == u'/': self.prev_dest_value = self.ti_target.GetValue() if event: event.Skip() ## Retrieves the directory tree object used by this page # # Used in input.list.FileList for referencing size # # \return # <b><i>ui.tree.DirectoryTreePanel</i></b> instance def GetDirTreePanel(self): return self.tree_dirs ## Retrieves number of files in list # # \return # <b><i>Integer</i></b> count of items in file list def GetFileCount(self): return self.lst_files.GetItemCount() ## Retrieves the file list object used by this page # # \return # <b><i>input.list.FileList</i></b> instance def GetListInstance(self): return self.lst_files ## Retrieves file list to export to text file # # \return # List formatted text def GetSaveData(self): file_list = [] item_count = self.lst_files.GetItemCount() if item_count > 0: count = 0 while count < item_count: filename = self.lst_files.GetItemText(count) source = self.lst_files.GetItem(count, columns.SOURCE).GetText() target = self.lst_files.GetItem(count, columns.TARGET).GetText() absolute_filename = ConcatPaths((source, filename)) # Populate list with tuples of ('src', 'file', 'dest') if self.lst_files.GetItemTextColour(count) == (255, 0, 0): # Mark file as executable file_list.append((u'{}*'.format(absolute_filename), filename, target)) else: file_list.append((absolute_filename, filename, target)) count += 1 return_list = [] for F in file_list: f0 = u'{}'.encode(u'utf-8').format(F[0]) f1 = u'{}'.encode(u'utf-8').format(F[1]) f2 = u'{}'.encode(u'utf-8').format(F[2]) return_list.append(u'{} -> {} -> {}'.format(f0, f1, f2)) return u'<<FILES>>\n1\n{}\n<</FILES>>'.format(u'\n'.join(return_list)) else: # Place a "0" in FILES field if we are not saving any files return u'<<FILES>>\n0\n<</FILES>>' ## Retrieves the target output directory # # FIXME: Duplicate of wizbin.files.Page.GetDestValue? def GetTarget(self): if FieldEnabled(self.ti_target): return self.ti_target.GetValue() for target in self.grp_targets: if target.GetId() != inputid.CUSTOM and target.GetValue(): return target.GetLabel() ## Accepts a file path to read & parse to fill the page's fields # # \param filename # Absolute path of formatted text file to read def ImportFromFile(self, filename): Logger.Debug(__name__, GT(u'Importing page info from {}').format(filename)) if not os.path.isfile(filename): return dbrerrno.ENOENT files_data = ReadFile(filename, split=True) # Lines beginning with these characters will be ignored ignore_characters = ( u'', u' ', u'#', ) target = None targets_list = [] for L in files_data: if not TextIsEmpty(L) and L[0] not in ignore_characters: if u'[' in L and u']' in L: target = L.split(u'[')[-1].split(u']')[0] continue if target: executable = (len(L) > 1 and L[-2:] == u' *') if executable: L = L[:-2] targets_list.append((target, L, executable)) missing_files = [] for T in targets_list: # FIXME: Create method in FileList class to retrieve all missing files if not os.path.exists(T[1]): missing_files.append(T[1]) source_file = os.path.basename(T[1]) source_dir = os.path.dirname(T[1]) self.lst_files.AddFile(source_file, source_dir, T[0], executable=T[2]) if len(missing_files): main_window = GetMainWindow() err_line1 = GT(u'The following files/folders are missing from the filesystem.') err_line2 = GT(u'They will be highlighted on the Files page.') DetailedMessageDialog(main_window, title=GT(u'Warning'), icon=ICON_ERROR, text=u'\n'.join((err_line1, err_line2)), details=u'\n'.join(missing_files)).ShowModal() return 0 ## Checks if the page is ready for export/build # # \return # <b><i>True</i></b> if the file list (self.lst_files) is not empty def IsOkay(self): return not self.lst_files.IsEmpty() ## Reads files & directories & preps for loading into list # # \param pathsList # <b><i>List/Tuple</i></b> of <b><i>string</i></b> values representing # files & directories to be added # \return # Value of wizbin.files.Page.AddPaths, or <b><i>False</i></b> in case of error def LoadPaths(self, pathsList): if isinstance(pathsList, tuple): pathsList = list(pathsList) if not pathsList or not isinstance(pathsList, list): return False file_list = [] dir_list = {} prep = ProgressDialog(GetMainWindow(), GT(u'Processing Files'), GT(u'Scanning files ...'), style=wx.PD_APP_MODAL|wx.PD_AUTO_HIDE|wx.PD_CAN_ABORT) # Only update the gauge every N files (hack until I figure out timer) update_interval = 450 count = 0 prep.Show() if not self.chk_preserve_top.GetValue(): for INDEX in reversed(range(len(pathsList))): path = pathsList[INDEX] if os.path.isdir(path): # Remove top-level directory from list pathsList.pop(INDEX) insert_index = INDEX for P in os.listdir(path): pathsList.insert(insert_index, ConcatPaths((path, P))) insert_index += 1 try: for P in pathsList: if prep.WasCancelled(): prep.Destroy() return False count += 1 if count >= update_interval: wx.Yield() prep.Pulse() count = 0 if not self.chk_individuals.GetValue() or os.path.isfile(P): file_list.append(P) continue if os.path.isdir(P): parent_dir = os.path.dirname(P) if parent_dir not in dir_list: dir_list[parent_dir] = [] for ROOT, DIRS, FILES in os.walk(P): if prep.WasCancelled(): prep.Destroy() return False wx.Yield() prep.SetMessage(GT(u'Scanning directory {} ...').format(ROOT)) count += 1 if count >= update_interval: wx.Yield() prep.Pulse() count = 0 for F in FILES: if prep.WasCancelled(): prep.Destroy() return False count += 1 if count >= update_interval: wx.Yield() prep.Pulse() count = 0 # os.path.dirname preserves top level directory ROOT = ROOT.replace(os.path.dirname(P), u'').strip(u'/') F = u'{}/{}'.format(ROOT, F).strip(u'/') if F not in dir_list[parent_dir]: dir_list[parent_dir].append(F) except: prep.Destroy() ShowErrorDialog(GT(u'Could not retrieve file list'), traceback.format_exc()) return False wx.Yield() prep.Pulse(GT(u'Counting Files')) file_count = len(file_list) count = 0 for D in dir_list: for F in dir_list[D]: file_count += 1 count += 1 if count >= update_interval: wx.Yield() prep.Pulse() count = 0 prep.Destroy() # Add files to directory list for F in file_list: f_name = os.path.basename(F) f_dir = os.path.dirname(F) if f_dir not in dir_list: dir_list[f_dir] = [] dir_list[f_dir].append(f_name) if file_count > warning_threshhold: count_warnmsg = GT(u'Importing {} files'.format(file_count)) count_warnmsg = u'{}. {}.'.format(count_warnmsg, GT(u'This could take a VERY long time')) count_warnmsg = u'{}\n{}'.format(count_warnmsg, GT(u'Are you sure you want to continue?')) if not ConfirmationDialog(GetMainWindow(), text=count_warnmsg).Confirmed(): return False return self.AddPaths(dir_list, file_count, showDialog=file_count >= efficiency_threshold) ## Handles event emitted by 'browse' button # # Opens a directory dialog to select a custom output target def OnBrowse(self, event=None): dia = GetDirDialog(GetMainWindow(), GT(u'Choose Target Directory')) if ShowDialog(dia): self.ti_target.SetValue(dia.GetPath()) ## Handles event emitted by 'clear' button # # Displays confirmation dialog to clear list if not empty # # TODO: Rename to OnClearList? def OnClearFileList(self, event=None): if self.lst_files.GetItemCount(): if ConfirmationDialog(GetMainWindow(), GT(u'Confirm'), GT(u'Clear all files?')).Confirmed(): self.lst_files.DeleteAllItems() ## Adds files to list from file manager drop # # Note that this method should not be renamed as 'OnDropFiles' # is the implicit handler for wx.FileDropTarget (<- correct class???) # # \param fileList # <b><i>List</i></b> of files dropped from file manager # \return # Value of wizbin.files.Page.LoadPaths def OnDropFiles(self, fileList): return self.LoadPaths(fileList) ## Handles files & directories added from ui.tree.DirectoryTreePanel object # (self.tree_dirs) # # Actually bypasses DirectoryTreePanel & directly accesses # ui.tree.DirectoryTree.GetSelectedPaths def OnImportFromTree(self, event=None): return self.LoadPaths(self.DirTree.GetSelectedPaths()) ## Updates files' status in the file list # # Refreshes files' executable & available status # # \return # Value of self.lst_files.RefreshFileList def OnRefreshFileList(self, event=None): return self.lst_files.RefreshFileList() ## Handles event emitted by 'remove' button # # Removes all currently selected/highlighted files in list def OnRemoveSelected(self, event=None): try: modifier = event.GetModifiers() keycode = event.GetKeyCode() except AttributeError: keycode = event.GetEventObject().GetId() if keycode in (wx.ID_REMOVE, wx.WXK_DELETE): self.lst_files.RemoveSelected() elif keycode == 65 and modifier == wx.MOD_CONTROL: self.lst_files.SelectAll() ## Handles enabling/disabling the custom target field if the corresponding # when a target radio button is selected # # TODO: Rename to 'OnSetTarget' or 'OnSelectTarget' def OnSetDestination(self, event=None): enable = self.rb_custom.GetValue() self.ti_target.Enable(enable) self.btn_browse.Enable(enable) ## Resets page's fields to default values # # \return # Value of self.lst_files.Reset def Reset(self): return self.lst_files.Reset() ## Selects all files in the list # # \return # Value of self.lst_files.SelectAll def SelectAll(self): return self.lst_files.SelectAll() ## Sets the page's fields # # \param data # The text information to parse # \return # <b><i>True</i></b> if the data was imported correctly def Set(self, data): # Clear files list self.lst_files.DeleteAllItems() files_data = data.split(u'\n') if int(files_data[0]): # Get file count from list minus first item "1" files_total = len(files_data) # Store missing files here missing_files = [] progress = None if files_total >= efficiency_threshold: progress = ProgressDialog(GetMainWindow(), GT(u'Adding Files'), maximum=files_total, style=PD_DEFAULT_STYLE|wx.PD_CAN_ABORT) wx.Yield() progress.Show() current_file = files_total while current_file > 1: if progress and progress.WasCancelled(): progress.Destroy() # Project continues opening even if file import is cancelled msg = ( GT(u'File import did not complete.'), GT(u'Project files may be missing in file list.'), ) ShowMessageDialog(u'\n'.join(msg), GT(u'Import Cancelled')) return False current_file -= 1 executable = False file_info = files_data[current_file].split(u' -> ') absolute_filename = file_info[0] if absolute_filename[-1] == u'*': # Set executable flag and remove "*" executable = True absolute_filename = absolute_filename[:-1] filename = file_info[1] source_dir = absolute_filename[:len(absolute_filename) - len(filename)] target_dir = file_info[2] if not self.lst_files.AddFile(filename, source_dir, target_dir, executable): Logger.Warn(__name__, GT(u'File not found: {}').format(absolute_filename)) missing_files.append(absolute_filename) if progress: update_value = files_total - current_file wx.Yield() progress.Update(update_value+1, GT(u'Imported file {} of {}').format(update_value, files_total)) if progress: progress.Destroy() Logger.Debug(__name__, u'Missing file count: {}'.format(len(missing_files))) # If files are missing show a message if missing_files: alert = DetailedMessageDialog(GetMainWindow(), GT(u'Missing Files'), ICON_EXCLAMATION, GT(u'Could not locate the following files:'), u'\n'.join(missing_files)) alert.ShowModal() return True
def __init__(self, parent): WizardPage.__init__(self, parent, pgid.BUILD) # Bypass build prep check self.prebuild_check = False # Add checkable items to this list # FIXME: Use a different method self.build_options = [] # ----- Extra Options pnl_options = BorderedPanel(self) self.chk_md5 = CheckBoxESS(pnl_options, chkid.MD5, GT(u'Create md5sums file'), name=u'MD5', defaultValue=True, commands=u'md5sum') # The » character denotes that an alternate tooltip should be shown if the control is disabled self.chk_md5.tt_name = u'md5»' self.chk_md5.col = 0 if UsingTest(u'alpha'): # Brings up control file preview for editing self.chk_editctrl = CheckBoxCFG( pnl_options, chkid.EDIT, GT(u'Preview control file for editing'), name=u'editctrl') self.chk_editctrl.col = 1 # TODO: Use CheckBoxCFG instead of CheckBoxESS: # Fields will be set from config instead of project file # Option to strip binaries self.chk_strip = CheckBoxESS(pnl_options, chkid.STRIP, GT(u'Strip binaries'), name=u'strip»', defaultValue=True, commands=u'strip') self.chk_strip.col = 0 # Deletes the temporary build tree self.chk_rmstage = CheckBoxESS(pnl_options, chkid.DELETE, GT(u'Delete staged directory'), name=u'RMSTAGE', defaultValue=True) self.chk_rmstage.col = 0 # Checks the output .deb for errors self.chk_lint = CheckBoxESS( pnl_options, chkid.LINT, GT(u'Check package for errors with lintian'), name=u'LINTIAN', defaultValue=True, commands=u'lintian') self.chk_lint.tt_name = u'lintian»' self.chk_lint.col = 0 # Installs the deb on the system self.chk_install = CheckBox(pnl_options, chkid.INSTALL, GT(u'Install package after build'), name=u'INSTALL', commands=( u'gdebi-gtk', u'gdebi-kde', )) self.chk_install.tt_name = u'install»' self.chk_install.col = 0 # *** Lintian Overrides *** # if UsingTest(u'alpha'): # FIXME: Move next to lintian check box self.lint_overrides = [] btn_lint_overrides = CreateButton(self, label=GT(u'Lintian overrides')) btn_lint_overrides.Bind(wx.EVT_BUTTON, self.OnSetLintOverrides) btn_build = CreateButton(self, btnid.BUILD, GT(u'Build'), u'build', 64) # Display log dsp_log = OutputLog(self) SetPageToolTips(self) # *** Event Handling *** # btn_build.Bind(wx.EVT_BUTTON, self.OnBuild) # *** Layout *** # lyt_options = wx.GridBagSizer() next_row = 0 prev_row = next_row for CHK in pnl_options.Children: row = next_row FLAGS = lyt.PAD_LR if CHK.col: row = prev_row FLAGS = wx.RIGHT lyt_options.Add(CHK, (row, CHK.col), flag=FLAGS, border=5) if not CHK.col: prev_row = next_row next_row += 1 pnl_options.SetSizer(lyt_options) pnl_options.SetAutoLayout(True) pnl_options.Layout() lyt_buttons = BoxSizer(wx.HORIZONTAL) lyt_buttons.Add(btn_build, 1) lyt_main = BoxSizer(wx.VERTICAL) lyt_main.AddSpacer(10) lyt_main.Add(wx.StaticText(self, label=GT(u'Extra Options')), 0, lyt.ALGN_LB | wx.LEFT, 5) lyt_main.Add(pnl_options, 0, wx.LEFT, 5) lyt_main.AddSpacer(5) if UsingTest(u'alpha'): #lyt_main.Add(wx.StaticText(self, label=GT(u'Lintian overrides')), 0, wx.LEFT, 5) lyt_main.Add(btn_lint_overrides, 0, wx.LEFT, 5) lyt_main.AddSpacer(5) lyt_main.Add(lyt_buttons, 0, lyt.ALGN_C) lyt_main.Add(dsp_log, 2, wx.EXPAND | lyt.PAD_LRB, 5) self.SetAutoLayout(True) self.SetSizer(lyt_main) self.Layout() # *** Post-layout functions *** # self.InitDefaultSettings()
def __init__(self, parent): wx.Dialog.__init__(self, parent, title=GT(u'Quick Build'), pos=wx.DefaultPosition, size=wx.Size(400, 260)) self.title = self.GetTitle() label_stage = wx.StaticText(self, label=GT(u'Staged directory tree')) self.input_stage = wx.TextCtrl(self) self.input_stage.SetToolTip( wx.ToolTip(GT(u'Root directory of build tree'))) btn_browse_stage = CreateButton(self, btnid.STAGE, image=u'browse') btn_browse_stage.Bind(wx.EVT_BUTTON, self.OnBrowse) label_target = wx.StaticText(self, label=GT(u'Target file')) self.input_target = wx.TextCtrl(self) self.input_target.SetToolTip(wx.ToolTip(GT(u'Target output file'))) btn_browse_target = CreateButton(self, btnid.TARGET, image=u'browse') btn_browse_target.Bind(wx.EVT_BUTTON, self.OnBrowse) btn_build = CreateButton(self, btnid.BUILD) btn_build.SetToolTip(wx.ToolTip(GT(u'Start building'))) btn_build.Bind(wx.EVT_BUTTON, self.OnBuild) btn_cancel = CreateButton(self, btnid.EXIT) btn_cancel.SetToolTip(wx.ToolTip(GT(u'Close dialog'))) btn_cancel.Bind(wx.EVT_BUTTON, self.OnClose) self.gauge = wx.Gauge(self, GAUGE_MAX) self.timer = DebreateTimer(self) self.Bind(wx.EVT_TIMER, self.OnUpdateProgress) self.Bind(EVT_TIMER_STOP, self.OnTimerStop) # *** Layout *** # Lstage_V1 = BoxSizer(wx.VERTICAL) Lstage_V1.Add(label_stage, 0, wx.ALIGN_LEFT) Lstage_V1.Add(self.input_stage, 1, wx.EXPAND) Lstage_H1 = BoxSizer(wx.HORIZONTAL) Lstage_H1.Add(Lstage_V1, 3, wx.ALIGN_TOP) Lstage_H1.Add(btn_browse_stage, 0, wx.ALIGN_TOP | wx.TOP, 7) Ltarget_V1 = BoxSizer(wx.VERTICAL) Ltarget_V1.Add(label_target, 0, wx.ALIGN_LEFT) Ltarget_V1.Add(self.input_target, 1, wx.EXPAND) Ltarget_H1 = BoxSizer(wx.HORIZONTAL) Ltarget_H1.Add(Ltarget_V1, 3, wx.ALIGN_TOP) Ltarget_H1.Add(btn_browse_target, 0, wx.ALIGN_TOP | wx.TOP, 7) Lbtn_H1 = BoxSizer(wx.HORIZONTAL) Lbtn_H1.Add(btn_build, 1, wx.ALIGN_BOTTOM | wx.RIGHT, 2) Lbtn_H1.Add(btn_cancel, 1, wx.ALIGN_BOTTOM | wx.LEFT, 2) Lguage_H1 = BoxSizer(wx.HORIZONTAL) Lguage_H1.Add(self.gauge, 1, lyt.PAD_LR, 5) Lmain_V = BoxSizer(wx.VERTICAL) Lmain_V.AddSpacer(1, wx.EXPAND) Lmain_V.Add(Lstage_H1, -1, wx.EXPAND | lyt.PAD_LR, 5) Lmain_V.Add(Ltarget_H1, -1, wx.EXPAND | lyt.PAD_LR, 5) Lmain_V.Add(Lbtn_H1, -1, wx.ALIGN_CENTER | wx.ALL, 5) Lmain_V.Add(Lguage_H1, -1, wx.EXPAND | wx.ALL, 5) Lmain_V.AddSpacer(1, wx.EXPAND) self.SetAutoLayout(True) self.SetSizer(Lmain_V) self.Layout() self.Bind(wx.EVT_CLOSE, self.OnClose) self.CenterOnParent() # For showing error dialog after build thread exits self.build_error = None
def __init__(self, parent): WizardPage.__init__(self, parent, pgid.COPYRIGHT) self.custom_licenses = [] ## A list of available license templates self.sel_templates = Choice(self, selid.LICENSE, name=u'list»') # Initialize the template list self.OnRefreshList() btn_template = CreateButton(self, label=GT(u'Full Template'), image=u'full', name=u'full»') self.btn_template_simple = CreateButton(self, label=GT(u'Short Template'), image=u'short', name=u'short»') btn_refresh = CreateButton(self, btnid.REFRESH, GT(u'Refresh Template List'), u'refresh', name=u'btn refresh') btn_open = CreateButton(self, btnid.BROWSE, GT(u'Open Template Directory'), u'browse', name=u'btn opendir', commands=u'xdg-open') if not self.sel_templates.GetCount(): self.sel_templates.Enable(False) btn_template.Enable(False) self.btn_template_simple.Enable(False) ## Area where license text is displayed self.dsp_copyright = TextAreaPanelESS(self, monospace=True, name=u'license') self.dsp_copyright.EnableDropTarget() SetPageToolTips(self) # Initiate tooltip for drop-down selector if self.sel_templates.IsEnabled(): self.OnSelectLicense(self.sel_templates) # *** Event Handling *** # self.sel_templates.Bind(wx.EVT_CHOICE, self.OnSelectLicense) btn_open.Bind(wx.EVT_BUTTON, self.OnOpenPath) btn_refresh.Bind(wx.EVT_BUTTON, self.OnRefreshList) btn_template.Bind(wx.EVT_BUTTON, self.OnTemplateFull) self.btn_template_simple.Bind(wx.EVT_BUTTON, self.OnTemplateShort) # *** Layout *** # lyt_top = BoxSizer(wx.HORIZONTAL) lyt_top.Add(wx.StaticText(self, label=GT(u'Available Templates')), 0, lyt.ALGN_CV) lyt_top.Add(self.sel_templates, 0, lyt.ALGN_CV|wx.LEFT, 5) lyt_top.Add(btn_template, 0, wx.LEFT, 5) lyt_top.Add(self.btn_template_simple) lyt_top.Add(btn_refresh) lyt_top.Add(btn_open) lyt_main = BoxSizer(wx.VERTICAL) lyt_main.AddSpacer(10) lyt_main.Add(lyt_top, 0, lyt.PAD_LR|wx.BOTTOM, 5) lyt_main.Add(self.dsp_copyright, 1, wx.EXPAND|lyt.PAD_LRB, 5) self.SetAutoLayout(True) self.SetSizer(lyt_main) self.Layout()
def __init__(self, parent): WizardPage.__init__(self, parent, pgid.MENU) #, name=GT(u'Menu Launcher')) ## Override default label self.Label = GT(u'Menu Launcher') # --- Buttons to open/preview/save .desktop file btn_open = CreateButton(self, btnid.BROWSE, GT(u'Browse'), u'browse', name=u'btn browse') btn_save = CreateButton(self, btnid.SAVE, GT(u'Save'), u'save', name=u'btn save') btn_preview = CreateButton(self, btnid.PREVIEW, GT(u'Preview'), u'preview', name=u'btn preview') # --- CHECKBOX chk_enable = CheckBox(self, chkid.ENABLE, GT(u'Create system menu launcher')) # --- TYPE opts_type = ( u'Application', u'Link', u'Directory', ) txt_type = wx.StaticText(self, label=GT(u'Type'), name=u'type') ti_type = ComboBoxESS(self, inputid.TYPE, choices=opts_type, name=u'Type', defaultValue=opts_type[0]) # --- ENCODING opts_enc = ( u'UTF-1', u'UTF-7', u'UTF-8', u'CESU-8', u'UTF-EBCDIC', u'UTF-16', u'UTF-32', u'SCSU', u'BOCU-1', u'Punycode', u'GB 18030', ) txt_enc = wx.StaticText(self, label=GT(u'Encoding'), name=u'encoding') ti_enc = ComboBoxESS(self, inputid.ENC, choices=opts_enc, name=u'Encoding', defaultValue=opts_enc[2]) # --- TERMINAL chk_term = CheckBoxESS(self, chkid.TERM, GT(u'Terminal'), name=u'Terminal') # --- STARTUP NOTIFY chk_notify = CheckBoxESS(self, chkid.NOTIFY, GT(u'Startup Notify'), name=u'StartupNotify', defaultValue=True) # --- Custom output filename txt_filename = wx.StaticText(self, txtid.FNAME, GT(u'Filename'), name=u'filename') ti_filename = TextArea(self, inputid.FNAME, name=txt_filename.Name) chk_filename = CheckBox( self, chkid.FNAME, GT(u'Use "Name" as output filename (<Name>.desktop)'), name=u'filename chk', defaultValue=True) # --- NAME (menu) txt_name = wx.StaticText(self, label=GT(u'Name'), name=u'name*') ti_name = TextAreaESS(self, inputid.NAME, name=u'Name') ti_name.req = True # --- EXECUTABLE txt_exec = wx.StaticText(self, label=GT(u'Executable'), name=u'exec') ti_exec = TextAreaESS(self, inputid.EXEC, name=u'Exec') # --- COMMENT txt_comm = wx.StaticText(self, label=GT(u'Comment'), name=u'comment') ti_comm = TextAreaESS(self, inputid.DESCR, name=u'Comment') # --- ICON txt_icon = wx.StaticText(self, label=GT(u'Icon'), name=u'icon') ti_icon = TextAreaESS(self, inputid.ICON, name=u'Icon') txt_mime = wx.StaticText(self, label=GT(u'MIME Type'), name=u'mime') ti_mime = TextAreaESS(self, inputid.MIME, defaultValue=wx.EmptyString, name=u'MimeType') # ----- OTHER/CUSTOM txt_other = wx.StaticText(self, label=GT(u'Custom Fields'), name=u'other') ti_other = TextAreaPanel(self, inputid.OTHER, name=txt_other.Name) ti_other.EnableDropTarget() # --- CATEGORIES opts_category = ( u'2DGraphics', u'Accessibility', u'Application', u'ArcadeGame', u'Archiving', u'Audio', u'AudioVideo', u'BlocksGame', u'BoardGame', u'Calculator', u'Calendar', u'CardGame', u'Compression', u'ContactManagement', u'Core', u'DesktopSettings', u'Development', u'Dictionary', u'DiscBurning', u'Documentation', u'Email', u'FileManager', u'FileTransfer', u'Game', u'GNOME', u'Graphics', u'GTK', u'HardwareSettings', u'InstantMessaging', u'KDE', u'LogicGame', u'Math', u'Monitor', u'Network', u'OCR', u'Office', u'P2P', u'PackageManager', u'Photography', u'Player', u'Presentation', u'Printing', u'Qt', u'RasterGraphics', u'Recorder', u'RemoteAccess', u'Scanning', u'Screensaver', u'Security', u'Settings', u'Spreadsheet', u'System', u'Telephony', u'TerminalEmulator', u'TextEditor', u'Utility', u'VectorGraphics', u'Video', u'Viewer', u'WordProcessor', u'Wine', u'Wine-Programs-Accessories', u'X-GNOME-NetworkSettings', u'X-GNOME-PersonalSettings', u'X-GNOME-SystemSettings', u'X-KDE-More', u'X-Red-Hat-Base', u'X-SuSE-ControlCenter-System', ) txt_category = wx.StaticText(self, label=GT(u'Categories'), name=u'category') # This option does not get set by importing a new project ti_category = ComboBox(self, inputid.CAT, choices=opts_category, name=txt_category.Name, defaultValue=opts_category[0]) btn_catadd = CreateButton(self, btnid.ADD, GT(u'Add'), u'add', name=u'add category') btn_catdel = CreateButton(self, btnid.REMOVE, GT(u'Remove'), u'remove', name=u'rm category') btn_catclr = CreateButton(self, btnid.CLEAR, GT(u'Clear'), u'clear', name=u'clear category') # FIXME: Allow using multi-select + remove lst_categories = ListCtrl(self, listid.CAT, name=u'Categories') # Can't set LC_SINGLE_SEL in constructor for wx 3.0 (ListCtrl bug???) lst_categories.SetSingleStyle(wx.LC_SINGLE_SEL) self.OnToggle() SetPageToolTips(self) # *** Event Handling *** # btn_open.Bind(wx.EVT_BUTTON, self.OnLoadLauncher) btn_save.Bind(wx.EVT_BUTTON, self.OnExportLauncher) btn_preview.Bind(wx.EVT_BUTTON, self.OnPreviewLauncher) chk_enable.Bind(wx.EVT_CHECKBOX, self.OnToggle) chk_filename.Bind(wx.EVT_CHECKBOX, self.OnSetCustomFilename) wx.EVT_KEY_DOWN(ti_category, self.SetCategory) wx.EVT_KEY_DOWN(lst_categories, self.SetCategory) btn_catadd.Bind(wx.EVT_BUTTON, self.SetCategory) btn_catdel.Bind(wx.EVT_BUTTON, self.SetCategory) btn_catclr.Bind(wx.EVT_BUTTON, self.OnClearCategories) # *** Layout *** # LEFT_CENTER = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL LEFT_BOTTOM = lyt.ALGN_LB RIGHT_BOTTOM = wx.ALIGN_RIGHT | wx.ALIGN_BOTTOM lyt_top = BoxSizer(wx.HORIZONTAL) lyt_top.Add(chk_enable, 0, LEFT_BOTTOM) lyt_top.AddStretchSpacer(1) lyt_top.Add(btn_open, 0, wx.ALIGN_TOP) lyt_top.Add(btn_save, 0, wx.ALIGN_TOP) lyt_top.Add(btn_preview, 0, wx.ALIGN_TOP) lyt_opts1 = wx.FlexGridSizer() lyt_opts1.SetCols(3) lyt_opts1.SetRows(2) lyt_opts1.Add(txt_type, 0, LEFT_CENTER) lyt_opts1.Add(ti_type, 0, wx.EXPAND | wx.LEFT, 5) lyt_opts1.Add(chk_term, 0, LEFT_CENTER | wx.LEFT, 5) lyt_opts1.Add(txt_enc, 0, LEFT_CENTER | wx.TOP, 5) lyt_opts1.Add(ti_enc, 0, lyt.PAD_LT, 5) lyt_opts1.Add(chk_notify, 0, LEFT_CENTER | lyt.PAD_LT, 5) lyt_mid = wx.GridBagSizer() lyt_mid.SetCols(4) lyt_mid.AddGrowableCol(1) lyt_mid.AddGrowableCol(3) # Row 1 row = 0 lyt_mid.Add(txt_filename, (row, 0), flag=LEFT_CENTER) lyt_mid.Add(ti_filename, (row, 1), flag=wx.EXPAND | wx.LEFT, border=5) lyt_mid.Add(chk_filename, (row, 2), span=(1, 2), flag=LEFT_CENTER | wx.LEFT, border=5) # Row 2 row += 1 lyt_mid.Add(txt_name, (row, 0), flag=LEFT_CENTER | wx.TOP, border=5) lyt_mid.Add(ti_name, (row, 1), flag=wx.EXPAND | lyt.PAD_LT, border=5) lyt_mid.Add(txt_exec, (row, 2), flag=LEFT_CENTER | lyt.PAD_LT, border=5) lyt_mid.Add(ti_exec, (row, 3), flag=wx.EXPAND | lyt.PAD_LT, border=5) # Row 3 row += 1 lyt_mid.Add(txt_comm, (row, 0), flag=LEFT_CENTER | wx.TOP, border=5) lyt_mid.Add(ti_comm, (row, 1), flag=wx.EXPAND | lyt.PAD_LT, border=5) lyt_mid.Add(txt_icon, (row, 2), flag=LEFT_CENTER | lyt.PAD_LT, border=5) lyt_mid.Add(ti_icon, (row, 3), flag=wx.EXPAND | lyt.PAD_LT, border=5) # Row 4 row += 1 lyt_mid.Add(txt_mime, (row, 0), flag=LEFT_CENTER | wx.TOP, border=5) lyt_mid.Add(ti_mime, (row, 1), flag=wx.EXPAND | lyt.PAD_LT, border=5) lyt_bottom = wx.GridBagSizer() row = 0 lyt_bottom.Add(txt_other, (row, 0), flag=LEFT_BOTTOM) lyt_bottom.Add(txt_category, (row, 2), flag=LEFT_BOTTOM | wx.LEFT, border=5) lyt_bottom.Add(ti_category, (row, 3), flag=LEFT_BOTTOM | wx.LEFT, border=5) lyt_bottom.Add(btn_catadd, (row, 4), flag=RIGHT_BOTTOM) lyt_bottom.Add(btn_catdel, (row, 5), flag=RIGHT_BOTTOM) lyt_bottom.Add(btn_catclr, (row, 6), flag=RIGHT_BOTTOM) row += 1 lyt_bottom.Add(ti_other, (row, 0), (1, 2), wx.EXPAND) lyt_bottom.Add(lst_categories, (row, 2), (1, 5), wx.EXPAND | wx.LEFT, 5) lyt_bottom.AddGrowableRow(1) lyt_bottom.AddGrowableCol(1) lyt_bottom.AddGrowableCol(4) # --- Page 5 Sizer --- # lyt_main = BoxSizer(wx.VERTICAL) lyt_main.AddSpacer(5) lyt_main.Add(lyt_top, 0, wx.EXPAND | lyt.PAD_LR, 5) lyt_main.Add(lyt_opts1, 0, wx.EXPAND | lyt.PAD_LRT, 5) lyt_main.Add(lyt_mid, 0, wx.EXPAND | lyt.PAD_LRT, 5) lyt_main.Add(lyt_bottom, 1, wx.EXPAND | wx.ALL, 5) self.SetAutoLayout(True) self.SetSizer(lyt_main) self.Layout()
def __init__(self, parent): WizardPage.__init__(self, parent, pgid.CONTROL) # Bypass checking this page for build # This is mandatory & done manually self.prebuild_check = False self.SetScrollbars(0, 20, 0, 0) pnl_bg = wx.Panel(self) # Buttons to open, save, & preview control file btn_open = CreateButton(pnl_bg, btnid.BROWSE, GT(u'Browse'), u'browse', name=u'btn browse') btn_save = CreateButton(pnl_bg, btnid.SAVE, GT(u'Save'), u'save', name=u'btn save') btn_preview = CreateButton(pnl_bg, btnid.PREVIEW, GT(u'Preview'), u'preview', name=u'btn preview') # *** Required fields *** # pnl_require = BorderedPanel(pnl_bg) txt_package = wx.StaticText(pnl_require, label=GT(u'Package'), name=u'package') txt_package.req = True ti_package = TextAreaESS(pnl_require, inputid.PACKAGE, name=txt_package.Name) ti_package.req = True txt_version = wx.StaticText(pnl_require, label=GT(u'Version'), name=u'version') txt_version.req = True ti_version = TextAreaESS(pnl_require, inputid.VERSION, name=txt_version.Name) ti_version.req = True txt_maintainer = wx.StaticText(pnl_require, label=GT(u'Maintainer'), name=u'maintainer') txt_maintainer.req = True ti_maintainer = TextAreaESS(pnl_require, inputid.MAINTAINER, name=txt_maintainer.Name) ti_maintainer.req = True txt_email = wx.StaticText(pnl_require, label=GT(u'Email'), name=u'email') txt_email.req = True ti_email = TextAreaESS(pnl_require, inputid.EMAIL, name=txt_email.Name) ti_email.req = True opts_arch = ( u'all', u'alpha', u'amd64', u'arm', u'arm64', u'armeb', u'armel', u'armhf', u'avr32', u'hppa', u'i386', u'ia64', u'lpia', u'm32r', u'm68k', u'mips', u'mipsel', u'powerpc', u'powerpcspe', u'ppc64', u's390', u's390x', u'sh3', u'sh3eb', u'sh4', u'sh4eb', u'sparc', u'sparc64', ) txt_arch = wx.StaticText(pnl_require, label=GT(u'Architecture'), name=u'architecture') sel_arch = ChoiceESS(pnl_require, inputid.ARCH, choices=opts_arch, name=txt_arch.Name) sel_arch.Default = 0 sel_arch.SetSelection(sel_arch.Default) # *** Recommended fields *** # pnl_recommend = BorderedPanel(pnl_bg) opts_section = ( u'admin', u'cli-mono', u'comm', u'database', u'devel', u'debug', u'doc', u'editors', u'electronics', u'embedded', u'fonts', u'games', u'gnome', u'graphics', u'gnu-r', u'gnustep', u'hamradio', u'haskell', u'httpd', u'interpreters', u'java', u'kde', u'kernel', u'libs', u'libdevel', u'lisp', u'localization', u'mail', u'math', u'metapackages', u'misc', u'net', u'news', u'ocaml', u'oldlibs', u'otherosfs', u'perl', u'php', u'python', u'ruby', u'science', u'shells', u'sound', u'tex', u'text', u'utils', u'vcs', u'video', u'web', u'x11', u'xfce', u'zope', ) txt_section = wx.StaticText(pnl_recommend, label=GT(u'Section'), name=u'section') ti_section = ComboBoxESS(pnl_recommend, choices=opts_section, name=txt_section.Name) opts_priority = ( u'optional', u'standard', u'important', u'required', u'extra', ) txt_priority = wx.StaticText(pnl_recommend, label=GT(u'Priority'), name=u'priority') sel_priority = ChoiceESS(pnl_recommend, choices=opts_priority, name=txt_priority.Name) sel_priority.Default = 0 sel_priority.SetSelection(sel_priority.Default) txt_synopsis = wx.StaticText(pnl_recommend, label=GT(u'Short Description'), name=u'synopsis') ti_synopsis = TextAreaESS(pnl_recommend, name=txt_synopsis.Name) txt_description = wx.StaticText(pnl_recommend, label=GT(u'Long Description'), name=u'description') self.ti_description = TextAreaPanelESS(pnl_recommend, name=txt_description.Name) # *** Optional fields *** # pnl_option = BorderedPanel(pnl_bg) txt_source = wx.StaticText(pnl_option, label=GT(u'Source'), name=u'source') ti_source = TextAreaESS(pnl_option, name=txt_source.Name) txt_homepage = wx.StaticText(pnl_option, label=GT(u'Homepage'), name=u'homepage') ti_homepage = TextAreaESS(pnl_option, name=txt_homepage.Name) txt_essential = wx.StaticText(pnl_option, label=GT(u'Essential'), name=u'essential') self.chk_essential = CheckBoxESS(pnl_option, name=u'essential') self.chk_essential.Default = False self.grp_input = ( ti_package, ti_version, ti_maintainer, # Maintainer must be listed before email ti_email, ti_section, ti_source, ti_homepage, ti_synopsis, self.ti_description, ) self.grp_select = ( sel_arch, sel_priority, ) SetPageToolTips(self) # *** Event Handling *** # btn_open.Bind(wx.EVT_BUTTON, self.OnBrowse) btn_save.Bind(wx.EVT_BUTTON, self.OnSave) btn_preview.Bind(wx.EVT_BUTTON, self.OnPreviewControl) # *** Layout *** # LEFT_BOTTOM = lyt.ALGN_LB RIGHT_CENTER = wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL | wx.RIGHT # Buttons lyt_buttons = BoxSizer(wx.HORIZONTAL) lyt_buttons.Add(btn_open, 0) lyt_buttons.Add(btn_save, 0) lyt_buttons.Add(btn_preview, 0) # Required fields lyt_require = wx.FlexGridSizer(0, 4, 5, 5) lyt_require.AddGrowableCol(1) lyt_require.AddGrowableCol(3) lyt_require.AddMany(( (txt_package, 0, RIGHT_CENTER | lyt.PAD_LT, 5), (ti_package, 0, wx.EXPAND | wx.TOP, 5), (txt_version, 0, RIGHT_CENTER | wx.TOP, 5), (ti_version, 0, wx.EXPAND | wx.TOP | wx.RIGHT, 5), (txt_maintainer, 0, RIGHT_CENTER | wx.LEFT, 5), (ti_maintainer, 0, wx.EXPAND), (txt_email, 0, RIGHT_CENTER, 5), (ti_email, 0, wx.EXPAND | wx.RIGHT, 5), (txt_arch, 0, RIGHT_CENTER | lyt.PAD_LB, 5), (sel_arch, 0, wx.BOTTOM, 5), )) pnl_require.SetSizer(lyt_require) pnl_require.SetAutoLayout(True) pnl_require.Layout() # Recommended fields lyt_recommend = wx.GridBagSizer() lyt_recommend.SetCols(4) lyt_recommend.AddGrowableCol(1) lyt_recommend.AddGrowableRow(3) lyt_recommend.Add(txt_section, (0, 2), flag=RIGHT_CENTER | lyt.PAD_TB, border=5) lyt_recommend.Add(ti_section, (0, 3), flag=wx.EXPAND | lyt.PAD_RTB, border=5) lyt_recommend.Add(txt_synopsis, (0, 0), (1, 2), LEFT_BOTTOM | wx.LEFT, 5) lyt_recommend.Add(ti_synopsis, (1, 0), (1, 2), wx.EXPAND | lyt.PAD_LR, 5) lyt_recommend.Add(txt_priority, (1, 2), flag=RIGHT_CENTER, border=5) lyt_recommend.Add(sel_priority, (1, 3), flag=wx.EXPAND | wx.RIGHT, border=5) lyt_recommend.Add(txt_description, (2, 0), (1, 2), LEFT_BOTTOM | lyt.PAD_LT, 5) lyt_recommend.Add(self.ti_description, (3, 0), (1, 4), wx.EXPAND | lyt.PAD_LR | wx.BOTTOM, 5) pnl_recommend.SetSizer(lyt_recommend) pnl_recommend.SetAutoLayout(True) pnl_recommend.Layout() # Optional fields lyt_option = wx.FlexGridSizer(0, 4, 5, 5) lyt_option.AddGrowableCol(1) lyt_option.AddGrowableCol(3) lyt_option.AddSpacer(5) lyt_option.AddSpacer(5) lyt_option.AddSpacer(5) lyt_option.AddSpacer(5) lyt_option.AddMany(( (txt_source, 0, RIGHT_CENTER | wx.LEFT, 5), (ti_source, 0, wx.EXPAND), (txt_homepage, 0, RIGHT_CENTER, 5), (ti_homepage, 0, wx.EXPAND | wx.RIGHT, 5), (txt_essential, 0, RIGHT_CENTER | lyt.PAD_LB, 5), (self.chk_essential, 0, wx.BOTTOM, 5), )) pnl_option.SetSizer(lyt_option) pnl_option.SetAutoLayout(True) pnl_option.Layout() # Main background panel sizer # FIXME: Is background panel (pnl_bg) necessary lyt_bg = BoxSizer(wx.VERTICAL) lyt_bg.Add(lyt_buttons, 0, wx.ALIGN_RIGHT | wx.BOTTOM, 5) lyt_bg.Add(wx.StaticText(pnl_bg, label=GT(u'Required')), 0) lyt_bg.Add(pnl_require, 0, wx.EXPAND) lyt_bg.Add(wx.StaticText(pnl_bg, label=GT(u'Recommended')), 0, wx.TOP, 5) lyt_bg.Add(pnl_recommend, 1, wx.EXPAND) lyt_bg.Add(wx.StaticText(pnl_bg, label=GT(u'Optional')), 0, wx.TOP, 5) lyt_bg.Add(pnl_option, 0, wx.EXPAND) pnl_bg.SetAutoLayout(True) pnl_bg.SetSizer(lyt_bg) pnl_bg.Layout() # Page's main sizer lyt_main = BoxSizer(wx.VERTICAL) lyt_main.AddSpacer(5) lyt_main.Add(pnl_bg, 1, wx.EXPAND | lyt.PAD_LR | wx.BOTTOM, 5) self.SetAutoLayout(True) self.SetSizer(lyt_main) self.Layout()
class Page(WizardPage): ## Constructor # # \param parent # Parent <b><i>wx.Window</i></b> instance def __init__(self, parent): WizardPage.__init__(self, parent, pgid.CHANGELOG) txt_package = wx.StaticText(self, label=GT(u'Package'), name=u'package') self.ti_package = TextArea(self, inputid.PACKAGE, name=txt_package.Name) txt_version = wx.StaticText(self, label=GT(u'Version'), name=u'version') self.ti_version = TextArea(self, inputid.VERSION, name=txt_version.Name) dist_names = GetOSDistNames() txt_dist = wx.StaticText(self, label=GT(u'Distribution'), name=u'dist') if dist_names: self.ti_dist = ComboBox(self, inputid.DIST, choices=dist_names, name=txt_dist.Name) # Use regular text input if could not retrieve distribution names list else: self.ti_dist = TextArea(self, inputid.DIST, name=txt_dist.Name) opts_urgency = ( u'low', u'medium', u'high', u'emergency', ) txt_urgency = wx.StaticText(self, label=GT(u'Urgency'), name=u'urgency') self.sel_urgency = Choice(self, selid.URGENCY, choices=opts_urgency, name=txt_urgency.Name) txt_maintainer = wx.StaticText(self, label=GT(u'Maintainer'), name=u'maintainer') self.ti_maintainer = TextArea(self, inputid.MAINTAINER, name=txt_maintainer.Name) txt_email = wx.StaticText(self, label=GT(u'Email'), name=u'email') self.ti_email = TextArea(self, inputid.EMAIL, name=txt_email.Name) btn_import = CreateButton(self, btnid.IMPORT, GT(u'Import'), u'import', name=u'btn import') txt_import = wx.StaticText( self, label=GT(u'Import information from Control page')) # Changes input self.ti_changes = TextAreaPanel(self, size=(20, 150), name=u'changes') # *** Target installation directory # FIXME: Should this be set by config or project file??? self.pnl_target = FileOTarget(self, u'/usr/share/doc/<package>', name=u'target default', defaultType=CheckBoxESS, customType=PathCtrlESS, pathIds=( chkid.TARGET, inputid.TARGET, )) self.btn_add = CreateButton(self, btnid.ADD, GT(u'Add'), u'add', name=u'btn add') txt_add = wx.StaticText(self, label=GT(u'Insert new changelog entry')) self.chk_indentation = CheckBox(self, label=GT(u'Preserve indentation'), name=u'indent') self.dsp_changes = TextAreaPanelESS(self, inputid.CHANGES, monospace=True, name=u'log') self.dsp_changes.EnableDropTarget() SetPageToolTips(self) # *** Event Handling *** # btn_import.Bind(wx.EVT_BUTTON, self.OnImportFromControl) self.btn_add.Bind(wx.EVT_BUTTON, self.AddInfo) # *** Layout *** # LEFT_BOTTOM = lyt.ALGN_LB LEFT_CENTER = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL RIGHT_CENTER = wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL lyt_info = wx.FlexGridSizer(2, 6) lyt_info.AddGrowableCol(1) lyt_info.AddGrowableCol(3) lyt_info.AddGrowableCol(5) lyt_info.AddMany( ((txt_package, 0, RIGHT_CENTER | wx.RIGHT, 5), (self.ti_package, 1, wx.EXPAND | wx.BOTTOM | wx.RIGHT, 5), (txt_version, 0, RIGHT_CENTER | wx.RIGHT, 5), (self.ti_version, 1, wx.EXPAND | wx.BOTTOM | wx.RIGHT, 5), (txt_dist, 0, RIGHT_CENTER | wx.RIGHT, 5), (self.ti_dist, 1, wx.EXPAND | wx.BOTTOM, 5), (txt_urgency, 0, RIGHT_CENTER | wx.RIGHT, 5), (self.sel_urgency, 1, wx.RIGHT, 5), (txt_maintainer, 0, RIGHT_CENTER | wx.RIGHT, 5), (self.ti_maintainer, 1, wx.EXPAND | wx.RIGHT, 5), (txt_email, 0, RIGHT_CENTER | wx.RIGHT, 5), (self.ti_email, 1, wx.EXPAND))) lyt_details = wx.GridBagSizer() lyt_details.SetCols(3) lyt_details.AddGrowableRow(2) lyt_details.AddGrowableCol(1) lyt_details.Add(btn_import, (0, 0)) lyt_details.Add(txt_import, (0, 1), flag=LEFT_CENTER) lyt_details.Add(wx.StaticText(self, label=GT(u'Changes')), (1, 0), flag=LEFT_BOTTOM) lyt_details.Add(wx.StaticText(self, label=GT(u'Target')), (1, 2), flag=LEFT_BOTTOM) lyt_details.Add(self.ti_changes, (2, 0), (1, 2), wx.EXPAND | wx.RIGHT, 5) lyt_details.Add(self.pnl_target, (2, 2)) lyt_details.Add(self.btn_add, (3, 0), (2, 1)) lyt_details.Add(txt_add, (3, 1), flag=LEFT_BOTTOM | wx.TOP, border=5) lyt_details.Add(self.chk_indentation, (4, 1), flag=LEFT_BOTTOM) lyt_main = BoxSizer(wx.VERTICAL) lyt_main.AddSpacer(10) lyt_main.Add(lyt_info, 0, wx.EXPAND | lyt.PAD_LR, 5) lyt_main.AddSpacer(10) lyt_main.Add(lyt_details, 1, wx.EXPAND | lyt.PAD_LR, 5) lyt_main.Add(wx.StaticText(self, label=u'Changelog Output'), 0, LEFT_BOTTOM | lyt.PAD_LT, 5) lyt_main.Add(self.dsp_changes, 1, wx.EXPAND | lyt.PAD_LR | wx.BOTTOM, 5) self.SetAutoLayout(True) self.SetSizer(lyt_main) self.Layout() ## Formats input text from 'changes' field for new entry in changelog def AddInfo(self, event=None): new_changes = self.ti_changes.GetValue() if TextIsEmpty(new_changes): DetailedMessageDialog( GetMainWindow(), GT(u'Warning'), ICON_WARNING, GT(u'"Changes" section is empty')).ShowModal() self.ti_changes.SetInsertionPointEnd() self.ti_changes.SetFocus() return package = self.ti_package.GetValue() version = self.ti_version.GetValue() dist = self.ti_dist.GetValue() urgency = self.sel_urgency.GetStringSelection() maintainer = self.ti_maintainer.GetValue() email = self.ti_email.GetValue() new_changes = FormatChangelog(new_changes, package, version, dist, urgency, maintainer, email, self.chk_indentation.GetValue()) # Clean up leading & trailing whitespace in old changes old_changes = self.dsp_changes.GetValue().strip(u' \t\n\r') # Only append newlines if log isn't already empty if not TextIsEmpty(old_changes): new_changes = u'{}\n\n\n{}'.format(new_changes, old_changes) # Add empty line to end of log if not new_changes.endswith(u'\n'): new_changes = u'{}\n'.format(new_changes) self.dsp_changes.SetValue(new_changes) # Clear "Changes" text self.ti_changes.Clear() self.ti_changes.SetFocus() ## Retrieves changelog text # # The output is a text file that uses sections defined by braces ([, ]) # # \return # <b><i>tuple(str, str)</i></b>: Filename & formatted string of changelog target & body def Get(self): target = self.pnl_target.GetPath() if target == self.pnl_target.GetDefaultPath(): target = u'STANDARD' return (target, self.GetChangelog()) ## Retrieves plain text of the changelog field # # \return # Formatted changelog text def GetChangelog(self): return self.dsp_changes.GetValue() ## TODO: Doxygen def GetSaveData(self): target = self.pnl_target.GetPath() if target == self.pnl_target.GetDefaultPath(): target = u'<<DEST>>DEFAULT<</DEST>>' else: target = u'<<DEST>>{}<</DEST>>'.format(target) return u'\n'.join((u'<<CHANGELOG>>', target, self.dsp_changes.GetValue(), u'<</CHANGELOG>>')) ## Checks the page's fields for exporting # # \return # <b><i>False</i></b> if page cannot be exported def IsOkay(self): return not TextIsEmpty(self.dsp_changes.GetValue()) ## Imports select field values from the 'Control' page def OnImportFromControl(self, event=None): fields = ( (self.ti_package, inputid.PACKAGE), (self.ti_version, inputid.VERSION), (self.ti_maintainer, inputid.MAINTAINER), (self.ti_email, inputid.EMAIL), ) for F, FID in fields: field_value = GetFieldValue(pgid.CONTROL, FID) if isinstance(field_value, ErrorTuple): err_msg1 = GT( u'Got error when attempting to retrieve field value') err_msg2 = u'\tError code: {}\n\tError message: {}'.format( field_value.GetCode(), field_value.GetString()) Logger.Error(__name__, u'{}:\n{}'.format(err_msg1, err_msg2)) continue if not TextIsEmpty(field_value): F.SetValue(field_value) ## Sets values of page's fields with given input # # \param data # Text to parse for values def Set(self, data): changelog = data.split(u'\n') target = changelog[0].split(u'<<DEST>>')[1].split(u'<</DEST>>')[0] if target == u'DEFAULT': if not self.pnl_target.UsingDefault(): self.pnl_target.Reset() else: self.pnl_target.SetPath(target) self.dsp_changes.SetValue(u'\n'.join(changelog[1:]))
def __init__(self, parent): WizardPage.__init__(self, parent, pgid.DEPENDS) ## Override default label self.Label = GT(u'Dependencies and Conflicts') # Bypass checking this page for build self.prebuild_check = False # Buttons to open, save, & preview control file self.btn_open = CreateButton(self, btnid.BROWSE, GT(u'Browse'), u'browse', name=u'btn browse') self.btn_save = CreateButton(self, btnid.SAVE, GT(u'Save'), u'save', name=u'btn save') self.btn_preview = CreateButton(self, btnid.PREVIEW, GT(u'Preview'), u'preview', name=u'btn preview') txt_package = wx.StaticText(self, label=GT(u'Dependency/Conflict Package Name'), name=u'package') txt_version = wx.StaticText(self, label=GT(u'Version'), name=u'version') self.ti_package = TextArea(self, size=(300,25), name=u'package') opts_operator = ( u'>=', u'<=', u'=', u'>>', u'<<', ) self.sel_operator = Choice(self, choices=opts_operator, name=u'operator') self.ti_version = TextArea(self, name=u'version') self.ti_package.SetSize((100,50)) pnl_categories = BorderedPanel(self) self.DefaultCategory = u'Depends' rb_dep = wx.RadioButton(pnl_categories, label=GT(u'Depends'), name=self.DefaultCategory, style=wx.RB_GROUP) rb_pre = wx.RadioButton(pnl_categories, label=GT(u'Pre-Depends'), name=u'Pre-Depends') rb_rec = wx.RadioButton(pnl_categories, label=GT(u'Recommends'), name=u'Recommends') rb_sug = wx.RadioButton(pnl_categories, label=GT(u'Suggests'), name=u'Suggests') rb_enh = wx.RadioButton(pnl_categories, label=GT(u'Enhances'), name=u'Enhances') rb_con = wx.RadioButton(pnl_categories, label=GT(u'Conflicts'), name=u'Conflicts') rb_rep = wx.RadioButton(pnl_categories, label=GT(u'Replaces'), name=u'Replaces') rb_break = wx.RadioButton(pnl_categories, label=GT(u'Breaks'), name=u'Breaks') self.categories = ( rb_dep, rb_pre, rb_rec, rb_sug, rb_enh, rb_con, rb_rep, rb_break, ) # Buttons to add and remove dependencies from the list btn_add = CreateButton(self, btnid.ADD) btn_append = CreateButton(self, btnid.APPEND) btn_remove = CreateButton(self, btnid.REMOVE) btn_clear = CreateButton(self, btnid.CLEAR) # ----- List self.lst_deps = ListCtrlESS(self, inputid.LIST, name=u'list') self.lst_deps.SetSingleStyle(wx.LC_REPORT) self.lst_deps.InsertColumn(0, GT(u'Category'), width=150) self.lst_deps.InsertColumn(1, GT(u'Package(s)')) # wx 3.0 compatibility if wx.MAJOR_VERSION < 3: self.lst_deps.SetColumnWidth(100, wx.LIST_AUTOSIZE) SetPageToolTips(self) # *** Event Handling *** # wx.EVT_KEY_DOWN(self.ti_package, self.SetDepends) wx.EVT_KEY_DOWN(self.ti_version, self.SetDepends) btn_add.Bind(wx.EVT_BUTTON, self.SetDepends) btn_append.Bind(wx.EVT_BUTTON, self.SetDepends) btn_remove.Bind(wx.EVT_BUTTON, self.SetDepends) btn_clear.Bind(wx.EVT_BUTTON, self.SetDepends) wx.EVT_KEY_DOWN(self.lst_deps, self.SetDepends) # *** Layout *** # LEFT_BOTTOM = lyt.ALGN_LB lyt_top = wx.GridBagSizer() lyt_top.SetCols(6) lyt_top.AddGrowableCol(3) # Row 1 lyt_top.Add(txt_package, (1, 0), flag=LEFT_BOTTOM) lyt_top.Add(txt_version, (1, 2), flag=LEFT_BOTTOM) lyt_top.Add(self.btn_open, (0, 3), (4, 1), wx.ALIGN_RIGHT) lyt_top.Add(self.btn_save, (0, 4), (4, 1)) lyt_top.Add(self.btn_preview, (0, 5), (4, 1)) # Row 2 lyt_top.Add(self.ti_package, (2, 0), flag=wx.ALIGN_CENTER_VERTICAL) lyt_top.Add(self.sel_operator, (2, 1), flag=wx.ALIGN_CENTER_VERTICAL) lyt_top.Add(self.ti_version, (2, 2), flag=wx.ALIGN_CENTER_VERTICAL) lyt_categories = wx.GridSizer(4, 2, 5, 5) for C in self.categories: lyt_categories.Add(C, 0) pnl_categories.SetAutoLayout(True) pnl_categories.SetSizer(lyt_categories) pnl_categories.Layout() lyt_buttons = BoxSizer(wx.HORIZONTAL) lyt_buttons.AddMany(( (btn_add, 0, wx.ALIGN_CENTER_VERTICAL), (btn_append, 0, wx.ALIGN_CENTER_VERTICAL), (btn_remove, 0, wx.ALIGN_CENTER_VERTICAL), (btn_clear, 0, wx.ALIGN_CENTER_VERTICAL), )) lyt_mid = wx.GridBagSizer() lyt_mid.SetCols(2) lyt_mid.Add(wx.StaticText(self, label=u'Categories'), (0, 0), (1, 1), LEFT_BOTTOM) lyt_mid.Add(pnl_categories, (1, 0), flag=wx.RIGHT, border=5) lyt_mid.Add(lyt_buttons, (1, 1), flag=wx.ALIGN_BOTTOM) lyt_list = BoxSizer(wx.HORIZONTAL) lyt_list.Add(self.lst_deps, 1, wx.EXPAND) lyt_main = BoxSizer(wx.VERTICAL) # Spacer is less on this page because text is aligned to bottom lyt_main.AddSpacer(5) lyt_main.Add(lyt_top, 0, wx.EXPAND|lyt.PAD_LR, 5) lyt_main.Add(lyt_mid, 0, lyt.PAD_LR, 5) lyt_main.Add(lyt_list, 1, wx.EXPAND|wx.ALL, 5) self.SetAutoLayout(True) self.SetSizer(lyt_main) self.Layout()
class Page(WizardPage): ## Constructor # # \param parent # Parent <b><i>wx.Window</i></b> instance def __init__(self, parent): WizardPage.__init__(self, parent, pgid.DEPENDS) ## Override default label self.Label = GT(u'Dependencies and Conflicts') # Bypass checking this page for build self.prebuild_check = False # Buttons to open, save, & preview control file self.btn_open = CreateButton(self, btnid.BROWSE, GT(u'Browse'), u'browse', name=u'btn browse') self.btn_save = CreateButton(self, btnid.SAVE, GT(u'Save'), u'save', name=u'btn save') self.btn_preview = CreateButton(self, btnid.PREVIEW, GT(u'Preview'), u'preview', name=u'btn preview') txt_package = wx.StaticText(self, label=GT(u'Dependency/Conflict Package Name'), name=u'package') txt_version = wx.StaticText(self, label=GT(u'Version'), name=u'version') self.ti_package = TextArea(self, size=(300,25), name=u'package') opts_operator = ( u'>=', u'<=', u'=', u'>>', u'<<', ) self.sel_operator = Choice(self, choices=opts_operator, name=u'operator') self.ti_version = TextArea(self, name=u'version') self.ti_package.SetSize((100,50)) pnl_categories = BorderedPanel(self) self.DefaultCategory = u'Depends' rb_dep = wx.RadioButton(pnl_categories, label=GT(u'Depends'), name=self.DefaultCategory, style=wx.RB_GROUP) rb_pre = wx.RadioButton(pnl_categories, label=GT(u'Pre-Depends'), name=u'Pre-Depends') rb_rec = wx.RadioButton(pnl_categories, label=GT(u'Recommends'), name=u'Recommends') rb_sug = wx.RadioButton(pnl_categories, label=GT(u'Suggests'), name=u'Suggests') rb_enh = wx.RadioButton(pnl_categories, label=GT(u'Enhances'), name=u'Enhances') rb_con = wx.RadioButton(pnl_categories, label=GT(u'Conflicts'), name=u'Conflicts') rb_rep = wx.RadioButton(pnl_categories, label=GT(u'Replaces'), name=u'Replaces') rb_break = wx.RadioButton(pnl_categories, label=GT(u'Breaks'), name=u'Breaks') self.categories = ( rb_dep, rb_pre, rb_rec, rb_sug, rb_enh, rb_con, rb_rep, rb_break, ) # Buttons to add and remove dependencies from the list btn_add = CreateButton(self, btnid.ADD) btn_append = CreateButton(self, btnid.APPEND) btn_remove = CreateButton(self, btnid.REMOVE) btn_clear = CreateButton(self, btnid.CLEAR) # ----- List self.lst_deps = ListCtrlESS(self, inputid.LIST, name=u'list') self.lst_deps.SetSingleStyle(wx.LC_REPORT) self.lst_deps.InsertColumn(0, GT(u'Category'), width=150) self.lst_deps.InsertColumn(1, GT(u'Package(s)')) # wx 3.0 compatibility if wx.MAJOR_VERSION < 3: self.lst_deps.SetColumnWidth(100, wx.LIST_AUTOSIZE) SetPageToolTips(self) # *** Event Handling *** # wx.EVT_KEY_DOWN(self.ti_package, self.SetDepends) wx.EVT_KEY_DOWN(self.ti_version, self.SetDepends) btn_add.Bind(wx.EVT_BUTTON, self.SetDepends) btn_append.Bind(wx.EVT_BUTTON, self.SetDepends) btn_remove.Bind(wx.EVT_BUTTON, self.SetDepends) btn_clear.Bind(wx.EVT_BUTTON, self.SetDepends) wx.EVT_KEY_DOWN(self.lst_deps, self.SetDepends) # *** Layout *** # LEFT_BOTTOM = lyt.ALGN_LB lyt_top = wx.GridBagSizer() lyt_top.SetCols(6) lyt_top.AddGrowableCol(3) # Row 1 lyt_top.Add(txt_package, (1, 0), flag=LEFT_BOTTOM) lyt_top.Add(txt_version, (1, 2), flag=LEFT_BOTTOM) lyt_top.Add(self.btn_open, (0, 3), (4, 1), wx.ALIGN_RIGHT) lyt_top.Add(self.btn_save, (0, 4), (4, 1)) lyt_top.Add(self.btn_preview, (0, 5), (4, 1)) # Row 2 lyt_top.Add(self.ti_package, (2, 0), flag=wx.ALIGN_CENTER_VERTICAL) lyt_top.Add(self.sel_operator, (2, 1), flag=wx.ALIGN_CENTER_VERTICAL) lyt_top.Add(self.ti_version, (2, 2), flag=wx.ALIGN_CENTER_VERTICAL) lyt_categories = wx.GridSizer(4, 2, 5, 5) for C in self.categories: lyt_categories.Add(C, 0) pnl_categories.SetAutoLayout(True) pnl_categories.SetSizer(lyt_categories) pnl_categories.Layout() lyt_buttons = BoxSizer(wx.HORIZONTAL) lyt_buttons.AddMany(( (btn_add, 0, wx.ALIGN_CENTER_VERTICAL), (btn_append, 0, wx.ALIGN_CENTER_VERTICAL), (btn_remove, 0, wx.ALIGN_CENTER_VERTICAL), (btn_clear, 0, wx.ALIGN_CENTER_VERTICAL), )) lyt_mid = wx.GridBagSizer() lyt_mid.SetCols(2) lyt_mid.Add(wx.StaticText(self, label=u'Categories'), (0, 0), (1, 1), LEFT_BOTTOM) lyt_mid.Add(pnl_categories, (1, 0), flag=wx.RIGHT, border=5) lyt_mid.Add(lyt_buttons, (1, 1), flag=wx.ALIGN_BOTTOM) lyt_list = BoxSizer(wx.HORIZONTAL) lyt_list.Add(self.lst_deps, 1, wx.EXPAND) lyt_main = BoxSizer(wx.VERTICAL) # Spacer is less on this page because text is aligned to bottom lyt_main.AddSpacer(5) lyt_main.Add(lyt_top, 0, wx.EXPAND|lyt.PAD_LR, 5) lyt_main.Add(lyt_mid, 0, lyt.PAD_LR, 5) lyt_main.Add(lyt_list, 1, wx.EXPAND|wx.ALL, 5) self.SetAutoLayout(True) self.SetSizer(lyt_main) self.Layout() ## Add a category & dependency to end of list # # \param category # Category label # \param value # Dependency value def AppendDependency(self, category, value): self.lst_deps.AppendStringItem((category, value)) ## Retrieves the default category to use def GetDefaultCategory(self): return self.DefaultCategory ## Reads & parses page data from a formatted text file # # \param filename # File path to open # \see wiz.wizard.WizardPage.ImportFromFile def ImportFromFile(self, d_type, d_string): Logger.Debug(__name__, GT(u'Importing {}: {}'.format(d_type, d_string))) values = d_string.split(u', ') for V in values: self.lst_deps.InsertStringItem(0, d_type) self.lst_deps.SetStringItem(0, 1, V) ## \see wiz.wizard.WizardPage.InitPage def InitPage(self): control_page = GetPage(pgid.CONTROL) self.btn_open.Bind(wx.EVT_BUTTON, control_page.OnBrowse) self.btn_save.Bind(wx.EVT_BUTTON, control_page.OnSave) self.btn_preview.Bind(wx.EVT_BUTTON, control_page.OnPreviewControl) return True ## Resets all fields on page to default values def Reset(self): for C in self.categories: if C.GetName() == self.DefaultCategory: C.SetValue(True) break self.ti_package.Clear() self.sel_operator.Reset() self.ti_version.Clear() self.lst_deps.DeleteAllItems() ## Adds/Appends/Removes dependency to list def SetDepends(self, event=None): try: key_id = event.GetKeyCode() except AttributeError: key_id = event.GetEventObject().GetId() addname = self.ti_package.GetValue() oper = self.sel_operator.GetStringSelection() ver = self.ti_version.GetValue() addver = u'({}{})'.format(oper, ver) if key_id in (btnid.ADD, wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER): if TextIsEmpty(addname): return category = self.GetDefaultCategory() for C in self.categories: if C.GetValue(): category = C.GetName() break if TextIsEmpty(ver): self.AppendDependency(category, addname) else: self.AppendDependency(category, u'{} {}'.format(addname, addver)) elif key_id == btnid.APPEND: selected_count = self.lst_deps.GetSelectedItemCount() Logger.Debug(__name__, u'Appending to {} items'.format(selected_count)) if not TextIsEmpty(addname) and self.lst_deps.GetItemCount() and selected_count: selected_rows = self.lst_deps.GetSelectedIndexes() if DebugEnabled(): Logger.Debug(__name__, u'Selected rows:') for R in selected_rows: print(u'\t{}'.format(R)) for listrow in selected_rows: Logger.Debug(__name__, u'Setting list row: {}'.format(listrow)) # Get item from second column colitem = self.lst_deps.GetItem(listrow, 1) # Get the text from that item prev_text = colitem.GetText() if not TextIsEmpty(ver): new_text = u'{} | {} {}'.format(prev_text, addname, addver) else: new_text = u'{} | {}'.format(prev_text, addname) Logger.Debug(__name__, u'Appended item: {}'.format(new_text)) self.lst_deps.SetStringItem(listrow, 1, new_text) elif key_id in (btnid.REMOVE, wx.WXK_DELETE): self.lst_deps.RemoveSelected() elif key_id == btnid.CLEAR: if self.lst_deps.GetItemCount(): if ConfirmationDialog(GetMainWindow(), GT(u'Confirm'), GT(u'Clear all dependencies?')).ShowModal() in (wx.ID_OK, wx.OK): self.lst_deps.DeleteAllItems() if event: event.Skip() ## Sets the page's fields data # # \param data # Text to parse for field values def Set(self, data): self.lst_deps.DeleteAllItems() for item in data: item_count = len(item) while item_count > 1: item_count -= 1 self.lst_deps.InsertStringItem(0, item[0]) self.lst_deps.SetStringItem(0, 1, item[item_count])
def __init__(self, parent, pageList=None): wx.Panel.__init__(self, parent, wx.ID_ANY, pageList) testing = u'alpha' in GetTestList() # List of pages available in the wizard self.Pages = [] self.PagesIds = {} # IDs for first & last pages self.ID_FIRST = None self.ID_LAST = None if testing: # Help button btn_help = CreateButton(self, btnid.HELP) btn_help.SetToolTipString(GT(u'Page help')) # A Header for the wizard pnl_title = wx.Panel(self, style=wx.RAISED_BORDER) pnl_title.SetBackgroundColour((10, 47, 162)) # Text displayed from objects "name" - object.GetName() self.txt_title = wx.StaticText(pnl_title, label=GT(u'Title')) self.txt_title.SetForegroundColour((255, 255, 255)) # font to use in the header headerfont = wx.Font(18, wx.DEFAULT, wx.NORMAL, wx.BOLD) self.txt_title.SetFont(headerfont) # Previous and Next buttons self.btn_prev = CreateButton(self, btnid.PREV) self.btn_prev.SetToolTip(TT_wiz_prev) self.btn_next = CreateButton(self, btnid.NEXT) self.btn_next.SetToolTip(TT_wiz_next) # These widgets are put into a list so that they are not automatically hidden self.permanent_children = [ pnl_title, self.btn_prev, self.btn_next, ] if testing: self.permanent_children.insert(0, btn_help) # *** Event Handling *** # if testing: btn_help.Bind(wx.EVT_BUTTON, self.OnHelpButton) self.btn_prev.Bind(wx.EVT_BUTTON, self.ChangePage) self.btn_next.Bind(wx.EVT_BUTTON, self.ChangePage) # *** Layout *** # # Position the text in the header lyt_title = wx.GridSizer(1, 1) lyt_title.Add(self.txt_title, 0, wx.ALIGN_CENTER|wx.ALIGN_CENTER_VERTICAL) pnl_title.SetSizer(lyt_title) # Button sizer includes header lyt_buttons = BoxSizer(wx.HORIZONTAL) if testing: lyt_buttons.Add(btn_help, 0, wx.LEFT, 5) lyt_buttons.AddSpacer(5) lyt_buttons.Add(pnl_title, 1, wx.EXPAND|wx.RIGHT, 5) lyt_buttons.Add(self.btn_prev) lyt_buttons.AddSpacer(5) lyt_buttons.Add(self.btn_next) lyt_buttons.AddSpacer(5) lyt_main = BoxSizer(wx.VERTICAL) lyt_main.Add(lyt_buttons, 0, wx.EXPAND) self.SetSizer(lyt_main) self.SetAutoLayout(True) self.Layout()
class Wizard(wx.Panel): ## Constructor # # \param parent # Parent <b><i>wx.Window</i></b> instance # \param pageList # <b><i>List</i></b> of wiz.wizard.WizardPage instances to initialize # wizard with def __init__(self, parent, pageList=None): wx.Panel.__init__(self, parent, wx.ID_ANY, pageList) testing = u'alpha' in GetTestList() # List of pages available in the wizard self.Pages = [] self.PagesIds = {} # IDs for first & last pages self.ID_FIRST = None self.ID_LAST = None if testing: # Help button btn_help = CreateButton(self, btnid.HELP) btn_help.SetToolTipString(GT(u'Page help')) # A Header for the wizard pnl_title = wx.Panel(self, style=wx.RAISED_BORDER) pnl_title.SetBackgroundColour((10, 47, 162)) # Text displayed from objects "name" - object.GetName() self.txt_title = wx.StaticText(pnl_title, label=GT(u'Title')) self.txt_title.SetForegroundColour((255, 255, 255)) # font to use in the header headerfont = wx.Font(18, wx.DEFAULT, wx.NORMAL, wx.BOLD) self.txt_title.SetFont(headerfont) # Previous and Next buttons self.btn_prev = CreateButton(self, btnid.PREV) self.btn_prev.SetToolTip(TT_wiz_prev) self.btn_next = CreateButton(self, btnid.NEXT) self.btn_next.SetToolTip(TT_wiz_next) # These widgets are put into a list so that they are not automatically hidden self.permanent_children = [ pnl_title, self.btn_prev, self.btn_next, ] if testing: self.permanent_children.insert(0, btn_help) # *** Event Handling *** # if testing: btn_help.Bind(wx.EVT_BUTTON, self.OnHelpButton) self.btn_prev.Bind(wx.EVT_BUTTON, self.ChangePage) self.btn_next.Bind(wx.EVT_BUTTON, self.ChangePage) # *** Layout *** # # Position the text in the header lyt_title = wx.GridSizer(1, 1) lyt_title.Add(self.txt_title, 0, wx.ALIGN_CENTER|wx.ALIGN_CENTER_VERTICAL) pnl_title.SetSizer(lyt_title) # Button sizer includes header lyt_buttons = BoxSizer(wx.HORIZONTAL) if testing: lyt_buttons.Add(btn_help, 0, wx.LEFT, 5) lyt_buttons.AddSpacer(5) lyt_buttons.Add(pnl_title, 1, wx.EXPAND|wx.RIGHT, 5) lyt_buttons.Add(self.btn_prev) lyt_buttons.AddSpacer(5) lyt_buttons.Add(self.btn_next) lyt_buttons.AddSpacer(5) lyt_main = BoxSizer(wx.VERTICAL) lyt_main.Add(lyt_buttons, 0, wx.EXPAND) self.SetSizer(lyt_main) self.SetAutoLayout(True) self.Layout() ## Add a new page to the wizard # # \param page # Must either be a wiz.wizard.WizardPage instance or the string suffix of the page's module def AddPage(self, page): err_msg = None err_det = None if not isinstance(page, WizardPage): try: pagemod = u'wizbin.{}'.format(page) page = mimport(pagemod).Page(self) except ImportError: err_msg = u'module does not exist' err_det = traceback.format_exc() lyt_main = self.GetSizer() if not err_msg: # Must already be child if not isinstance(page, WizardPage): err_msg = u'not WizardPage instance' elif page not in self.GetChildren(): err_msg = u'not child of wizard' elif page in lyt_main.GetChildWindows(): err_msg = u'page is already added to wizard' if err_msg: err_msg = u'Cannot add page, {}'.format(err_msg) if err_det: ShowErrorDialog(err_msg, err_det) else: ShowErrorDialog(err_msg) return main_window = GetMainWindow() lyt_main.Add(page, 1, wx.EXPAND) self.Pages.append(page) # Add to page menu page_menu = GetMenu(menuid.PAGE) page_menu.AppendItem( wx.MenuItem(page_menu, page.Id, page.GetTitle(), kind=wx.ITEM_RADIO)) # Bind menu event to ID wx.EVT_MENU(main_window, page.Id, main_window.OnMenuChangePage) ## Handles displaying a new page when commanded def ChangePage(self, event=None): event_id = event.GetEventObject().GetId() # Get index of currently shown page for page in self.Pages: if page.IsShown(): index = self.Pages.index(page) break if event_id == btnid.PREV: if index != 0: index -= 1 elif event_id == btnid.NEXT: if index != len(self.Pages) - 1: index += 1 page_id = self.Pages[index].GetId() # Show the indexed page self.ShowPage(page_id) GetMenu(menuid.PAGE).Check(page_id, True) ## Deletes all pages from the wizard def ClearPages(self): for page in self.Pages: self.GetSizer().Remove(page) self.Pages = [] # Re-enable the buttons if they have been disabled self.EnableNext() self.EnablePrev() ## Disables the 'next' page button when displaying the last page def DisableNext(self): self.EnableNext(False) ## Disables 'previous' page button when displaying the first page def DisablePrev(self): self.EnablePrev(False) ## Enables/Disables 'next' page button dependent on if the last # page is displayed # # \param value # Button is enabled <b><i>True</i></b>, disabled otherwise def EnableNext(self, value=True): if isinstance(value, (bool, int)): if value: self.btn_next.Enable() else: self.btn_next.Disable() else: # FIXME: Should not raise error here??? raise TypeError(u'Must be bool or int value') ## Enables/Disables 'previous' page button dependent on if the last # page is displayed # # \param value # Button is enabled <b><i>True</i></b>, disabled otherwise def EnablePrev(self, value=True): if isinstance(value, (bool, int)): if value: self.btn_prev.Enable() else: self.btn_prev.Disable() else: # FIXME: Should not raise error here??? raise TypeError(u'Must be bool or int value') ## Exports pages individually by calling wiz.wizard.WizardPage.Export # # Filename output is handled by classes inheriting WizardPage # # \param pageList # List of WizardPage instances, or page IDs, to be exported # \param outDir # Path to target directory def ExportPages(self, pageList, outDir): for P in pageList: # Support using list of IDs instead of WizardPage instances if not isinstance(P, WizardPage): P = self.GetPage(P) P.Export(outDir) ## Retrieves all current wiz.wizard.WizardPage instances # # \return # <b><i>Tuple</i></b> list of currently available wizard pages def GetAllPages(self): return tuple(self.Pages) ## Retrieves currently displayed page # # \return # wiz.wizard.WizardPage instance def GetCurrentPage(self): for page in self.Pages: if page.IsShown(): return page ## Retrieve currently displayed page's ID # # \return # <b><i>Integer</i></b> ID of page def GetCurrentPageId(self): current_page = self.GetCurrentPage() if current_page: return current_page.GetId() ## Retrieves a page by ID # # \param pageId # <b><i>Integer</i></b> ID of desired page # \return # wiz.wizard.WizardPage instance or <b><i>None</i></b> if ID not found def GetPage(self, pageId): for P in self.Pages: if P.GetId() == pageId: return P Logger.Warn(__name__, u'Page with ID {} has not been constructed'.format(pageId)) ## Retrieves the full list of page IDs # # \return # <b><i>Tuple</i></b> list of all current pages IDs def GetPagesIdList(self): page_ids = [] for P in self.Pages: page_ids.append(P.GetId()) return tuple(page_ids) ## Fills information for each page when project file is opened # # Each page imports a file by parsing the filename # # \param filesDir # Path to directory where project files have been extracted def ImportPagesInfo(self, filesDir): for PATH, DIRS, FILES in os.walk(filesDir): for F in FILES: for page in self.Pages: page_name = page_ids[page.GetId()].upper() n_index = len(page_name) if F[:n_index] == page_name: Logger.Debug(__name__, GT(u'Imported project file {} matches page {}'.format(F, page_name))) page.ImportFromFile(u'{}/{}'.format(PATH, F)) ## Initializes wizard by displaying an initial page # # \param showPage # <b><i>Integer</i></b> index of page to be shown def Initialize(self, showPage=0): if self.Pages: self.ID_FIRST = self.Pages[0].Id self.ID_LAST = self.Pages[-1].Id if not showPage: self.ShowPage(self.ID_FIRST) else: self.ShowPage(self.Pages[showPage].Id) for PAGE in self.Pages: PAGE.InitPage() self.Layout() ## Uses children wiz.wizard.WizardPage instances to set pages # # \return # Value of wiz.wizard.Wizard.SetPages def InitPages(self): pages = [] for C in self.GetChildren(): if isinstance(C, WizardPage): pages.append(C) return self.SetPages(pages) ## Handles event emitted by 'help' button # # Shows a help dialog for currently displayed page def OnHelpButton(self, event=None): label = self.GetCurrentPage().GetTitle() page_help = MarkdownDialog(self, title=GT(u'Help'), readonly=True) page_help.SetText(GT(u'Help information for page "{}"'.format(label))) ShowDialog(page_help) ## Removes a page from the wizard & memory # # \param pageId # <b><i>Integer</i></b> ID of the page to be removed def RemovePage(self, pageId): page = self.GetPage(pageId) if page in self.Pages: self.Pages.pop(self.Pages.index(page)) lyt_main = self.GetSizer() if page in lyt_main.GetChildWindows(): lyt_main.Remove(page) self.Layout() # Remove from page menu GetMenu(menuid.PAGE).Remove(pageId).Destroy() ## Resets all but greeting page # # \return # Value of wiz.wizard.Wizard.Initialize def Reset(self): for PAGE in reversed(self.Pages): if PAGE.Id != pgid.GREETING: self.RemovePage(PAGE.Id) return self.Initialize() ## Resets each page's fields to default settings # # Calls wiz.wizard.WizardPage.Reset def ResetPagesInfo(self): for page in self.Pages: page.Reset() ## Sets up the wizard for 'binary' mode # # \param startPage # <b><i>Integer</i></b> index of page to be initially displayed def SetModeBin(self, startPage=1): self.Reset() mods = [ u'control', u'depends', u'files', u'scripts', u'changelog', u'copyright', u'launchers', u'build', ] if u'alpha' in GetTestList() or DebugEnabled(): mods.insert(3, u'manuals') for M in mods: self.AddPage(M) self.Initialize(startPage) ## Sets up the wizard for 'source' mode # # FIXME: WIP def SetModeSrc(self): self.Reset() ## Organizes wiz.wizard.WizardPage instances for displaying as pages in wizard # # FIXME: Deprecated??? # # \param pages # List of pages owned by wizard to be used # \deprecated def SetPages(self, pages): self.ID_FIRST = pages[0].GetId() self.ID_LAST = pages[-1].GetId() main_window = GetMainWindow() # Make sure all pages are hidden children = self.GetChildren() for child in children: if child not in self.permanent_children: child.Hide() # Remove any current pages from the wizard self.ClearPages() if not isinstance(pages, (list, tuple)): # FIXME: Should not raise error here??? raise TypeError(u'Argument 2 of Wizard.SetPages() must be List or Tuple') for PAGE in pages: if PAGE.GetId() != pgid.GREETING: self.Pages.append(PAGE) self.PagesIds[PAGE.GetId()] = PAGE.GetName().upper() self.GetSizer().Insert(1, PAGE, 1, wx.EXPAND) page_id = PAGE.GetId() # Add pages to main menu page_menu = main_window.GetMenu(menuid.PAGE) page_menu.AppendItem( wx.MenuItem(page_menu, page_id, PAGE.GetTitle(), kind=wx.ITEM_RADIO)) # Bind menu event to ID wx.EVT_MENU(main_window, page_id, main_window.OnMenuChangePage) # Initailize functions that can only be called after all pages are constructed for PAGE in pages: PAGE.InitPage() self.ShowPage(self.ID_FIRST) self.Layout() ## Sets the text displayed in the wizard title bar # # \param title # Text to be displayed def SetTitle(self, title): self.txt_title.SetLabel(title) self.Layout() ## Sets or changes the displayed page # # Posts a 'change page' event to notify the main window # # \param pageId # globals.ident.pgid of the page to be displayed def ShowPage(self, pageId): for p in self.Pages: if p.GetId() != pageId: p.Hide() else: p.Show() self.txt_title.SetLabel(p.GetTitle()) if pageId == self.ID_FIRST: self.btn_prev.Enable(False) elif not FieldEnabled(self.btn_prev): self.btn_prev.Enable(True) if pageId == self.ID_LAST: self.btn_next.Enable(False) elif not FieldEnabled(self.btn_next): self.btn_next.Enable(True) self.Layout() wx.PostEvent(GetMainWindow(), ChangePageEvent(0))
def __init__(self, parent): WizardPage.__init__(self, parent, pgid.CHANGELOG) txt_package = wx.StaticText(self, label=GT(u'Package'), name=u'package') self.ti_package = TextArea(self, inputid.PACKAGE, name=txt_package.Name) txt_version = wx.StaticText(self, label=GT(u'Version'), name=u'version') self.ti_version = TextArea(self, inputid.VERSION, name=txt_version.Name) dist_names = GetOSDistNames() txt_dist = wx.StaticText(self, label=GT(u'Distribution'), name=u'dist') if dist_names: self.ti_dist = ComboBox(self, inputid.DIST, choices=dist_names, name=txt_dist.Name) # Use regular text input if could not retrieve distribution names list else: self.ti_dist = TextArea(self, inputid.DIST, name=txt_dist.Name) opts_urgency = ( u'low', u'medium', u'high', u'emergency', ) txt_urgency = wx.StaticText(self, label=GT(u'Urgency'), name=u'urgency') self.sel_urgency = Choice(self, selid.URGENCY, choices=opts_urgency, name=txt_urgency.Name) txt_maintainer = wx.StaticText(self, label=GT(u'Maintainer'), name=u'maintainer') self.ti_maintainer = TextArea(self, inputid.MAINTAINER, name=txt_maintainer.Name) txt_email = wx.StaticText(self, label=GT(u'Email'), name=u'email') self.ti_email = TextArea(self, inputid.EMAIL, name=txt_email.Name) btn_import = CreateButton(self, btnid.IMPORT, GT(u'Import'), u'import', name=u'btn import') txt_import = wx.StaticText( self, label=GT(u'Import information from Control page')) # Changes input self.ti_changes = TextAreaPanel(self, size=(20, 150), name=u'changes') # *** Target installation directory # FIXME: Should this be set by config or project file??? self.pnl_target = FileOTarget(self, u'/usr/share/doc/<package>', name=u'target default', defaultType=CheckBoxESS, customType=PathCtrlESS, pathIds=( chkid.TARGET, inputid.TARGET, )) self.btn_add = CreateButton(self, btnid.ADD, GT(u'Add'), u'add', name=u'btn add') txt_add = wx.StaticText(self, label=GT(u'Insert new changelog entry')) self.chk_indentation = CheckBox(self, label=GT(u'Preserve indentation'), name=u'indent') self.dsp_changes = TextAreaPanelESS(self, inputid.CHANGES, monospace=True, name=u'log') self.dsp_changes.EnableDropTarget() SetPageToolTips(self) # *** Event Handling *** # btn_import.Bind(wx.EVT_BUTTON, self.OnImportFromControl) self.btn_add.Bind(wx.EVT_BUTTON, self.AddInfo) # *** Layout *** # LEFT_BOTTOM = lyt.ALGN_LB LEFT_CENTER = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL RIGHT_CENTER = wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL lyt_info = wx.FlexGridSizer(2, 6) lyt_info.AddGrowableCol(1) lyt_info.AddGrowableCol(3) lyt_info.AddGrowableCol(5) lyt_info.AddMany( ((txt_package, 0, RIGHT_CENTER | wx.RIGHT, 5), (self.ti_package, 1, wx.EXPAND | wx.BOTTOM | wx.RIGHT, 5), (txt_version, 0, RIGHT_CENTER | wx.RIGHT, 5), (self.ti_version, 1, wx.EXPAND | wx.BOTTOM | wx.RIGHT, 5), (txt_dist, 0, RIGHT_CENTER | wx.RIGHT, 5), (self.ti_dist, 1, wx.EXPAND | wx.BOTTOM, 5), (txt_urgency, 0, RIGHT_CENTER | wx.RIGHT, 5), (self.sel_urgency, 1, wx.RIGHT, 5), (txt_maintainer, 0, RIGHT_CENTER | wx.RIGHT, 5), (self.ti_maintainer, 1, wx.EXPAND | wx.RIGHT, 5), (txt_email, 0, RIGHT_CENTER | wx.RIGHT, 5), (self.ti_email, 1, wx.EXPAND))) lyt_details = wx.GridBagSizer() lyt_details.SetCols(3) lyt_details.AddGrowableRow(2) lyt_details.AddGrowableCol(1) lyt_details.Add(btn_import, (0, 0)) lyt_details.Add(txt_import, (0, 1), flag=LEFT_CENTER) lyt_details.Add(wx.StaticText(self, label=GT(u'Changes')), (1, 0), flag=LEFT_BOTTOM) lyt_details.Add(wx.StaticText(self, label=GT(u'Target')), (1, 2), flag=LEFT_BOTTOM) lyt_details.Add(self.ti_changes, (2, 0), (1, 2), wx.EXPAND | wx.RIGHT, 5) lyt_details.Add(self.pnl_target, (2, 2)) lyt_details.Add(self.btn_add, (3, 0), (2, 1)) lyt_details.Add(txt_add, (3, 1), flag=LEFT_BOTTOM | wx.TOP, border=5) lyt_details.Add(self.chk_indentation, (4, 1), flag=LEFT_BOTTOM) lyt_main = BoxSizer(wx.VERTICAL) lyt_main.AddSpacer(10) lyt_main.Add(lyt_info, 0, wx.EXPAND | lyt.PAD_LR, 5) lyt_main.AddSpacer(10) lyt_main.Add(lyt_details, 1, wx.EXPAND | lyt.PAD_LR, 5) lyt_main.Add(wx.StaticText(self, label=u'Changelog Output'), 0, LEFT_BOTTOM | lyt.PAD_LT, 5) lyt_main.Add(self.dsp_changes, 1, wx.EXPAND | lyt.PAD_LR | wx.BOTTOM, 5) self.SetAutoLayout(True) self.SetSizer(lyt_main) self.Layout()
class Page(WizardPage): ## Constructor # # \param parent # Parent <b><i>wx.Window</i></b> instance def __init__(self, parent): WizardPage.__init__(self, parent, pgid.COPYRIGHT) self.custom_licenses = [] ## A list of available license templates self.sel_templates = Choice(self, selid.LICENSE, name=u'list»') # Initialize the template list self.OnRefreshList() btn_template = CreateButton(self, label=GT(u'Full Template'), image=u'full', name=u'full»') self.btn_template_simple = CreateButton(self, label=GT(u'Short Template'), image=u'short', name=u'short»') btn_refresh = CreateButton(self, btnid.REFRESH, GT(u'Refresh Template List'), u'refresh', name=u'btn refresh') btn_open = CreateButton(self, btnid.BROWSE, GT(u'Open Template Directory'), u'browse', name=u'btn opendir', commands=u'xdg-open') if not self.sel_templates.GetCount(): self.sel_templates.Enable(False) btn_template.Enable(False) self.btn_template_simple.Enable(False) ## Area where license text is displayed self.dsp_copyright = TextAreaPanelESS(self, monospace=True, name=u'license') self.dsp_copyright.EnableDropTarget() SetPageToolTips(self) # Initiate tooltip for drop-down selector if self.sel_templates.IsEnabled(): self.OnSelectLicense(self.sel_templates) # *** Event Handling *** # self.sel_templates.Bind(wx.EVT_CHOICE, self.OnSelectLicense) btn_open.Bind(wx.EVT_BUTTON, self.OnOpenPath) btn_refresh.Bind(wx.EVT_BUTTON, self.OnRefreshList) btn_template.Bind(wx.EVT_BUTTON, self.OnTemplateFull) self.btn_template_simple.Bind(wx.EVT_BUTTON, self.OnTemplateShort) # *** Layout *** # lyt_top = BoxSizer(wx.HORIZONTAL) lyt_top.Add(wx.StaticText(self, label=GT(u'Available Templates')), 0, lyt.ALGN_CV) lyt_top.Add(self.sel_templates, 0, lyt.ALGN_CV|wx.LEFT, 5) lyt_top.Add(btn_template, 0, wx.LEFT, 5) lyt_top.Add(self.btn_template_simple) lyt_top.Add(btn_refresh) lyt_top.Add(btn_open) lyt_main = BoxSizer(wx.VERTICAL) lyt_main.AddSpacer(10) lyt_main.Add(lyt_top, 0, lyt.PAD_LR|wx.BOTTOM, 5) lyt_main.Add(self.dsp_copyright, 1, wx.EXPAND|lyt.PAD_LRB, 5) self.SetAutoLayout(True) self.SetSizer(lyt_main) self.Layout() ## Displays a confirmation dialog to clear the text area if it is not empty # # \return # <b><i>True</i></b>, if user confirmed def DestroyLicenseText(self): if not TextIsEmpty(self.dsp_copyright.GetValue()): warn_msg = GT(u'This will destroy all license text.') warn_msg = u'{}\n\n{}'.format(warn_msg, GT(u'Continue?')) if ConfirmationDialog(GetMainWindow(), text=warn_msg).ShowModal() not in (wx.ID_OK, wx.OK): return False return True ## \see wiz.wizard.WizardPage.ExportBuild def ExportBuild(self, stage): stage = u'{}/usr/share/doc/{}'.format(stage, GetPage(pgid.CONTROL).GetPackageName()).replace(u'//', u'/') # FIXME: Should be error check self.Export(stage, u'copyright') return (0, None) ## Retrieves copyright/license text # # \return # <b><i>tuple(str, str)</i></b>: Filename & copyright/license text def Get(self, getModule=False): page = self.dsp_copyright.GetValue() if TextIsEmpty(page): page = None if getModule: page = (__name__, page,) return page ## Retrieves license path # # \param licName # License file basename to search for # If 'None', uses currently selected license # \return # Full path to license file if found def GetLicensePath(self, licName=None): # Default to currently selected template if not licName: licName = self.GetSelectedName() return GetLicenseTemplateFile(licName) ## Retrieves the name of the template currently selected def GetSelectedName(self): return GetField(self, selid.LICENSE).GetStringSelection() ## Sets page's fields from opened file def ImportFromFile(self, filename): if not os.path.isfile(filename): return dbrerrno.ENOENT copyright_data = ReadFile(filename, split=True) # Remove preceding empty lines remove_index = 0 for I in copyright_data: if not TextIsEmpty(I): break remove_index += 1 for I in reversed(range(remove_index)): copyright_data.remove(copyright_data[I]) copyright_data = u'\n'.join(copyright_data) self.dsp_copyright.SetValue(copyright_data) return 0 ## Checks if page can be exported or or added to build def IsOkay(self): return not TextIsEmpty(self.dsp_copyright.GetValue()) ## Opens directory containing currently selected license def OnOpenPath(self, event=None): CMD_open = GetExecutable(u'xdg-open') if CMD_open: path = self.GetLicensePath() if not path: ShowErrorDialog(GT(u'Error retrieving template path: {}').format(self.GetSelectedName())) return False path = os.path.dirname(path) if os.path.isdir(path): ExecuteCommand(CMD_open, (path,)) return True return False ## Repopulates template list def OnRefreshList(self, event=None): # FIXME: Ignore symbolic links??? self.custom_licenses = GetLocalLicenses() licenses = list(self.custom_licenses) # System licenses are not added to "custom" list for LIC in GetSysLicenses(): if LIC not in licenses: licenses.append(LIC) for LIC in GetCustomLicenses(): if LIC not in licenses: licenses.append(LIC) self.custom_licenses.append(LIC) self.custom_licenses.sort(key=GS.lower) sel_templates = GetField(self, selid.LICENSE) selected = None if sel_templates.GetCount(): selected = sel_templates.GetStringSelection() sel_templates.Set(sorted(licenses, key=GS.lower)) if selected: if not sel_templates.SetStringSelection(selected): # Selected template file was not found sel_templates.SetSelection(sel_templates.GetDefaultValue()) # Update short template button enabled state self.OnSelectLicense() else: sel_templates.SetSelection(sel_templates.GetDefaultValue()) ## Enables/Disables simple template button # # Simple template generation is only available # for system licenses. def OnSelectLicense(self, event=None): choice = GetField(self, selid.LICENSE) if choice: template = choice.GetString(choice.GetSelection()) if template in self.custom_licenses: self.btn_template_simple.Disable() else: self.btn_template_simple.Enable() self.SetLicenseTooltip() ## Generates a full license template def OnTemplateFull(self, event=None): selected_template = self.sel_templates.GetStringSelection() template_file = self.GetLicensePath(selected_template) if self.DestroyLicenseText(): if not template_file or not os.path.isfile(template_file): ShowErrorDialog(GT(u'Could not locate license file: {}').format(self.GetSelectedName())) return Logger.Debug(__name__, u'Copying license {}'.format(template_file)) license_text = ReadFile(template_file, noStrip=u' ') # Number defines how many empty lines to add after the copyright header # Boolean/Integer defines whether copyright header should be centered/offset add_header = { u'Artistic': (1, True), u'BSD': (0, False), } template_name = os.path.basename(template_file) if template_name in add_header: license_text = license_text.split(u'\n') empty_lines = add_header[template_name][0] for L in range(empty_lines): license_text.insert(0, wx.EmptyString) header = copyright_header.format(GetYear()) center_header = add_header[template_name][1] if center_header: Logger.Debug(__name__, u'Centering header...') offset = 0 # Don't use isinstance() here because boolean is an instance of integer if type(center_header) == int: offset = center_header else: # Use the longest line found in the text to center the header longest_line = GetLongestLine(license_text) Logger.Debug(__name__, u'Longest line: {}'.format(longest_line)) header_length = len(header) if header_length < longest_line: offset = (longest_line - header_length) / 2 if offset: Logger.Debug(__name__, u'Offset: {}'.format(offset)) header = u'{}{}'.format(u' ' * offset, header) # Special changes for BSD license if template_name == u'BSD': line_index = 0 for LI in license_text: if u'copyright (c)' in LI.lower(): license_text[line_index] = header break line_index += 1 else: license_text.insert(0, header) license_text = u'\n'.join(license_text) if not license_text: ShowErrorDialog(GT(u'License template is empty')) return self.dsp_copyright.SetValue(license_text) self.dsp_copyright.SetInsertionPoint(0) self.dsp_copyright.SetFocus() ## Generates a short reference template for a system license def OnTemplateShort(self, event=None): if self.DestroyLicenseText(): self.dsp_copyright.Clear() license_path = u'{}/{}'.format(sys_licenses_path, self.sel_templates.GetString(self.sel_templates.GetSelection())) self.dsp_copyright.WriteText(u'{}\n\n{}'.format(copyright_header.format(GetYear()), license_path)) self.dsp_copyright.SetInsertionPoint(0) self.dsp_copyright.SetFocus() ## Resets all page fields to default values def Reset(self): self.dsp_copyright.Clear() if self.sel_templates.IsEnabled(): self.sel_templates.Reset() self.OnSelectLicense(self.sel_templates) ## Sets the text of the displayed copyright # # \param data # Text to parse for field values def Set(self, data): self.dsp_copyright.SetValue(data) ## Changes the Choice instance's tooltip for the current license def SetLicenseTooltip(self): license_name = self.sel_templates.GetString(self.sel_templates.GetSelection()) license_path = self.GetLicensePath(license_name) if license_path: self.sel_templates.SetToolTip(wx.ToolTip(license_path)) return self.sel_templates.SetToolTip(None)
def __init__(self, parent, win_id=wx.ID_ANY, name=u'launcher'): ScrolledPanel.__init__(self, parent, win_id, name=name) # --- Buttons to open/preview/save .desktop file btn_open = CreateButton(self, btnid.BROWSE, GT(u'Browse'), u'browse', name=u'btn browse') btn_save = CreateButton(self, btnid.SAVE, GT(u'Save'), u'save', name=u'btn save') btn_preview = CreateButton(self, btnid.PREVIEW, GT(u'Preview'), u'preview', name=u'btn preview') # --- TYPE opts_type = ( u'Application', u'Link', u'Directory', ) txt_type = wx.StaticText(self, label=GT(u'Type'), name=u'type') ti_type = ComboBoxESS(self, inputid.TYPE, choices=opts_type, name=u'Type', defaultValue=opts_type[0]) # --- ENCODING opts_enc = ( u'UTF-1', u'UTF-7', u'UTF-8', u'CESU-8', u'UTF-EBCDIC', u'UTF-16', u'UTF-32', u'SCSU', u'BOCU-1', u'Punycode', u'GB 18030', ) txt_enc = wx.StaticText(self, label=GT(u'Encoding'), name=u'encoding') ti_enc = ComboBoxESS(self, inputid.ENC, choices=opts_enc, name=u'Encoding', defaultValue=opts_enc[2]) # --- TERMINAL chk_term = CheckBoxESS(self, chkid.TERM, GT(u'Terminal'), name=u'Terminal') # --- STARTUP NOTIFY chk_notify = CheckBoxESS(self, chkid.NOTIFY, GT(u'Startup Notify'), name=u'StartupNotify', defaultValue=True) # --- NAME (menu) txt_name = wx.StaticText(self, label=GT(u'Name'), name=u'name*') ti_name = TextAreaESS(self, inputid.NAME, name=u'Name') ti_name.req = True # --- EXECUTABLE txt_exec = wx.StaticText(self, label=GT(u'Executable'), name=u'exec') ti_exec = TextAreaESS(self, inputid.EXEC, name=u'Exec') # --- COMMENT txt_comm = wx.StaticText(self, label=GT(u'Comment'), name=u'comment') ti_comm = TextAreaESS(self, inputid.DESCR, name=u'Comment') # --- ICON txt_icon = wx.StaticText(self, label=GT(u'Icon'), name=u'icon') ti_icon = TextAreaESS(self, inputid.ICON, name=u'Icon') txt_mime = wx.StaticText(self, label=GT(u'MIME Type'), name=u'mime') ti_mime = TextAreaESS(self, inputid.MIME, defaultValue=wx.EmptyString, name=u'MimeType', outLabel=u'MimeType') # ----- OTHER/CUSTOM txt_other = wx.StaticText(self, label=GT(u'Custom Fields'), name=u'other') btn_other = CreateButton(self, label=GT(u'Other'), image=u'add', name=u'btn other') btn_rm_other = CreateButton(self, btnid.REMOVE, GT(u'Remove Other'), u'remove', name=u'btn rm other') pnl_other = SectionedPanel(self, inputid.OTHER) btn_rm_other.Enable(pnl_other.HasSelected()) # --- CATEGORIES opts_category = ( u'2DGraphics', u'Accessibility', u'Application', u'ArcadeGame', u'Archiving', u'Audio', u'AudioVideo', u'BlocksGame', u'BoardGame', u'Calculator', u'Calendar', u'CardGame', u'Compression', u'ContactManagement', u'Core', u'DesktopSettings', u'Development', u'Dictionary', u'DiscBurning', u'Documentation', u'Email', u'FileManager', u'FileTransfer', u'Game', u'GNOME', u'Graphics', u'GTK', u'HardwareSettings', u'InstantMessaging', u'KDE', u'LogicGame', u'Math', u'Monitor', u'Network', u'OCR', u'Office', u'P2P', u'PackageManager', u'Photography', u'Player', u'Presentation', u'Printing', u'Qt', u'RasterGraphics', u'Recorder', u'RemoteAccess', u'Scanning', u'Screensaver', u'Security', u'Settings', u'Spreadsheet', u'System', u'Telephony', u'TerminalEmulator', u'TextEditor', u'Utility', u'VectorGraphics', u'Video', u'Viewer', u'WordProcessor', u'Wine', u'Wine-Programs-Accessories', u'X-GNOME-NetworkSettings', u'X-GNOME-PersonalSettings', u'X-GNOME-SystemSettings', u'X-KDE-More', u'X-Red-Hat-Base', u'X-SuSE-ControlCenter-System', ) txt_category = wx.StaticText(self, label=GT(u'Categories'), name=u'category') btn_catclr = CreateButton(self, btnid.CLEAR, GT(u'Clear'), u'clear', name=u'clear category') lst_categories = CheckList(self, listid.CAT, opts_category, name=u'Categories') if not lst_categories.HasSelected(): btn_catclr.Disable() txt_catcustom = wx.StaticText( self, label=GT(u'Custom Categories (Separate by "," or ";")')) # Set to 'True' to list custom categories first # FIXME: Should this be saved to project instead of config??? chk_catcustom = CheckBoxCFG(self, chkid.CAT, GT(u'List first'), name=u'chk catcustom', cfgKey=u'prioritize custom categories') ti_catcustom = TextAreaESS(self, inputid.CAT2, name=u'category custom') # *** Event Handling *** # btn_open.Bind(wx.EVT_BUTTON, self.OnLoadLauncher) btn_save.Bind(wx.EVT_BUTTON, self.OnExportLauncher) btn_preview.Bind(wx.EVT_BUTTON, self.OnPreviewLauncher) btn_other.Bind(wx.EVT_BUTTON, self.OnOtherAdd) btn_rm_other.Bind(wx.EVT_BUTTON, self.OnOtherRemove) btn_catclr.Bind(wx.EVT_BUTTON, self.OnClearCategories) wx.EVT_CHECKBOX(self, inputid.OTHER, self.OnOtherSelect) wx.EVT_CHECKBOX(self, listid.CAT, self.OnCatSelect) # *** Layout *** # LEFT_CENTER = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL LEFT_BOTTOM = wx.ALIGN_LEFT | wx.ALIGN_BOTTOM RIGHT_BOTTOM = wx.ALIGN_RIGHT | wx.ALIGN_BOTTOM lyt_opts1 = wx.FlexGridSizer() lyt_opts1.SetCols(3) lyt_opts1.SetRows(2) lyt_opts1.Add(txt_type, 0, LEFT_CENTER) lyt_opts1.Add(ti_type, 0, wx.EXPAND | wx.LEFT, 5) lyt_opts1.Add(chk_term, 0, LEFT_CENTER | wx.LEFT, 5) lyt_opts1.Add(txt_enc, 0, LEFT_CENTER | wx.TOP, 5) lyt_opts1.Add(ti_enc, 0, wx.LEFT | wx.TOP, 5) lyt_opts1.Add(chk_notify, 0, LEFT_CENTER | wx.LEFT | wx.TOP, 5) lyt_top = BoxSizer(wx.HORIZONTAL) lyt_top.Add(lyt_opts1, 0, wx.EXPAND | wx.ALIGN_BOTTOM) lyt_top.AddStretchSpacer(1) lyt_top.Add(btn_open, 0, wx.ALIGN_TOP) lyt_top.Add(btn_save, 0, wx.ALIGN_TOP) lyt_top.Add(btn_preview, 0, wx.ALIGN_TOP) lyt_mid = wx.GridBagSizer() lyt_mid.SetCols(4) lyt_mid.AddGrowableCol(1) lyt_mid.AddGrowableCol(3) # Row 1 row = 0 lyt_mid.Add(txt_name, (row, 0), flag=LEFT_CENTER) lyt_mid.Add(ti_name, (row, 1), flag=wx.EXPAND | wx.LEFT, border=5) lyt_mid.Add(txt_exec, (row, 2), flag=LEFT_CENTER | wx.LEFT, border=5) lyt_mid.Add(ti_exec, (row, 3), flag=wx.EXPAND | wx.LEFT, border=5) # Row 2 row += 1 lyt_mid.Add(txt_comm, (row, 0), flag=LEFT_CENTER | wx.TOP, border=5) lyt_mid.Add(ti_comm, (row, 1), flag=wx.EXPAND | wx.LEFT | wx.TOP, border=5) lyt_mid.Add(txt_icon, (row, 2), flag=LEFT_CENTER | wx.LEFT | wx.TOP, border=5) lyt_mid.Add(ti_icon, (row, 3), flag=wx.EXPAND | wx.LEFT | wx.TOP, border=5) # Row 3 row += 1 lyt_mid.Add(txt_mime, (row, 0), flag=LEFT_CENTER | wx.TOP, border=5) lyt_mid.Add(ti_mime, (row, 1), flag=wx.EXPAND | wx.LEFT | wx.TOP, border=5) lyt_bottom = wx.GridBagSizer() row = 0 lyt_bottom.Add(txt_other, (row, 0), flag=LEFT_BOTTOM) lyt_bottom.Add(btn_other, (row, 1), flag=RIGHT_BOTTOM) lyt_bottom.Add(btn_rm_other, (row, 2), flag=RIGHT_BOTTOM) lyt_bottom.Add(txt_category, (row, 3), flag=LEFT_BOTTOM | wx.LEFT, border=5) lyt_bottom.Add(btn_catclr, (row, 4), flag=RIGHT_BOTTOM) row += 1 lyt_bottom.Add(pnl_other, (row, 0), (3, 3), wx.EXPAND) lyt_bottom.Add(lst_categories, (row, 3), (1, 2), wx.EXPAND | wx.LEFT, 5) row += 1 lyt_bottom.Add(txt_catcustom, (row, 3), flag=LEFT_BOTTOM | wx.LEFT | wx.TOP, border=5) lyt_bottom.Add(chk_catcustom, (row, 4), flag=RIGHT_BOTTOM) row += 1 lyt_bottom.Add(ti_catcustom, (row, 3), (1, 2), flag=wx.EXPAND | wx.LEFT, border=5) lyt_bottom.AddGrowableRow(1) lyt_bottom.AddGrowableCol(1) lyt_bottom.AddGrowableCol(3) # --- Page 5 Sizer --- # lyt_main = BoxSizer(wx.VERTICAL) lyt_main.AddSpacer(5) lyt_main.Add(lyt_top, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, 5) lyt_main.Add(lyt_mid, 0, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, 5) lyt_main.Add(lyt_bottom, 1, wx.EXPAND | wx.ALL, 5) self.SetAutoLayout(True) self.SetSizer(lyt_main) self.Layout()