예제 #1
0
    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()
예제 #2
0
	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
예제 #3
0
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:]))
예제 #4
0
	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)
예제 #5
0
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
예제 #6
0
    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()
예제 #7
0
    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
예제 #8
0
 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()
예제 #9
0
    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()
예제 #10
0
    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()
예제 #11
0
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:]))
예제 #12
0
	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()
예제 #13
0
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])
예제 #14
0
 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()
예제 #15
0
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))
예제 #16
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()
예제 #17
0
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)
예제 #18
0
    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()