Beispiel #1
0
    def CreateDetailedView(self, details):
        # Controls have not been constructed yet
        if TextIsEmpty(self.details):
            self.btn_details = wx.ToggleButton(self, label=GT(u'Details'))
            #btn_copy = wx.Button(self, label=GT(u'Copy details'))

            self.dsp_details = TextAreaPanel(self,
                                             value=details,
                                             style=wx.TE_READONLY)

            # *** Event handlers *** #

            self.btn_details.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleDetails)
            #btn_copy.Bind(wx.EVT_BUTTON, self.OnCopyDetails)

            layout = self.GetSizer()
            layout.Add(self.btn_details, (2, 1))
            #layout.Add(btn_copy, (2, 2), flag=wx.ALIGN_LEFT|wx.RIGHT, border=5)
            layout.Add(self.dsp_details, (3, 1), (1, 2), wx.EXPAND | wx.RIGHT,
                       5)

            self.ToggleDetails()

        if not TextIsEmpty(details):
            for C in self.GetChildren():
                if isinstance(C, TextAreaPanel):
                    self.details = details
                    C.SetValue(self.details)

                    return True

        return False
Beispiel #2
0
 def __init__(self, parent, logFile):
     wx.Dialog.__init__(self, parent, style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
     
     self.SetIcon(APP_logo)
     
     self.LogFile = FileItem(logFile)
     self.SetTitle()
     
     self.LogPollThread = Thread(self.PollLogFile)
     
     self.DspLog = TextAreaPanel(self, style=wx.TE_READONLY)
     self.DspLog.font_size = 8
     self.DspLog.SetFont(GetMonospacedFont(self.DspLog.font_size))
     
     btn_open = CreateButton(self, btnid.BROWSE, GT(u'Open and Display Log File'), u'browse')
     btn_font = CreateButton(self, btnid.ZOOM, GT(u'Zoom Text'), u'zoom')
     btn_refresh = CreateButton(self, btnid.REFRESH, GT(u'Refresh'), u'refresh')
     btn_hide = CreateButton(self, btnid.CLOSE, GT(u'Hide'), u'hide')
     
     # *** Event Handling *** #
     
     EVT_REFRESH_LOG(self, wx.ID_ANY, self.OnLogTimestampChanged)
     
     wx.EVT_BUTTON(self, btnid.BROWSE, self.OnOpenLogFile)
     wx.EVT_BUTTON(self, btnid.ZOOM, self.OnChangeFont)
     wx.EVT_BUTTON(self, btnid.REFRESH, self.RefreshLog)
     wx.EVT_BUTTON(self, btnid.CLOSE, self.OnClose)
     
     wx.EVT_CLOSE(self, self.OnClose)
     wx.EVT_SHOW(self, self.OnShow)
     wx.EVT_SHOW(GetMainWindow(), self.OnShowMainWindow)
     
     # *** Layout *** #
     
     layout_btnF1 = wx.FlexGridSizer(cols=5)
     layout_btnF1.AddGrowableCol(1, 1)
     layout_btnF1.Add(btn_open, 0, wx.LEFT, 5)
     layout_btnF1.AddStretchSpacer(1)
     layout_btnF1.Add(btn_font, 0, wx.RIGHT, 5)
     layout_btnF1.Add(btn_refresh, 0, wx.RIGHT, 5)
     layout_btnF1.Add(btn_hide, 0, wx.RIGHT, 5)
     
     layout_mainV1 = BoxSizer(wx.VERTICAL)
     layout_mainV1.Add(self.DspLog, 1, wx.ALL|wx.EXPAND, 5)
     layout_mainV1.Add(layout_btnF1, 0, wx.EXPAND|wx.BOTTOM, 5)
     
     self.SetAutoLayout(True)
     self.SetSizer(layout_mainV1)
     self.Layout()
     
     self.SetMinSize(self.GetSize())
     
     self.SetSize(wx.Size(600, 600))
     
     self.AlignWithMainWindow()
     
     # Make sure log window is not shown at initialization
     self.Show(False)
Beispiel #3
0
    def SetModeManual(self):
        self.ManualText = TextAreaPanel(self)

        # *** Layout *** #

        self.lyt_main.Add(self.lyt_buttons, 0, wx.EXPAND | wx.ALL, 5)
        self.lyt_main.Add(self.ManualText, 1, wx.EXPAND)

        self.SetAutoLayout(True)
        self.SetSizer(self.lyt_main)
        self.Layout()
Beispiel #4
0
    def __init__(self,
                 parent=None,
                 ID=wx.ID_ANY,
                 title=GT(u'Preview'),
                 text=wx.EmptyString,
                 pos=wx.DefaultPosition,
                 size=wx.DefaultSize,
                 style=wx.DEFAULT_DIALOG_STYLE,
                 name=wx.DialogNameStr,
                 monospace=True,
                 readonly=True):

        BaseDialog.__init__(self, parent, ID, title, pos, size, style, name)

        ti_style = 0
        if readonly:
            ti_style = wx.TE_READONLY

        # FIXME: Hide caret
        text_display = TextAreaPanel(self, monospace=monospace, style=ti_style)

        if text:
            text_display.SetValue(text)

        # *** Event Handling *** #

        self.Bind(wx.EVT_BUTTON, self.OnButton)

        # *** Layout *** #

        lyt_main = BoxSizer(wx.VERTICAL)
        lyt_main.Add(text_display, 1, wx.EXPAND | lyt.PAD_LR | wx.BOTTOM, 5)

        self.SetAutoLayout(True)
        self.SetSizer(lyt_main)
        self.Layout()
Beispiel #5
0
    def GetObject(self,
                  section_name=None,
                  multiline=False,
                  static=False,
                  expand=False,
                  removable=False):
        if static:
            try:
                self.sect_name = wx.StaticText(self.Parent, label=section_name)

            except TypeError:
                err_l1 = GT(u'Could not remove section')
                err_l2 = GT(u'Please report this problem to the developers')
                ShowErrorDialog(u'{}\n\n{}'.format(err_l1, err_l2),
                                traceback.format_exc())

                return None

        else:
            self.sect_name = Choice(self.Parent, choices=self.sections)

        if multiline:
            value = TextAreaPanel(self.Parent)
            FLAG_VALUE = wx.EXPAND | wx.LEFT
            FLAG_LABEL = wx.ALIGN_TOP

        else:
            value = TextArea(self.Parent)
            FLAG_VALUE = wx.ALIGN_CENTER_VERTICAL | wx.LEFT
            FLAG_LABEL = wx.ALIGN_CENTER_VERTICAL

        self.lyt_main.Add(self.sect_name, (0, 0), flag=FLAG_LABEL)
        self.lyt_main.Add(value, (0, 1), flag=FLAG_VALUE, border=5)

        if expand:
            self.lyt_main.AddGrowableCol(1)

        if removable:
            self.btn_remove = CreateButton(self.Parent, btnid.REMOVE)

            self.lyt_main.Add(self.btn_remove, (0, 2), flag=wx.RIGHT, border=5)

        return ManSectBase.GetObject(self)
Beispiel #6
0
    def __init__(self, parent, label=None, style=DEFAULT_MANSECT_STYLE):
        ManSectBase2.__init__(self, parent, label, style)

        FLAGS = wx.EXPAND | wx.LEFT | wx.ALIGN_CENTER_VERTICAL
        FLAGS_MAIN = wx.ALIGN_CENTER_VERTICAL

        if self.HasStyle(manid.MULTILINE):
            self.Input = TextAreaPanel(self.Panel)
            #FLAGS = wx.EXPAND|FLAGS
            FLAGS_MAIN = wx.EXPAND | FLAGS_MAIN

        else:
            self.Input = TextArea(self.Panel)

        lyt_input = BoxSizer(wx.VERTICAL)
        lyt_input.Add(self.Input, 1, FLAGS, 5)
        #lyt_input = wx.GridBagSizer()
        #lyt_input.AddGrowableCol(0)

        #lyt_input.Add(self.Input, (0, 0), flag=FLAGS, border=5)

        lyt_main = self.GetSizer()
        lyt_main.Insert(1, lyt_input, 3, FLAGS_MAIN)
Beispiel #7
0
    def __init__(self, parent):
        ManSectBase.__init__(self, parent)

        self._add_field(GT(u'Synopsis'), TextAreaPanel(parent), expand=True)
Beispiel #8
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()
Beispiel #9
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:]))
Beispiel #10
0
    def __init__(self, parent, size=(600, 558)):
        wx.Dialog.__init__(self,
                           parent,
                           wx.ID_ABOUT,
                           GT(u'About'),
                           size=size,
                           style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)

        self.SetMinSize(wx.Size(400, 375))
        self.CenterOnParent()

        # Create a tabbed interface
        tabs = wx.Notebook(self, -1)

        # Pages
        self.t_about = wx.Panel(tabs, -1)
        t_credits = wx.Panel(tabs, -1)
        t_changelog = wx.Panel(tabs, -1)
        t_license = wx.Panel(tabs, -1)

        # Add pages to tabbed interface
        tabs.AddPage(self.t_about, GT(u'About'))
        tabs.AddPage(t_credits, GT(u'Credits'))
        tabs.AddPage(t_changelog, GT(u'Changelog'))
        tabs.AddPage(t_license, GT(u'License'))

        # FIXME: Center verticall on about tab
        self.about_layout_V1 = BoxSizer(wx.VERTICAL)
        self.about_layout_V1.AddStretchSpacer()
        self.about_layout_V1.AddStretchSpacer()

        self.t_about.SetAutoLayout(True)
        self.t_about.SetSizer(self.about_layout_V1)
        self.t_about.Layout()

        ## List of credits
        self.credits = ListCtrl(t_credits)
        self.credits.SetSingleStyle(wx.LC_REPORT)
        self.credits.InsertColumn(0, GT(u'Name'), width=150)
        self.credits.InsertColumn(1, GT(u'Job'), width=200)
        self.credits.InsertColumn(2, GT(u'Email'), width=240)

        credits_sizer = BoxSizer(wx.VERTICAL)
        credits_sizer.Add(self.credits, 1, wx.EXPAND)

        t_credits.SetAutoLayout(True)
        t_credits.SetSizer(credits_sizer)
        t_credits.Layout()

        ## Changelog text area
        self.changelog = TextAreaPanel(t_changelog, style=wx.TE_READONLY)
        self.changelog.SetFont(MONOSPACED_MD)

        log_sizer = BoxSizer(wx.VERTICAL)
        log_sizer.Add(self.changelog, 1, wx.EXPAND)

        t_changelog.SetSizer(log_sizer)
        t_changelog.Layout()

        ## Licensing information text area
        self.license = TextAreaPanel(t_license, style=wx.TE_READONLY)
        self.license.SetFont(MONOSPACED_MD)

        license_sizer = BoxSizer(wx.VERTICAL)
        license_sizer.Add(self.license, 1, wx.EXPAND)

        t_license.SetSizer(license_sizer)
        t_license.Layout()

        # System info
        sys_info = wx.Panel(tabs, -1)
        tabs.AddPage(sys_info, GT(u'System Information'))

        ## System's <a href="https://www.python.org/">Python</a> version
        self.py_info = wx.StaticText(
            sys_info, -1,
            GT(u'Python version: {}').format(PY_VER_STRING))

        ## System's <a href="https://wxpython.org/">wxPython</a> version
        self.wx_info = wx.StaticText(
            sys_info, -1,
            GT(u'wxPython version: {}').format(WX_VER_STRING))

        ## Debreate's installation prefix
        install_prefix = wx.StaticText(
            sys_info, label=GT(u'App location: {}').format(PATH_app))

        if INSTALLED:
            install_prefix.SetLabel(
                GT(u'Installation prefix: {}').format(PREFIX))

        self.py_info.SetFont(sys_info_font)
        self.wx_info.SetFont(sys_info_font)

        sysinfo_layout_V1 = BoxSizer(wx.VERTICAL)
        sysinfo_layout_V1.AddStretchSpacer()
        sysinfo_layout_V1.Add(self.py_info, 0, wx.ALIGN_CENTER | wx.BOTTOM, 5)
        sysinfo_layout_V1.Add(self.wx_info, 0, wx.ALIGN_CENTER | wx.TOP, 5)
        sysinfo_layout_V1.AddSpacer(20)
        sysinfo_layout_V1.Add(install_prefix, 0, wx.ALIGN_CENTER | wx.TOP, 5)
        sysinfo_layout_V1.AddStretchSpacer()

        if OS_name:
            os_info = wx.StaticText(sys_info, label=OS_name)
            os_info.SetFont(sys_info_font)

            if OS_version:
                os_info.SetLabel(u'{} {}'.format(os_info.LabelText,
                                                 OS_version))

            if OS_codename:
                os_info.SetLabel(u'{} {}'.format(os_info.LabelText,
                                                 OS_codename))

            sysinfo_layout_V1.Insert(1, os_info, 0,
                                     wx.ALIGN_CENTER | wx.BOTTOM, 5)
            sysinfo_layout_V1.InsertSpacer(2, 20)

            if OS_upstream_name:
                os_upstream_info = wx.StaticText(sys_info,
                                                 label=OS_upstream_name)

                if OS_upstream_version:
                    os_upstream_info.SetLabel(u'{} {}'.format(
                        os_upstream_info.LabelText, OS_upstream_version))

                if OS_upstream_codename:
                    os_upstream_info.SetLabel(u'{} {}'.format(
                        os_upstream_info.LabelText, OS_upstream_codename))

                sysinfo_layout_V1.Insert(2, os_upstream_info, 0,
                                         wx.ALIGN_CENTER | wx.BOTTOM, 5)

        sys_info.SetSizer(sysinfo_layout_V1)
        sys_info.Layout()

        # Button to close the dialog
        btn_confirm = CreateButton(self, btnid.CONFIRM)

        sizer = BoxSizer(wx.VERTICAL)
        sizer.Add(tabs, 1, wx.EXPAND)
        sizer.Add(btn_confirm, 0, wx.ALIGN_RIGHT | lyt.PAD_RTB, 5)

        self.SetSizer(sizer)
        self.Layout()
