예제 #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)
예제 #2
0
class Page(WizardPage):
	## Constructor
	#
	#  \param parent
	#	Parent <b><i>wx.Window</i></b> instance
	def __init__(self, parent):
		WizardPage.__init__(self, parent, pgid.DEPENDS)

		## Override default label
		self.Label = GT(u'Dependencies and Conflicts')

		# Bypass checking this page for build
		self.prebuild_check = False

		# Buttons to open, save, & preview control file
		self.btn_open = CreateButton(self, btnid.BROWSE, GT(u'Browse'), u'browse', name=u'btn browse')
		self.btn_save = CreateButton(self, btnid.SAVE, GT(u'Save'), u'save', name=u'btn save')
		self.btn_preview = CreateButton(self, btnid.PREVIEW, GT(u'Preview'), u'preview', name=u'btn preview')

		txt_package = wx.StaticText(self, label=GT(u'Dependency/Conflict Package Name'), name=u'package')
		txt_version = wx.StaticText(self, label=GT(u'Version'), name=u'version')

		self.ti_package = TextArea(self, size=(300,25), name=u'package')

		opts_operator = (
			u'>=',
			u'<=',
			u'=',
			u'>>',
			u'<<',
			)

		self.sel_operator = Choice(self, choices=opts_operator, name=u'operator')

		self.ti_version = TextArea(self, name=u'version')

		self.ti_package.SetSize((100,50))

		pnl_categories = BorderedPanel(self)

		self.DefaultCategory = u'Depends'

		rb_dep = wx.RadioButton(pnl_categories, label=GT(u'Depends'), name=self.DefaultCategory, style=wx.RB_GROUP)
		rb_pre = wx.RadioButton(pnl_categories, label=GT(u'Pre-Depends'), name=u'Pre-Depends')
		rb_rec = wx.RadioButton(pnl_categories, label=GT(u'Recommends'), name=u'Recommends')
		rb_sug = wx.RadioButton(pnl_categories, label=GT(u'Suggests'), name=u'Suggests')
		rb_enh = wx.RadioButton(pnl_categories, label=GT(u'Enhances'), name=u'Enhances')
		rb_con = wx.RadioButton(pnl_categories, label=GT(u'Conflicts'), name=u'Conflicts')
		rb_rep = wx.RadioButton(pnl_categories, label=GT(u'Replaces'), name=u'Replaces')
		rb_break = wx.RadioButton(pnl_categories, label=GT(u'Breaks'), name=u'Breaks')

		self.categories = (
			rb_dep, rb_pre, rb_rec,
			rb_sug, rb_enh, rb_con,
			rb_rep, rb_break,
		)

		# Buttons to add and remove dependencies from the list
		btn_add = CreateButton(self, btnid.ADD)
		btn_append = CreateButton(self, btnid.APPEND)
		btn_remove = CreateButton(self, btnid.REMOVE)
		btn_clear = CreateButton(self, btnid.CLEAR)

		# ----- List
		self.lst_deps = ListCtrlESS(self, inputid.LIST, name=u'list')
		self.lst_deps.SetSingleStyle(wx.LC_REPORT)
		self.lst_deps.InsertColumn(0, GT(u'Category'), width=150)
		self.lst_deps.InsertColumn(1, GT(u'Package(s)'))

		# wx 3.0 compatibility
		if wx.MAJOR_VERSION < 3:
			self.lst_deps.SetColumnWidth(100, wx.LIST_AUTOSIZE)

		SetPageToolTips(self)

		# *** Event Handling *** #

		wx.EVT_KEY_DOWN(self.ti_package, self.SetDepends)
		wx.EVT_KEY_DOWN(self.ti_version, self.SetDepends)

		btn_add.Bind(wx.EVT_BUTTON, self.SetDepends)
		btn_append.Bind(wx.EVT_BUTTON, self.SetDepends)
		btn_remove.Bind(wx.EVT_BUTTON, self.SetDepends)
		btn_clear.Bind(wx.EVT_BUTTON, self.SetDepends)

		wx.EVT_KEY_DOWN(self.lst_deps, self.SetDepends)

		# *** Layout *** #

		LEFT_BOTTOM = lyt.ALGN_LB

		lyt_top = wx.GridBagSizer()
		lyt_top.SetCols(6)
		lyt_top.AddGrowableCol(3)

		# Row 1
		lyt_top.Add(txt_package, (1, 0), flag=LEFT_BOTTOM)
		lyt_top.Add(txt_version, (1, 2), flag=LEFT_BOTTOM)
		lyt_top.Add(self.btn_open, (0, 3), (4, 1), wx.ALIGN_RIGHT)
		lyt_top.Add(self.btn_save, (0, 4), (4, 1))
		lyt_top.Add(self.btn_preview, (0, 5), (4, 1))

		# Row 2
		lyt_top.Add(self.ti_package, (2, 0), flag=wx.ALIGN_CENTER_VERTICAL)
		lyt_top.Add(self.sel_operator, (2, 1), flag=wx.ALIGN_CENTER_VERTICAL)
		lyt_top.Add(self.ti_version, (2, 2), flag=wx.ALIGN_CENTER_VERTICAL)

		lyt_categories = wx.GridSizer(4, 2, 5, 5)

		for C in self.categories:
			lyt_categories.Add(C, 0)

		pnl_categories.SetAutoLayout(True)
		pnl_categories.SetSizer(lyt_categories)
		pnl_categories.Layout()

		lyt_buttons = BoxSizer(wx.HORIZONTAL)

		lyt_buttons.AddMany((
			(btn_add, 0, wx.ALIGN_CENTER_VERTICAL),
			(btn_append, 0, wx.ALIGN_CENTER_VERTICAL),
			(btn_remove, 0, wx.ALIGN_CENTER_VERTICAL),
			(btn_clear, 0, wx.ALIGN_CENTER_VERTICAL),
			))

		lyt_mid = wx.GridBagSizer()
		lyt_mid.SetCols(2)

		lyt_mid.Add(wx.StaticText(self, label=u'Categories'), (0, 0), (1, 1), LEFT_BOTTOM)
		lyt_mid.Add(pnl_categories, (1, 0), flag=wx.RIGHT, border=5)
		lyt_mid.Add(lyt_buttons, (1, 1), flag=wx.ALIGN_BOTTOM)

		lyt_list = BoxSizer(wx.HORIZONTAL)
		lyt_list.Add(self.lst_deps, 1, wx.EXPAND)

		lyt_main = BoxSizer(wx.VERTICAL)
		# Spacer is less on this page because text is aligned to bottom
		lyt_main.AddSpacer(5)
		lyt_main.Add(lyt_top, 0, wx.EXPAND|lyt.PAD_LR, 5)
		lyt_main.Add(lyt_mid, 0, lyt.PAD_LR, 5)
		lyt_main.Add(lyt_list, 1, wx.EXPAND|wx.ALL, 5)

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


	## Add a category & dependency to end of list
	#
	#  \param category
	#	Category label
	#  \param value
	#	Dependency value
	def AppendDependency(self, category, value):
		self.lst_deps.AppendStringItem((category, value))


	## Retrieves the default category to use
	def GetDefaultCategory(self):
		return self.DefaultCategory


	## Reads & parses page data from a formatted text file
	#
	#  \param filename
	#	File path to open
	#  \see wiz.wizard.WizardPage.ImportFromFile
	def ImportFromFile(self, d_type, d_string):
		Logger.Debug(__name__, GT(u'Importing {}: {}'.format(d_type, d_string)))

		values = d_string.split(u', ')

		for V in values:
			self.lst_deps.InsertStringItem(0, d_type)
			self.lst_deps.SetStringItem(0, 1, V)


	## \see wiz.wizard.WizardPage.InitPage
	def InitPage(self):
		control_page = GetPage(pgid.CONTROL)
		self.btn_open.Bind(wx.EVT_BUTTON, control_page.OnBrowse)
		self.btn_save.Bind(wx.EVT_BUTTON, control_page.OnSave)
		self.btn_preview.Bind(wx.EVT_BUTTON, control_page.OnPreviewControl)

		return True


	## Resets all fields on page to default values
	def Reset(self):
		for C in self.categories:
			if C.GetName() == self.DefaultCategory:
				C.SetValue(True)
				break

		self.ti_package.Clear()
		self.sel_operator.Reset()
		self.ti_version.Clear()
		self.lst_deps.DeleteAllItems()


	## Adds/Appends/Removes dependency to list
	def SetDepends(self, event=None):
		try:
			key_id = event.GetKeyCode()

		except AttributeError:
			key_id = event.GetEventObject().GetId()

		addname = self.ti_package.GetValue()
		oper = self.sel_operator.GetStringSelection()
		ver = self.ti_version.GetValue()
		addver = u'({}{})'.format(oper, ver)

		if key_id in (btnid.ADD, wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER):
			if TextIsEmpty(addname):
				return

			category = self.GetDefaultCategory()
			for C in self.categories:
				if C.GetValue():
					category = C.GetName()
					break

			if TextIsEmpty(ver):
				self.AppendDependency(category, addname)

			else:
				self.AppendDependency(category, u'{} {}'.format(addname, addver))

		elif key_id == btnid.APPEND:
			selected_count = self.lst_deps.GetSelectedItemCount()

			Logger.Debug(__name__, u'Appending to {} items'.format(selected_count))

			if not TextIsEmpty(addname) and self.lst_deps.GetItemCount() and selected_count:
				selected_rows = self.lst_deps.GetSelectedIndexes()

				if DebugEnabled():
					Logger.Debug(__name__, u'Selected rows:')
					for R in selected_rows:
						print(u'\t{}'.format(R))

				for listrow in selected_rows:
					Logger.Debug(__name__, u'Setting list row: {}'.format(listrow))

					# Get item from second column
					colitem = self.lst_deps.GetItem(listrow, 1)
					# Get the text from that item
					prev_text = colitem.GetText()

					if not TextIsEmpty(ver):
						new_text = u'{} | {} {}'.format(prev_text, addname, addver)

					else:
						new_text = u'{} | {}'.format(prev_text, addname)

					Logger.Debug(__name__, u'Appended item: {}'.format(new_text))

					self.lst_deps.SetStringItem(listrow, 1, new_text)

		elif key_id in (btnid.REMOVE, wx.WXK_DELETE):
			self.lst_deps.RemoveSelected()

		elif key_id == btnid.CLEAR:
			if self.lst_deps.GetItemCount():
				if ConfirmationDialog(GetMainWindow(), GT(u'Confirm'),
						GT(u'Clear all dependencies?')).ShowModal() in (wx.ID_OK, wx.OK):
					self.lst_deps.DeleteAllItems()

		if event:
			event.Skip()


	## Sets the page's fields data
	#
	#  \param data
	#	Text to parse for field values
	def Set(self, data):
		self.lst_deps.DeleteAllItems()
		for item in data:
			item_count = len(item)
			while item_count > 1:
				item_count -= 1
				self.lst_deps.InsertStringItem(0, item[0])
				self.lst_deps.SetStringItem(0, 1, item[item_count])