Example #1
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)
Example #2
0
class DebianScript(wx.Panel):
	## Constructor
	#
	#  \param parent
	#	The <b><i>wx.Window</i></b> parent instance
	#  \param scriptId
	#	Unique <b><i>integer</i></b> identifier for script
	def __init__(self, parent, scriptId):
		wx.Panel.__init__(self, parent, scriptId)

		## Filename used for exporting script
		self.FileName = id_definitions[scriptId].lower()

		## String name used for display in the application
		self.ScriptName = None
		self.SetScriptName()

		shell_options = []
		shell_options.append(u'/bin/sh')  # Place /bin/sh as first item
		for P in u'/bin/', u'/usr/bin/', u'/usr/bin/env ':
			for S in sorted(shell_descriptions, key=GS.lower):
				if S == u'sh':
					pass

				else:
					shell_options.append(P + S)

		self.Shell = ComboBoxESS(self, self.GetId(), choices=shell_options, monospace=True,
				defaultValue=u'/bin/bash')

		self.ScriptBody = TextAreaPanelESS(self, self.GetId(), monospace=True)
		self.ScriptBody.EnableDropTarget()

		# *** Layout *** #

		lyt_shell = BoxSizer(wx.HORIZONTAL)
		lyt_shell.Add(wx.StaticText(self, label=u'#!'), 0, lyt.ALGN_CV|wx.RIGHT, 5)
		lyt_shell.Add(self.Shell, 1)

		lyt_main = BoxSizer(wx.VERTICAL)
		lyt_main.Add(lyt_shell, 0)
		lyt_main.Add(self.ScriptBody, 1, wx.EXPAND|wx.TOP, 5)

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

		# Scripts are hidden by default
		self.Hide()


	## Exports the script to a text file
	#
	#  \param out_dir
	#	Target directory of output file
	#  \param executable
	#	If <b><i>True</i></b>, sets the files executable bit
	#  \param build
	#	If <b><i>True</i></b>, format output for final build
	def Export(self, out_dir, executable=True, build=False):
		if not os.path.isdir(out_dir):
			Logger.Error(__name__, GT(u'Directory not available: {}'.format(out_dir)))

			return (ERR_DIR_NOT_AVAILABLE, __name__)

		if build:
			absolute_filename = ConcatPaths((out_dir, self.FileName))

		else:
			filename = u'{}-{}'.format(page_ids[self.Parent.GetId()].upper(), self.FileName)
			absolute_filename = ConcatPaths((out_dir, filename))

		script_text = u'{}\n\n{}'.format(self.GetShebang(), self.ScriptBody.GetValue())

		WriteFile(absolute_filename, script_text)

		if not os.path.isfile(absolute_filename):
			Logger.Error(__name__, GT(u'Could not write to file: {}'.format(absolute_filename)))

			return (ERR_FILE_WRITE, __name__)

		if executable:
			os.chmod(absolute_filename, 0755)

		return (0, None)


	## Retrieves the filename to use for exporting
	#
	#  \return
	#	Script filename
	def GetFilename(self):
		return self.FileName


	## Retrieves the script's name for display
	#
	#  \return
	#	<b><i>String</i></b> representation of script's name
	def GetName(self):
		return self.ScriptName


	## Retrieves the description of a shell for display
	#
	#  \return
	#	Description or <b><i>None</i></b> if using custom shell
	def GetSelectedShellDescription(self):
		selected_shell = self.Shell.GetValue()

		if selected_shell in shell_descriptions:
			return shell_descriptions[selected_shell]

		return None


	## Retrieves the shebang/shell line
	def GetShebang(self):
		shell = self.Shell.GetValue()

		if shell.startswith(u'/usr/bin/env '):
			shell = u'#!{}\nset -e'.format(shell)

		else:
			shell = u'#!{} -e'.format(shell)

		return shell


	## Retrieves the text body of the script
	def GetValue(self):
		return self.ScriptBody.GetValue()


	## Checks if the script is used & can be exported
	#
	#  The text area is checked &, if not empty, signifies that
	#  the user want to export the script.
	#
	#  \return
	#	<b><i>True</i></b> if text area is not empty, <b><i>False</i></b> otherwise
	def IsOkay(self):
		return not TextIsEmpty(self.ScriptBody.GetValue())


	## Resets all members to default values
	def Reset(self):
		self.Shell.SetStringSelection(self.Shell.GetDefaultValue())
		self.ScriptBody.Clear()


	## Sets the name of the script to be displayed
	#
	#  Sets the displayed script name to a value of either 'Pre Install',
	#  'Pre Uninstall', 'Post Install', or 'Post Uninstall'. 'self.FileName'
	#  is used to determine the displayed name.
	#  TODO: Add strings to GetText translations
	def SetScriptName(self):
		prefix = None
		suffix = None

		if u'pre' in self.FileName:
			prefix = u'Pre'
			suffix = self.FileName.split(u'pre')[1]

		elif u'post' in self.FileName:
			prefix = u'Post'
			suffix = self.FileName.split(u'post')[1]

		if suffix.lower() == u'inst':
			suffix = u'Install'

		elif suffix.lower() == u'rm':
			suffix = u'Uninstall'

		if (prefix != None) and (suffix != None):
			self.ScriptName = GT(u'{}-{}'.format(prefix, suffix))


	## Sets the shell/shebang line to use for script
	#
	#  \param shell
	#	Path to desired shell
	#  \param forced
	#	???
	def SetShell(self, shell, forced=False):
		if forced:
			self.Shell.SetValue(shell)
			return

		self.Shell.SetStringSelection(shell)


	## Fills the script
	#
	#  \param value
	#	Text to be entered into the script body
	def SetValue(self, value):
		self.ScriptBody.SetValue(value)