Beispiel #11
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()
Beispiel #12
0
class LogWindow(wx.Dialog):
    def __init__(self, parent, logFile):
        wx.Dialog.__init__(self,
                           parent,
                           style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)

        self.SetIcon(APP_logo)

        self.LogFile = FileItem(logFile)
        self.SetTitle()

        self.LogPollThread = Thread(self.PollLogFile)

        self.DspLog = TextAreaPanel(self, style=wx.TE_READONLY)
        self.DspLog.font_size = 8
        self.DspLog.SetFont(GetMonospacedFont(self.DspLog.font_size))

        btn_open = CreateButton(self, btnid.BROWSE,
                                GT(u'Open and Display Log File'), u'browse')
        btn_font = CreateButton(self, btnid.ZOOM, GT(u'Zoom Text'), u'zoom')
        btn_refresh = CreateButton(self, btnid.REFRESH, GT(u'Refresh'),
                                   u'refresh')
        btn_hide = CreateButton(self, btnid.CLOSE, GT(u'Hide'), u'hide')

        # *** Event Handling *** #

        EVT_REFRESH_LOG(self, wx.ID_ANY, self.OnLogTimestampChanged)

        wx.EVT_BUTTON(self, btnid.BROWSE, self.OnOpenLogFile)
        wx.EVT_BUTTON(self, btnid.ZOOM, self.OnChangeFont)
        wx.EVT_BUTTON(self, btnid.REFRESH, self.RefreshLog)
        wx.EVT_BUTTON(self, btnid.CLOSE, self.OnClose)

        wx.EVT_CLOSE(self, self.OnClose)
        wx.EVT_SHOW(self, self.OnShow)
        wx.EVT_SHOW(GetMainWindow(), self.OnShowMainWindow)

        # *** Layout *** #

        layout_btnF1 = wx.FlexGridSizer(cols=5)
        layout_btnF1.AddGrowableCol(1, 1)
        layout_btnF1.Add(btn_open, 0, wx.LEFT, 5)
        layout_btnF1.AddStretchSpacer(1)
        layout_btnF1.Add(btn_font, 0, wx.RIGHT, 5)
        layout_btnF1.Add(btn_refresh, 0, wx.RIGHT, 5)
        layout_btnF1.Add(btn_hide, 0, wx.RIGHT, 5)

        layout_mainV1 = BoxSizer(wx.VERTICAL)
        layout_mainV1.Add(self.DspLog, 1, wx.ALL | wx.EXPAND, 5)
        layout_mainV1.Add(layout_btnF1, 0, wx.EXPAND | wx.BOTTOM, 5)

        self.SetAutoLayout(True)
        self.SetSizer(layout_mainV1)
        self.Layout()

        self.SetMinSize(self.GetSize())

        self.SetSize(wx.Size(600, 600))

        self.AlignWithMainWindow()

        # Make sure log window is not shown at initialization
        self.Show(False)

    ## Positions the log window relative to the main window
    def AlignWithMainWindow(self):
        debreate_pos = GetMainWindow().GetPosition()
        width = self.GetSize()[0]
        posX = debreate_pos[0] - width
        posY = debreate_pos[1]

        self.SetPosition(wx.Point(posX, posY))

    ## Hides the log window & clears contents
    def HideLog(self):
        self.Show(False)
        self.DspLog.Clear()

    ## Changes the font size
    def OnChangeFont(self, event=None):
        font_sizes = {
            7: 8,
            8: 10,
            10: 7,
        }

        current_font_size = self.DspLog.font_size

        for S in font_sizes:
            if S == current_font_size:
                self.DspLog.SetFont(GetMonospacedFont(font_sizes[S]))
                self.DspLog.font_size = font_sizes[S]

                return

        Logger.Error(__name__, GT(u'Can\'t change log window font'))

    ## Hides the log window when close event occurs
    def OnClose(self, event=None):
        self.HideLog()

    ## Called by refresh event to update the log display
    def OnLogTimestampChanged(self, event=None):
        self.RefreshLog()

    ## Opens a new log file
    def OnOpenLogFile(self, event=None):
        log_select = GetFileOpenDialog(self,
                                       GT(u'Open Log'),
                                       directory=PATH_logs)

        if ShowDialog(log_select):
            logFile = log_select.GetPath()

            if os.path.isfile(logFile):
                self.SetLogFile(logFile)

                return

            ShowErrorDialog(u'{}: {}'.format(GT(u'File does not exist'),
                                             logFile),
                            parent=self)

    ## Guarantees that menu item is synced with window's shown status
    def OnShow(self, event=None):
        menu_debug = GetMenu(menuid.DEBUG)

        # In case main window has been destroyed, but sub thread still active
        if GetMainWindow():
            window_shown = self.IsShown()
            m_checked = menu_debug.IsChecked(menuid.LOG)

            if m_checked != window_shown:
                menu_debug.Check(menuid.LOG, window_shown)

        else:
            Logger.Warn(__name__, u'Log thread still active!')

    ## Use an event to show the log window
    #
    #  By waiting until the main window emits a show event
    #	a separate item is not added in the system window
    #	list for the log.
    def OnShowMainWindow(self, event=None):
        main_window = GetMainWindow()

        # Make sure the main window has not been destroyed before showing log
        if main_window and main_window.IsShown():
            if GetMenu(menuid.DEBUG).IsChecked(menuid.LOG):
                self.ShowLog()

    ## Toggles the log window shown or hidden
    def OnToggleWindow(self, event=None):
        show = GetMenu(menuid.DEBUG).IsChecked(menuid.LOG)

        if show:
            self.ShowLog()
            return

        self.HideLog()

        if event:
            event.Skip(True)

    ## Creates a thread that polls for changes in log file
    def PollLogFile(self, args=None):
        while self and self.IsShown():
            if self.LogFile.TimestampChanged():
                print(u'Log timestamp changed, loading new log ...')

                wx.PostEvent(self, RefreshLogEvent(0))

            time.sleep(LOG_WINDOW_REFRESH_INTERVAL)

    ## Fills log with text file contents
    def RefreshLog(self, event=None):
        if self.LogFile.IsFile():
            log_data = self.LogFile.Read()

            if not self.DspLog.IsEmpty():
                self.DspLog.Clear()

            self.DspLog.SetValue(log_data)

            try:
                # Yield here to make sure last line is displayed
                # FIXME: Causes delay when debug enabled
                wx.SafeYield()
                self.DspLog.ShowPosition(self.DspLog.GetLastPosition())

            except wx.PyDeadObjectError:
                tb_error = GS(traceback.format_exc())

                Logger.Warn(
                    __name__,
                    u'Error refreshing log window. Details below:\n\n{}'.
                    format(tb_error))

    ## Changes the file to be loaded & displayed
    #
    #  \param logFile
    #	Absolute path of file to load
    def SetLogFile(self, logFile):
        self.LogFile = FileItem(logFile)
        self.RefreshLog()
        self.SetTitle()

    ## Updates the window's title using path of log file
    def SetTitle(self):
        new_title = self.LogFile.GetPath()
        if new_title:
            return wx.Dialog.SetTitle(self, new_title)

    ## Shows the log window
    def ShowLog(self):
        self.RefreshLog()
        self.Show(True)

        if not self.LogPollThread.IsActive():
            Logger.Debug(__name__, u'Starting log polling thread ...')

            self.LogPollThread.Start()

        else:
            Logger.Debug(__name__, u'Log polling thread is already started')
