def OnBuild(self, event=None): # Build preparation ret_code, build_prep = self.BuildPrep() if ret_code == dbrerrno.ECNCLD: return if ret_code == dbrerrno.FEMPTY: err_dia = DetailedMessageDialog( GetMainWindow(), GT(u'Cannot Continue'), ICON_EXCLAMATION, text=u'{}\n{}'.format( GT(u'One of the required fields is empty:'), build_prep)) err_dia.ShowModal() err_dia.Destroy() return if ret_code == dbrerrno.SUCCESS: task_list, build_path, filename = build_prep # Actual build ret_code, result = self.Build(task_list, build_path, filename) # FIXME: Check .deb package timestamp to confirm build success if ret_code == dbrerrno.SUCCESS: DetailedMessageDialog( GetMainWindow(), GT(u'Success'), ICON_INFORMATION, text=GT(u'Package created successfully')).ShowModal() # Installing the package if FieldEnabled( self.chk_install) and self.chk_install.GetValue(): self.InstallPackage(result) return if result: ShowErrorDialog(GT(u'Package build failed'), result) else: ShowErrorDialog(GT(u'Package build failed with unknown error')) return if build_prep: ShowErrorDialog(GT(u'Build preparation failed'), build_prep) else: ShowErrorDialog(GT(u'Build preparation failed with unknown error'))
def OnExportLauncher(self, event=None): Logger.Debug(__name__, u'Export launcher ...') export = GetFileSaveDialog(GetMainWindow(), GT(u'Save Launcher')) if ShowDialog(export): target = export.GetPath() # Create a backup file # FIXME: Create backup files in WriteFile function? overwrite = False if os.path.isfile(target): backup = u'{}.backup'.format(target) shutil.copy(target, backup) overwrite = True try: self.ExportToFile(target) if overwrite: os.remove(backup) except UnicodeEncodeError: detail1 = GT( u'Unfortunately Debreate does not support unicode yet.') detail2 = GT( u'Remove any non-ASCII characters from your project.') ShowErrorDialog(GT(u'Save failed'), u'{}\n{}'.format(detail1, detail2), title=GT(u'Unicode Error')) os.remove(target) # Restore from backup shutil.move(backup, target)
def SetCategory(self, event=None): try: ID = event.GetKeyCode() except AttributeError: ID = event.GetEventObject().GetId() cat = GetField(self, inputid.CAT).GetValue() cat = cat.split() cat = u''.join(cat) lst_categories = GetField(self, listid.CAT) if ID in (wx.ID_ADD, wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER): lst_categories.InsertStringItem(lst_categories.GetItemCount(), cat) elif ID in (wx.ID_REMOVE, wx.WXK_DELETE): if lst_categories.GetItemCount( ) and lst_categories.GetSelectedItemCount(): cur_cat = lst_categories.GetFirstSelected() lst_categories.DeleteItem(cur_cat) elif ID == wx.ID_CLEAR: if lst_categories.GetItemCount(): if ConfirmationDialog( GetMainWindow(), GT(u'Confirm'), GT(u'Clear categories?')).ShowModal() in (wx.ID_OK, wx.OK): lst_categories.DeleteAllItems() if event: event.Skip()
def WriteMD5(stage_dir, parent=None): CMD_md5sum = GetExecutable(u'md5sum') # Show an error if the 'md5sum' command does not exist # This is only a failsafe & should never actually occur if not CMD_md5sum: if not parent: parent = GetMainWindow() md5_label = GetField(pgid.BUILD, chkid.MD5).GetLabel() err_msg1 = GT(u'The "md5sum" command was not found on the system.') err_msg2 = GT(u'Uncheck the "{}" box.').format(md5_label) err_msg3 = GT( u'Please report this error to one of the following addresses:') err_url1 = u'https://github.com/AntumDeluge/debreate/issues' err_url2 = u'https://sourceforge.net/p/debreate/bugs/' Logger.Error( __name__, u'{} {} {}\n\t{}\n\t{}'.format(err_msg1, err_msg2, err_msg3, err_url1, err_url2)) md5_error = ErrorDialog(parent, text=u'{}\n{}\n\n{}'.format( err_msg1, err_msg2, err_msg3)) md5_error.AddURL(err_url1) md5_error.AddURL(err_url2) md5_error.ShowModal() return None temp_list = [] md5_list = [] # Final list used to write the md5sum file for ROOT, DIRS, FILES in os.walk(stage_dir): # Ignore the 'DEBIAN' directory if os.path.basename(ROOT) == u'DEBIAN': continue for F in FILES: F = u'{}/{}'.format(ROOT, F) md5 = GetCommandOutput(CMD_md5sum, (u'-t', F)) Logger.Debug(__name__, u'WriteMD5: GetCommandOutput: {}'.format(md5)) temp_list.append(md5) for item in temp_list: # Remove [stage_dir] from the path name in the md5sum so that it has a # true unix path # e.g., instead of "/myfolder_temp/usr/local/bin", "/usr/local/bin" sum_split = item.split(u'{}/'.format(stage_dir)) sum_join = u''.join(sum_split) md5_list.append(sum_join) # Create the md5sums file in the "DEBIAN" directory return WriteFile(u'{}/DEBIAN/md5sums'.format(stage_dir), u'{}\n'.format(u'\n'.join(md5_list)))
def GetDirDialog(parent, title): if parent == None: parent = GetMainWindow() dir_open = StandardDirDialog(parent, title) return dir_open
def ShowMessageDialog(text, title=GT(u'Message'), details=None, module=None, parent=None, linewrap=0): if not parent: parent = GetMainWindow() logger_text = text if isinstance(text, (tuple, list)): logger_text = u'; '.join(text) text = u'\n'.join(text) if details: logger_text = u'{}:\n{}'.format(logger_text, details) message_dialog = DetailedMessageDialog(parent, title, ICON_INFORMATION, text, linewrap=linewrap) if details: message_dialog.SetDetails(details) Logger.Debug(module, logger_text) message_dialog.ShowModal()
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))
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()
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)
def ExecuteCommand(cmd, args=[], elevate=False, pword=wx.EmptyString): if elevate and pword.strip(u' \t\n') == wx.EmptyString: return (None, GT(u'Empty password')) CMD_sudo = GetExecutable(u'sudo') if not CMD_sudo: return (None, GT(u'Super user command (sudo) not available')) main_window = GetMainWindow() if isinstance(args, (unicode, str)): cmd_line = [ args, ] else: cmd_line = list(args) cmd_line.insert(0, cmd) main_window.Enable(False) # FIXME: Better way to execute commands if elevate: cmd_line.insert(0, u'sudo') cmd_line.insert(1, u'-S') cmd_line = u' '.join(cmd_line) cmd_output = os.popen(u'echo {} | {}'.format(pword, cmd_line)).read() else: cmd_output = subprocess.Popen(cmd_line, stdout=PIPE, stderr=PIPE) cmd_output.wait() main_window.Enable(True) stdout = wx.EmptyString if isinstance(cmd_output, subprocess.Popen): if cmd_output.stdout: stdout = cmd_output.stdout if cmd_output.stderr: if stdout == wx.EmptyString: stdout = cmd_output.stderr else: stdout = u'{}\n{}'.format(stdout, cmd_output.stderr) returncode = cmd_output.returncode else: stdout = cmd_output returncode = 0 return (returncode, stdout)
def OnClearCategories(self, event=None): cats = GetField(self, listid.CAT) if cats.HasSelected(): clear = ConfirmationDialog(GetMainWindow(), GT(u'Confirm'), GT(u'Clear categories?')) if clear.Confirmed(): cats.Clear()
def OnClearCategories(self, event=None): cats = GetField(self, listid.CAT) if cats.GetItemCount(): clear = ConfirmationDialog(GetMainWindow(), GT(u'Confirm'), GT(u'Clear categories?')) if clear.Confirmed(): cats.DeleteAllItems()
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
def OnSave(self, event=None): # Get data to write to control file control = self.GetCtrlInfo() save_dialog = GetFileSaveDialog(GetMainWindow(), GT(u'Save Control Information')) save_dialog.SetFilename(u'control') if ShowDialog(save_dialog): # Be sure not to strip trailing newline (dpkg is picky) WriteFile(save_dialog.GetPath(), control, noStrip=u'\n')
def AddPage(self, page): err_msg = None err_det = None if not isinstance(page, WizardPage): try: pagemod = u'wizbin.{}'.format(page) page = mimport(pagemod).Page(self) except ImportError: err_msg = u'module does not exist' err_det = traceback.format_exc() lyt_main = self.GetSizer() if not err_msg: # Must already be child if not isinstance(page, WizardPage): err_msg = u'not WizardPage instance' elif page not in self.GetChildren(): err_msg = u'not child of wizard' elif page in lyt_main.GetChildWindows(): err_msg = u'page is already added to wizard' if err_msg: err_msg = u'Cannot add page, {}'.format(err_msg) if err_det: ShowErrorDialog(err_msg, err_det) else: ShowErrorDialog(err_msg) return main_window = GetMainWindow() lyt_main.Add(page, 1, wx.EXPAND) self.Pages.append(page) # Add to page menu page_menu = GetMenu(menuid.PAGE) page_menu.AppendItem( wx.MenuItem(page_menu, page.Id, page.GetTitle(), kind=wx.ITEM_RADIO)) # Bind menu event to ID wx.EVT_MENU(main_window, page.Id, main_window.OnMenuChangePage)
def ImportFromFile(self, filename): Logger.Debug(__name__, GT(u'Importing page info from {}').format(filename)) if not os.path.isfile(filename): return dbrerrno.ENOENT files_data = ReadFile(filename, split=True) # Lines beginning with these characters will be ignored ignore_characters = ( u'', u' ', u'#', ) target = None targets_list = [] for L in files_data: if not TextIsEmpty(L) and L[0] not in ignore_characters: if u'[' in L and u']' in L: target = L.split(u'[')[-1].split(u']')[0] continue if target: executable = (len(L) > 1 and L[-2:] == u' *') if executable: L = L[:-2] targets_list.append((target, L, executable)) missing_files = [] for T in targets_list: # FIXME: Create method in FileList class to retrieve all missing files if not os.path.exists(T[1]): missing_files.append(T[1]) source_file = os.path.basename(T[1]) source_dir = os.path.dirname(T[1]) self.lst_files.AddFile(source_file, source_dir, T[0], executable=T[2]) if len(missing_files): main_window = GetMainWindow() err_line1 = GT(u'The following files/folders are missing from the filesystem.') err_line2 = GT(u'They will be highlighted on the Files page.') DetailedMessageDialog(main_window, title=GT(u'Warning'), icon=ICON_ERROR, text=u'\n'.join((err_line1, err_line2)), details=u'\n'.join(missing_files)).ShowModal() return 0
def __init__(self, parent=None, ID=wx.ID_ANY, title=GT(u'Title'), pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE, name=wx.DialogNameStr): if parent == None: parent = GetMainWindow() wx.Dialog.__init__(self, parent, ID, title, pos, size, style | wx.RESIZE_BORDER, name)
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!')
def SetTabName(self, index=-1, rename=False, checkBox=None, checked=False): getname = TextEntryDialog(GetMainWindow(), GT(u'Name for new page')) new_name = None if not rename and checkBox: check_box = CheckBox(getname, label=checkBox) check_box.SetValue(checked) sizer = getname.GetSizer() insert_point = len(sizer.GetChildren()) - 1 sizer.InsertSpacer(insert_point, 5) sizer.Insert(insert_point + 1, check_box, 0, wx.LEFT, 16) getname.SetSize(sizer.GetMinSize()) getname.Fit() getname.CenterOnParent() valid_name = False while not valid_name: if new_name and TextIsEmpty(new_name): getname.Clear() # User cancelled if not ShowDialog(getname): return False else: new_name = getname.GetValue() valid_name = self._title_is_ok(new_name) if valid_name: break ShowErrorDialog(GT(u'Page name cannot contain whitespace'), warn=True) if rename: if index < 0: return False return self.Tabs.SetPageText(index, new_name) if checkBox: return self.AddPage(new_name, checkBox=check_box) return self.AddPage(new_name)
def OnLoadLauncher(self, event=None): dia = GetFileOpenDialog(GetMainWindow(), GT(u'Open Launcher')) if ShowDialog(dia): path = dia.GetPath() data = ReadFile(path, split=True, convert=list) # Remove unneeded lines if data[0] == u'[Desktop Entry]': data = data[1:] self.Reset() # First line needs to be changed to '1' data.insert(0, u'1') self.Set(u'\n'.join(data))
def GetFileSaveDialog(parent, title, wildcard=wx.FileSelectorDefaultWildcardStr, extension=None): if parent == None: parent = GetMainWindow() wildcard = _format_wildcard(wildcard) file_save = StandardFileDialog(parent, title, defaultExt=extension, wildcard=wildcard, style=wx.FD_SAVE) return file_save
def SetPages(self, pages): self.ID_FIRST = pages[0].GetId() self.ID_LAST = pages[-1].GetId() main_window = GetMainWindow() # Make sure all pages are hidden children = self.GetChildren() for child in children: if child not in self.permanent_children: child.Hide() # Remove any current pages from the wizard self.ClearPages() if not isinstance(pages, (list, tuple)): # FIXME: Should not raise error here??? raise TypeError( u'Argument 2 of Wizard.SetPages() must be List or Tuple') for PAGE in pages: if PAGE.GetId() != pgid.GREETING: self.Pages.append(PAGE) self.PagesIds[PAGE.GetId()] = PAGE.GetName().upper() self.GetSizer().Insert(1, PAGE, 1, wx.EXPAND) page_id = PAGE.GetId() # Add pages to main menu page_menu = main_window.GetMenu(menuid.PAGE) page_menu.AppendItem( wx.MenuItem(page_menu, page_id, PAGE.GetTitle(), kind=wx.ITEM_RADIO)) # Bind menu event to ID wx.EVT_MENU(main_window, page_id, main_window.OnMenuChangePage) # Initailize functions that can only be called after all pages are constructed for PAGE in pages: PAGE.InitPage() self.ShowPage(self.ID_FIRST) self.Layout()
def OnLoadLauncher(self, event=None): dia = wx.FileDialog(GetMainWindow(), GT(u'Open Launcher'), os.getcwd(), style=wx.FD_CHANGE_DIR) if ShowDialog(dia): path = dia.GetPath() data = ReadFile(path, split=True) # Remove unneeded lines if data[0] == u'[Desktop Entry]': data = data[1:] self.Reset() self.SetLauncherData(u'\n'.join(data))
def OnOtherRemove(self, event=None): pnl_other = GetField(self, inputid.OTHER) # FIXME: Show confirmation dialog if pnl_other: if pnl_other.HasSelected(): remove = ConfirmationDialog( GetMainWindow(), GT(u'Custom Fields'), GT(u'Remove all selected custom fields?')) if remove.Confirmed(): pnl_other.RemoveSelected() btn_remove = GetField(self, wx.ID_REMOVE) if btn_remove and FieldEnabled(btn_remove): btn_remove.Enable(pnl_other.HasSelected())
def Destroy(self, *args, **kwargs): # Re-enable parent/main window if previously disabled # ???: May not be necessary main_window = GetMainWindow() if not FieldEnabled(main_window): Logger.Debug(__name__, u'Re-enabling main window') main_window.Enable() if self.Parent and not FieldEnabled(self.Parent): Logger.Debug(__name__, u'Re-enabling parent') self.Parent.Enable() if wx.MAJOR_VERSION < 3: self.EndModal(0) return wx.ProgressDialog.Destroy(self, *args, **kwargs)
def AddPaths(self, dirs, fileCount=None, showDialog=False): target = self.GetTarget() if fileCount == None: fileCount = 0 for D in dirs: for F in dirs[D]: fileCount += 1 progress = None Logger.Debug(__name__, u'Adding {} files ...'.format(fileCount)) if showDialog: progress = ProgressDialog(GetMainWindow(), GT(u'Adding Files'), maximum=fileCount, style=PD_DEFAULT_STYLE | wx.PD_CAN_ABORT) progress.Show() completed = 0 for D in sorted(dirs): for F in sorted(dirs[D]): if progress and progress.WasCancelled(): progress.Destroy() return False if progress: wx.Yield() progress.Update(completed, GT(u'Adding file {}').format(F)) self.lst_files.AddFile(F, D, target) completed += 1 if progress: wx.Yield() progress.Update(completed) progress.Destroy() return True
def GetFileOpenDialog(parent, title, wildcard=wx.FileSelectorDefaultWildcardStr, extension=None, directory=None): if parent == None: parent = GetMainWindow() wildcard = _format_wildcard(wildcard) file_open = StandardFileDialog(parent, title, defaultDir=directory, defaultExt=extension, wildcard=wildcard, style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_CHANGE_DIR) return file_open
def SendToTrash(self, item_list): path_list = [] for I in item_list: if not os.access(I.Path, os.W_OK): ShowErrorDialog( GT(u'Cannot move "{}" to trash, no write access').format( I.Path), warn=True) return False path_list.append(I.Path) msg_l1 = GT(u'Move the following items to trash?') msg_l2 = u'\n'.join(path_list) if ConfirmationDialog(GetMainWindow(), GT(u'Delete'), u'{}\n\n{}'.format(msg_l1, msg_l2)).Confirmed(): arg_list = list(path_list) # Use 'force' argument to avoid crash on non-existing paths arg_list.insert(0, u'-f') ExecuteCommand(GetExecutable(u'gvfs-trash'), arg_list) Logger.Debug(__name__, u'Paths deleted') self.DeleteItems(item_list) Logger.Debug(__name__, u'Items deleted') # Confirm that paths were removed for P in path_list: if os.path.exists(P): Logger.Debug(__name__, u'Failed to remove "{}"'.format(P)) return False Logger.Debug(__name__, u'Items successfully moved to trash') return True return False
def OnExportLauncher(self, event=None): Logger.Debug(__name__, u'Export launcher ...') # Get data to write to control file menu_data = self.GetLauncherInfo().encode(u'utf-8') dia = wx.FileDialog(GetMainWindow(), GT(u'Save Launcher'), os.getcwd(), style=wx.FD_SAVE | wx.FD_CHANGE_DIR | wx.FD_OVERWRITE_PROMPT) if ShowDialog(dia): path = dia.GetPath() # Create a backup file overwrite = False if os.path.isfile(path): backup = u'{}.backup'.format(path) shutil.copy(path, backup) overwrite = True try: WriteFile(path, menu_data) if overwrite: os.remove(backup) except UnicodeEncodeError: detail1 = GT( u'Unfortunately Debreate does not support unicode yet.') detail2 = GT( u'Remove any non-ASCII characters from your project.') ShowErrorDialog(GT(u'Save failed'), u'{}\n{}'.format(detail1, detail2), title=GT(u'Unicode Error')) os.remove(path) # Restore from backup shutil.move(backup, path)
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()