Example #3
0
class DebianScript(wx.Panel):
    ## Constructor
    #
    #  \param parent
    #	The <b><i>wx.Window</i></b> parent instance
    #  \param scriptId
    #	Unique <b><i>integer</i></b> identifier for script
    def __init__(self, parent, scriptId):
        wx.Panel.__init__(self, parent, scriptId)

        ## Filename used for exporting script
        self.FileName = id_definitions[scriptId].lower()

        ## String name used for display in the application
        self.ScriptName = None
        self.SetScriptName()

        self.ScriptBody = TextAreaPanelESS(self, self.GetId(), monospace=True)
        self.ScriptBody.EnableDropTarget()

        self.Check = None

        # *** Layout *** #

        lyt_main = BoxSizer(wx.VERTICAL)
        lyt_main.Add(self.ScriptBody, 1, wx.EXPAND | wx.TOP, 5)

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

        # Scripts are hidden by default
        self.Hide()

    ## TODO: Doxygen
    def Disable(self):
        return self.Enable(False)

    ## TODO: Doxygen
    def Enable(self, enable=True):
        return self.ScriptBody.Enable(enable)

    ## Retrieves the filename to use for exporting
    #
    #  \return
    #	Script filename
    def GetFilename(self):
        return self.FileName

    ## Retrieves the script's name for display
    #
    #  \return
    #	<b><i>String</i></b> representation of script's name
    def GetName(self):
        return self.ScriptName

    ## Retrieves the text body of the script
    def GetValue(self):
        return self.ScriptBody.GetValue()

    ## TODO: Doxygen
    def Hide(self):
        if self.Check:
            self.Check.Hide()

        return wx.Panel.Hide(self)

    ## TODO: Doxygen
    def IsChecked(self):
        # FIXME: Should check if field is wx.CheckBox
        if self.Check:
            return self.Check.IsChecked()

        return False

    ## TODO: Doxygen
    def IsEnabled(self):
        return FieldEnabled(self.ScriptBody)

    ## Checks if the script is used & can be exported
    #
    #  The text area is checked &, if not empty, signifies that
    #  the user want to export the script.
    #
    #  \return
    #	<b><i>True</i></b> if text area is not empty, <b><i>False</i></b> otherwise
    def IsOkay(self):
        return not TextIsEmpty(self.ScriptBody.GetValue())

    ## Resets all members to default values
    def Reset(self):
        self.ScriptBody.Clear()
        if self.Check:
            self.Check.Reset()

    ## TODO: Doxygen
    def SetCheckBox(self, check_box):
        self.Check = check_box

    ## TODO: Doxygen
    def SetChecked(self, value=True):
        self.Check.SetValue(value)

    ## Sets the name of the script to be displayed
    #
    #  Sets the displayed script name to a value of either 'Pre Install',
    #  'Pre Uninstall', 'Post Install', or 'Post Uninstall'. 'self.FileName'
    #  is used to determine the displayed name.
    #  TODO: Add strings to GetText translations
    def SetScriptName(self):
        prefix = None
        suffix = None

        if u'pre' in self.FileName:
            prefix = u'Pre'
            suffix = self.FileName.split(u'pre')[1]

        elif u'post' in self.FileName:
            prefix = u'Post'
            suffix = self.FileName.split(u'post')[1]

        if suffix.lower() == u'inst':
            suffix = u'Install'

        elif suffix.lower() == u'rm':
            suffix = u'Uninstall'

        if (prefix != None) and (suffix != None):
            self.ScriptName = GT(u'{}-{}'.format(prefix, suffix))

    ## Fills the script
    #
    #  \param value
    #	Text to be entered into the script body
    def SetValue(self, value):
        self.ScriptBody.SetValue(value)

    ## TODO: Doxygen
    def Show(self):
        if self.Check:
            self.Check.Show()

        return wx.Panel.Show(self)