Beispiel #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.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:]))
Beispiel #14
0
	def __init__(self, parent):
		TextAreaPanel.__init__(self, parent, style=wx.TE_READONLY)
		self.stdout = sys.stdout
		self.stderr = sys.stderr
Beispiel #15
0
class DetailedMessageDialog(BaseDialog, ButtonDialog):
    def __init__(self,
                 parent,
                 title=GT(u'Message'),
                 icon=ICON_INFORMATION,
                 text=wx.EmptyString,
                 details=wx.EmptyString,
                 style=wx.DEFAULT_DIALOG_STYLE,
                 buttons=(wx.ID_OK, ),
                 linewrap=0):

        BaseDialog.__init__(self, parent, wx.ID_ANY, title, style=style)

        # Allow using strings for 'icon' argument
        if isinstance(icon, (unicode, str)):
            icon = wx.Bitmap(icon)

        icon = wx.StaticBitmap(self, wx.ID_ANY, icon)

        txt_message = wx.StaticText(self, label=text)
        if linewrap:
            txt_message.Wrap(linewrap)

        # self.details needs to be empty for constructor
        self.details = wx.EmptyString
        details = details

        # *** Layout *** #

        self.lyt_urls = BoxSizer(wx.VERTICAL)

        # Only set if buttons are added to dialog
        self.lyt_buttons = None

        lyt_main = wx.GridBagSizer(5, 5)
        lyt_main.SetCols(3)
        lyt_main.AddGrowableRow(3)
        lyt_main.AddGrowableCol(2)
        lyt_main.Add(icon, (0, 0), (5, 1),
                     wx.ALIGN_TOP | lyt.PAD_LR | wx.BOTTOM, 20)
        lyt_main.Add(txt_message, (0, 1), (1, 2), lyt.PAD_RT, 20)
        lyt_main.Add(self.lyt_urls, (1, 1), (1, 2), wx.RIGHT, 5)

        self.SetAutoLayout(True)
        self.SetSizer(lyt_main)

        self.AddButtons(buttons)

        if not TextIsEmpty(details):
            # self.details will be set here
            self.CreateDetailedView(details)

        else:
            self.Layout()

            self.Fit()
            self.SetMinSize(self.GetSize())

        self.CenterOnParent()

    ## Add custom buttons to dialog
    #
    #  NOTE: Do not call before self.SetSizer
    #
    #  FIXME: Rename to SetButtons???
    #  FIXME: Should delete any previous buttons
    def AddButtons(self, button_ids):
        self.lyt_buttons = AddCustomButtons(self, button_ids)

        self.Sizer.Add(self.lyt_buttons, (4, 2),
                       flag=wx.ALIGN_RIGHT | wx.ALIGN_BOTTOM | lyt.PAD_RTB,
                       border=5)

    ## Adds a clickable link to the dialog
    def AddURL(self, url):
        if not isinstance(url, Hyperlink):
            url = Hyperlink(self, wx.ID_ANY, label=url, url=url)

        self.lyt_urls.Add(url, 0, wx.ALIGN_CENTER_VERTICAL)

        self.Layout()
        self.Fit()
        self.SetMinSize(self.GetSize())
        self.CenterOnParent()

    ## Shows dialog modal & returns 'confirmed' value
    #
    #  \return
    #	\b \e bool : True if ShowModal return value one of wx.ID_OK, wx.OK, wx.ID_YES, wx.YES
    def Confirmed(self):
        return self.ShowModal() in (wx.ID_OK, wx.OK, wx.ID_YES, wx.YES)

    ## Adds buttons & details text to dialog
    #
    #  \param details
    #		\b \e unicode|str : Detailed text to show in dialog
    def CreateDetailedView(self, details):
        # Controls have not been constructed yet
        if TextIsEmpty(self.details):
            self.btn_details = wx.ToggleButton(self, label=GT(u'Details'))
            #btn_copy = wx.Button(self, label=GT(u'Copy details'))

            self.dsp_details = TextAreaPanel(self,
                                             value=details,
                                             style=wx.TE_READONLY)

            # *** Event handlers *** #

            self.btn_details.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleDetails)
            #btn_copy.Bind(wx.EVT_BUTTON, self.OnCopyDetails)

            layout = self.GetSizer()
            layout.Add(self.btn_details, (2, 1))
            #layout.Add(btn_copy, (2, 2), flag=wx.ALIGN_LEFT|wx.RIGHT, border=5)
            layout.Add(self.dsp_details, (3, 1), (1, 2), wx.EXPAND | wx.RIGHT,
                       5)

            self.ToggleDetails()

        if not TextIsEmpty(details):
            for C in self.GetChildren():
                if isinstance(C, TextAreaPanel):
                    self.details = details
                    C.SetValue(self.details)

                    return True

        return False

    ## Attempts to retrieve button instance matching btn_id
    #
    #  FIXME: This will fail if there are standard buttons in the dialog
    #  FIXME: Retrieving by label doesn't work
    #  \param btn_id
    #	ID of the button instance to retrieve
    #  \return
    #	\b \e wx.Button instance or None
    def GetButton(self, btn_id):
        # Allow search by label
        use_label = not isinstance(btn_id, int)

        if self.lyt_buttons:
            for sizer in self.lyt_buttons.GetChildren():
                sizer = sizer.GetSizer()

                btn_layout = sizer.GetChildren()

                if btn_layout:
                    BTN = btn_layout[0].GetWindow()
                    LBL = None

                    if len(btn_layout) < 2 and isinstance(BTN, wx.Button):
                        LBL = BTN.GetLabel()

                    else:
                        LBL = btn_layout[1]
                        if isinstance(LBL, wx.StaticText):
                            LBL = LBL.GetLabel()

                    if not use_label:
                        if BTN.GetId() == btn_id:
                            return BTN

                    else:
                        if LBL == btn_id:
                            return BTN

    ## TODO: Doxygen
    #
    #  FIXME: Layout initially wrong
    #  TODO: Allow copying details to clipboard
    def OnCopyDetails(self, event=None):
        print(u'DEBUG: Copying details to clipboard ...')

        DetailedMessageDialog(
            self, u'FIXME', ICON_EXCLAMATION,
            u'Copying details to clipboard not functional').ShowModal()
        return

        cb_set = False

        clipboard = wx.Clipboard()
        if clipboard.Open():
            print(u'DEBUG: Clipboard opened')

            details = wx.TextDataObject(self.dsp_details.GetValue())
            print(u'DEBUG: Details set to:\n{}'.format(details.GetText()))

            clipboard.Clear()
            print(u'DEBUG: Clipboard cleared')

            cb_set = clipboard.SetData(details)
            print(u'DEBUG: Clipboard data set')

            clipboard.Flush()
            print(u'DEBUG: Clipboard flushed')

            clipboard.Close()
            print(u'DEBUG: Clipboard cloased')

        del clipboard
        print(u'DEBUG: Clipboard object deleted')

        wx.MessageBox(u'FIXME: Details not copied to clipboard', GT(u'Debug'))

    ## Override inherited method to center on parent window first
    def ShowModal(self, *args, **kwargs):
        if self.Parent:
            self.CenterOnParent()

        return wx.Dialog.ShowModal(self, *args, **kwargs)

    ## TODO: Doxygen
    def SetDetails(self, details):
        return self.CreateDetailedView(details)

    ## TODO: Doxygen
    def ToggleDetails(self, event=None):
        try:
            if self.btn_details.GetValue():
                self.dsp_details.Show()

            else:
                self.dsp_details.Hide()

            self.Layout()
            self.Fit()
            self.SetMinSize(self.GetSize())

            return True

        except AttributeError:
            # Disable toggling details
            self.btn_details.Hide()

            self.Layout()
            self.Fit()
            self.SetMinSize(self.GetSize())

            return False
Beispiel #16
0
 def __init__(self, parent):
     TextAreaPanel.__init__(self, parent, style=wx.TE_READONLY)
     self.stdout = sys.stdout
     self.stderr = sys.stderr
Beispiel #17
0
class AboutDialog(wx.Dialog):
    ## Constructor
    #
    #  \param parent
    #	The <b><i>wx.Window</i></b> parent instance
    #  \param size
    #	Window size <b><i>tuple</i></b>
    def __init__(self, parent, size=(600, 558)):
        wx.Dialog.__init__(self,
                           parent,
                           wx.ID_ABOUT,
                           GT(u'About'),
                           size=size,
                           style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)

        self.SetMinSize(wx.Size(400, 375))
        self.CenterOnParent()

        # Create a tabbed interface
        tabs = wx.Notebook(self, -1)

        # Pages
        self.t_about = wx.Panel(tabs, -1)
        t_credits = wx.Panel(tabs, -1)
        t_changelog = wx.Panel(tabs, -1)
        t_license = wx.Panel(tabs, -1)

        # Add pages to tabbed interface
        tabs.AddPage(self.t_about, GT(u'About'))
        tabs.AddPage(t_credits, GT(u'Credits'))
        tabs.AddPage(t_changelog, GT(u'Changelog'))
        tabs.AddPage(t_license, GT(u'License'))

        # FIXME: Center verticall on about tab
        self.about_layout_V1 = BoxSizer(wx.VERTICAL)
        self.about_layout_V1.AddStretchSpacer()
        self.about_layout_V1.AddStretchSpacer()

        self.t_about.SetAutoLayout(True)
        self.t_about.SetSizer(self.about_layout_V1)
        self.t_about.Layout()

        ## List of credits
        self.credits = ListCtrl(t_credits)
        self.credits.SetSingleStyle(wx.LC_REPORT)
        self.credits.InsertColumn(0, GT(u'Name'), width=150)
        self.credits.InsertColumn(1, GT(u'Job'), width=200)
        self.credits.InsertColumn(2, GT(u'Email'), width=240)

        credits_sizer = BoxSizer(wx.VERTICAL)
        credits_sizer.Add(self.credits, 1, wx.EXPAND)

        t_credits.SetAutoLayout(True)
        t_credits.SetSizer(credits_sizer)
        t_credits.Layout()

        ## Changelog text area
        self.changelog = TextAreaPanel(t_changelog, style=wx.TE_READONLY)
        self.changelog.SetFont(MONOSPACED_MD)

        log_sizer = BoxSizer(wx.VERTICAL)
        log_sizer.Add(self.changelog, 1, wx.EXPAND)

        t_changelog.SetSizer(log_sizer)
        t_changelog.Layout()

        ## Licensing information text area
        self.license = TextAreaPanel(t_license, style=wx.TE_READONLY)
        self.license.SetFont(MONOSPACED_MD)

        license_sizer = BoxSizer(wx.VERTICAL)
        license_sizer.Add(self.license, 1, wx.EXPAND)

        t_license.SetSizer(license_sizer)
        t_license.Layout()

        # System info
        sys_info = wx.Panel(tabs, -1)
        tabs.AddPage(sys_info, GT(u'System Information'))

        ## System's <a href="https://www.python.org/">Python</a> version
        self.py_info = wx.StaticText(
            sys_info, -1,
            GT(u'Python version: {}').format(PY_VER_STRING))

        ## System's <a href="https://wxpython.org/">wxPython</a> version
        self.wx_info = wx.StaticText(
            sys_info, -1,
            GT(u'wxPython version: {}').format(WX_VER_STRING))

        ## Debreate's installation prefix
        install_prefix = wx.StaticText(
            sys_info, label=GT(u'App location: {}').format(PATH_app))

        if INSTALLED:
            install_prefix.SetLabel(
                GT(u'Installation prefix: {}').format(PREFIX))

        self.py_info.SetFont(sys_info_font)
        self.wx_info.SetFont(sys_info_font)

        sysinfo_layout_V1 = BoxSizer(wx.VERTICAL)
        sysinfo_layout_V1.AddStretchSpacer()
        sysinfo_layout_V1.Add(self.py_info, 0, wx.ALIGN_CENTER | wx.BOTTOM, 5)
        sysinfo_layout_V1.Add(self.wx_info, 0, wx.ALIGN_CENTER | wx.TOP, 5)
        sysinfo_layout_V1.AddSpacer(20)
        sysinfo_layout_V1.Add(install_prefix, 0, wx.ALIGN_CENTER | wx.TOP, 5)
        sysinfo_layout_V1.AddStretchSpacer()

        if OS_name:
            os_info = wx.StaticText(sys_info, label=OS_name)
            os_info.SetFont(sys_info_font)

            if OS_version:
                os_info.SetLabel(u'{} {}'.format(os_info.LabelText,
                                                 OS_version))

            if OS_codename:
                os_info.SetLabel(u'{} {}'.format(os_info.LabelText,
                                                 OS_codename))

            sysinfo_layout_V1.Insert(1, os_info, 0,
                                     wx.ALIGN_CENTER | wx.BOTTOM, 5)
            sysinfo_layout_V1.InsertSpacer(2, 20)

            if OS_upstream_name:
                os_upstream_info = wx.StaticText(sys_info,
                                                 label=OS_upstream_name)

                if OS_upstream_version:
                    os_upstream_info.SetLabel(u'{} {}'.format(
                        os_upstream_info.LabelText, OS_upstream_version))

                if OS_upstream_codename:
                    os_upstream_info.SetLabel(u'{} {}'.format(
                        os_upstream_info.LabelText, OS_upstream_codename))

                sysinfo_layout_V1.Insert(2, os_upstream_info, 0,
                                         wx.ALIGN_CENTER | wx.BOTTOM, 5)

        sys_info.SetSizer(sysinfo_layout_V1)
        sys_info.Layout()

        # Button to close the dialog
        btn_confirm = CreateButton(self, btnid.CONFIRM)

        sizer = BoxSizer(wx.VERTICAL)
        sizer.Add(tabs, 1, wx.EXPAND)
        sizer.Add(btn_confirm, 0, wx.ALIGN_RIGHT | lyt.PAD_RTB, 5)

        self.SetSizer(sizer)
        self.Layout()

    ## Displays logo in 'about' tab
    #
    #  \param graphic
    #	Path to image file
    def SetGraphic(self, graphic):
        insertion_point = GetContainerItemCount(self.about_layout_V1) - 1

        if not isinstance(graphic, wx.Bitmap):
            graphic = wx.Image(graphic)
            graphic.Rescale(64, 64, wx.IMAGE_QUALITY_HIGH)
            graphic = graphic.ConvertToBitmap()

        self.about_layout_V1.Insert(
            insertion_point, wx.StaticBitmap(self.t_about, wx.ID_ANY, graphic),
            0, wx.ALL | wx.ALIGN_CENTER, 10)

        self.t_about.Layout()

    ## Displays version in 'about' tab
    #
    #  \param version
    #	<b><i>String</i></b> to display
    def SetVersion(self, version):
        insertion_point = GetContainerItemCount(self.about_layout_V1) - 1

        app_label = wx.StaticText(self.t_about,
                                  label=u'{} {}'.format(APP_name, version))
        app_label.SetFont(bigfont)

        self.about_layout_V1.Insert(insertion_point, app_label, 0,
                                    wx.ALL | wx.ALIGN_CENTER, 10)

        self.t_about.Layout()

    ## Display author's name
    #
    #  \param author
    #	<b><i>String</i></b> to display
    def SetAuthor(self, author):
        insertion_point = GetContainerItemCount(self.about_layout_V1) - 1

        self.about_layout_V1.Insert(insertion_point,
                                    wx.StaticText(self.t_about, label=author),
                                    0, wx.ALL | wx.ALIGN_CENTER, 10)

        self.t_about.Layout()

    ## Sets a hotlink to the app's homepage
    #
    #  TODO: Remove: Deprecated, unused
    #
    #  \param URL
    #	URL to open when link is clicked
    def SetWebsite(self, URL):
        self.website.SetLabel(URL)
        self.website.SetURL(URL)

    ## Adds URL hotlinks to about dialog
    #
    #  \param url_list
    #	Label/URL <b><i>Tuple</i></b> (<i>string</i>, <i>string</i>) list
    def SetWebsites(self, url_list):
        insertion_point = GetContainerItemCount(self.about_layout_V1) - 1

        link_layout = BoxSizer(wx.VERTICAL)
        for label, link in url_list:
            link_layout.Add(
                Hyperlink(self.t_about, wx.ID_ANY, label=label, url=link), 0,
                wx.ALIGN_CENTER, 10)

        self.about_layout_V1.Insert(insertion_point, link_layout, 0,
                                    wx.ALL | wx.ALIGN_CENTER, 10)
        self.t_about.Layout()

    ## Displays a description about the app on the 'about' tab
    def SetDescription(self, desc):
        # Place between spacers
        insertion_point = GetContainerItemCount(self.about_layout_V1) - 1

        self.about_layout_V1.Insert(insertion_point,
                                    wx.StaticText(self.t_about, label=desc), 0,
                                    wx.ALL | wx.ALIGN_CENTER, 10)

        self.t_about.Layout()

    ## Adds a developer to the list of credits
    #
    #  \param name
    #	Developer's name
    #  \param email
    #	Developer's email address
    def AddDeveloper(self, name, email):
        next_item = self.credits.GetItemCount()
        self.credits.InsertStringItem(next_item, name)
        self.credits.SetStringItem(next_item, 2, email)
        self.credits.SetStringItem(next_item, 1, GT(u'Developer'))

    ## Adds a packager to the list of credits
    #
    #  \param name
    #	Packager's name
    #  \param email
    #	Packager's email address
    def AddPackager(self, name, email):
        next_item = self.credits.GetItemCount()
        self.credits.InsertStringItem(next_item, name)
        self.credits.SetStringItem(next_item, 2, email)
        self.credits.SetStringItem(next_item, 1, GT(u'Packager'))

    ## Adds a translator to the list of credits
    #
    #  \param name
    #	Translator's name
    #  \param email
    #	Translator's email address
    #  \param lang
    #	Locale code of the translation
    def AddTranslator(self, name, email, lang):
        job = GT(u'Translation')
        job = u'{} ({})'.format(job, lang)
        next_item = self.credits.GetItemCount()
        self.credits.InsertStringItem(next_item, name)
        self.credits.SetStringItem(next_item, 2, email)
        self.credits.SetStringItem(next_item, 1, job)

    ## Adds a general job to the credits list
    #
    #  \param name
    #	Contributer's name
    #  \param job
    #	Job description
    #  \param email
    #	str : Job holder's email address
    def AddJob(self, name, job, email=wx.EmptyString):
        next_item = self.credits.GetItemCount()
        self.credits.InsertStringItem(next_item, name)
        self.credits.SetStringItem(next_item, 1, job)

        if email != wx.EmptyString:
            self.credits.SetStringItem(next_item, 2, email)

    ## Adds list of jobs for single contributer
    #
    #  \param name
    #	<b><i>string</i></b>:
    #	  Contributer's name
    #  \param jobs
    #	<b><i>Tuple</i></b> (<i>string</i>, <i>string</i>):
    #	  List of contributer's jobs
    #  \param email
    #	<b><i>string</i></b>:
    #	  Optional contributer's email address
    def AddJobs(self, name, jobs, email=wx.EmptyString):
        if isinstance(jobs, str) or isinstance(jobs, unicode):
            Logger.Debug(__name__,
                         GT(u'Converting string argument "jobs" to tuple'))
            jobs = (jobs, )

        for x, value in enumerate(jobs):
            next_item = self.credits.GetItemCount()
            if x == 0:
                self.credits.InsertStringItem(next_item, name)
                if email != wx.EmptyString:
                    self.credits.SetStringItem(next_item, 2, email)
            else:
                self.credits.InsertStringItem(next_item, wx.EmptyString)

            self.credits.SetStringItem(next_item, 1, value)

    ## FIXME: Unused?
    def NoResizeCol(self, event=None):
        if event:
            event.Veto()

    ## Sets text to be shown on the 'Changelog' tab
    #
    #  FIXME: Change to create in class constructor
    def SetChangelog(self):
        ## Defines where the changelog is located
        #
        #  By default it is located in the folder 'doc'
        #   under the applications root directory. The
        #   install script or Makefile should change this
        #   to reflect installed path.
        if INSTALLED:
            # FIXME: Read compressed .gz changelog
            CHANGELOG = u'{}/share/doc/debreate/changelog.gz'.format(PREFIX)

        else:
            CHANGELOG = u'{}/docs/changelog'.format(PREFIX)

        if os.path.isfile(CHANGELOG):
            changelog_mimetype = GetFileMimeType(CHANGELOG)

            Logger.Debug(
                __name__,
                GT(u'Changelog mimetype: {}').format(changelog_mimetype))

            # Set log text in case of read error
            log_text = GT(u'Error reading changelog: {}\n\t').format(CHANGELOG)
            log_text = u'{}{}'.format(
                log_text,
                GT(u'Cannot decode, unrecognized mimetype: {}').format(
                    changelog_mimetype))

            if changelog_mimetype == u'application/gzip':
                temp_dir = CreateStage()

                shutil.copy(CHANGELOG, temp_dir)

                CMD_gzip = GetExecutable(u'gzip')

                if CMD_gzip:
                    prev_dir = os.getcwd()
                    os.chdir(temp_dir)

                    gzip_output = commands.getstatusoutput(u'{} -fd {}'.format(
                        CMD_gzip, os.path.basename(CHANGELOG)))

                    Logger.Debug(
                        __name__,
                        GT(u'gzip decompress; Code: {}, Output: {}').format(
                            gzip_output[0], gzip_output[1]))

                    os.chdir(prev_dir)

                changelog_file = os.path.basename(CHANGELOG).split(u'.')[0]
                changelog_file = u'{}/{}'.format(temp_dir, changelog_file)

                if os.path.isfile(changelog_file):
                    log_text = ReadFile(changelog_file)

                RemoveStage(temp_dir)

            elif changelog_mimetype == u'text/plain':
                log_text = ReadFile(CHANGELOG)

            else:
                ShowErrorDialog(log_text, parent=self)

        else:
            log_text = GT(
                u'ERROR: Could not locate changelog file:\n\t\'{}\' not found'.
                format(CHANGELOG))

        self.changelog.SetValue(log_text)
        self.changelog.SetInsertionPoint(0)

    ## Sets text to be shown on the 'License' tab
    def SetLicense(self):
        ## Defines where the LICENSE.txt is located
        #
        #  By default it is located in the folder 'doc'
        #   under the applications root directory. The
        #   install script or Makefile should change this
        #   to reflect installed path.
        if INSTALLED:
            license_path = u'{}/share/doc/debreate/copyright'.format(PREFIX)

        else:
            license_path = u'{}/docs/LICENSE.txt'.format(PREFIX)

        if os.path.isfile(license_path):
            lic_text = ReadFile(license_path)

        else:
            lic_text = GT(
                u'ERROR: Could not locate license file:\n\t\'{}\' not found'.
                format(license_path))
            lic_text += u'\n\nCopyright © {} {} <{}>'.format(
                GetYear(), AUTHOR_name, AUTHOR_email)
            lic_text += u'\n\nhttps://opensource.org/licenses/MIT'

        self.license.SetValue(lic_text)
        self.license.SetInsertionPoint(0)

    ## Defines action to take when 'Ok' button is press
    #
    #  Closes the dialog.
    #
    #  \param event
    #		<b><em>(wx.EVT_BUTTON)</em></b>
    def OnOk(self, event=None):
        self.Close()