def show(): """Show all the issues in a dialog. The list of issues will be automatically cleared. If there are no issues to report, nothing is done.""" global allIssues if len(allIssues) == 0: # Nothing to report. return import sb.util.dialog dialog, area = sb.util.dialog.createButtonDialog( 'issue-dialog', ['ok'], 'ok') message = area.createFormattedText() message.setMinSize(500, 300) msg = '' bgColor = ['#90E090', '#FFFF80', '#E05050'] fgColor = ['black', 'black', 'white'] severeName = ['Note', 'Warning', 'Error'] isFirst = True # Compose a HTML formatted version of each issue. for severe in [HIGH, MEDIUM, LOW]: # Show the important issues first. for issue in allIssues: if issue[0] != severe: continue if not isFirst: msg += '<hr>' isFirst = False msg += '<table width="100%" border=0 cellspacing=3 cellpadding=4>' msg += '<tr><td bgcolor="%s" width="20%%" align=center>' % \ bgColor[issue[0]] msg += '<font color="%s"><b>' % fgColor[issue[0]] + \ severeName[issue[0]] + '</b></font>' msg += '<td width="80%"><h3>' + language.expand( language.translate(issue[1]), *issue[2]) msg += '</h3>' + language.expand( language.translate(issue[1] + '-text'), *issue[2]) msg += '</table>' message.setText(msg) dialog.run() # Only show each issue once. allIssues = []
def show(): """Show all the issues in a dialog. The list of issues will be automatically cleared. If there are no issues to report, nothing is done.""" global allIssues if len(allIssues) == 0: # Nothing to report. return import sb.util.dialog dialog, area = sb.util.dialog.createButtonDialog('issue-dialog', ['ok'], 'ok') message = area.createFormattedText() message.setMinSize(500, 300) msg = '' bgColor = ['#90E090', '#FFFF80', '#E05050'] fgColor = ['black', 'black', 'white'] severeName = ['Note', 'Warning', 'Error'] isFirst = True # Compose a HTML formatted version of each issue. for severe in [HIGH, MEDIUM, LOW]: # Show the important issues first. for issue in allIssues: if issue[0] != severe: continue if not isFirst: msg += '<hr>' isFirst = False msg += '<table width="100%" border=0 cellspacing=3 cellpadding=4>' msg += '<tr><td bgcolor="%s" width="20%%" align=center>' % \ bgColor[issue[0]] msg += '<font color="%s"><b>' % fgColor[issue[0]] + \ severeName[issue[0]] + '</b></font>' msg += '<td width="80%"><h3>' + language.expand( language.translate(issue[1]), *issue[2]) msg += '</h3>' + language.expand( language.translate(issue[1] + '-text'), *issue[2]) msg += '</table>' message.setText(msg) dialog.run() # Only show each issue once. allIssues = []
def handleCommand(event): """Handle the About command and display the About Snowberry dialog. @param event An events.Command event. """ if event.hasId('about'): # Create the About dialog and show it. dialog, area = sb.util.dialog.createButtonDialog( 'about-dialog', ['show-credits', '', 'ok'], 'ok', resizable=False) content = area.createArea(alignment=ui.ALIGN_VERTICAL, border=0) content.setWeight(0) # Big logo. content.setBorder(16, ui.BORDER_BOTTOM) content.createImage('about') content.setBorder(6, ui.BORDER_BOTTOM) versionText = content.createText('', align=wt.Text.MIDDLE) versionText.setBoldStyle() versionText.setText( language.translate('about-version') + ' ' + st.getSystemString('snowberry-version')) content.createText('about-subtitle', align=wt.Text.MIDDLE) content.createText('about-license', align=wt.Text.MIDDLE) content.createText('about-website', align=wt.Text.MIDDLE).setSmallStyle() #content.setBorder(6) #content.setWeight(1) #box = content.createArea(boxedWithTitle='about-credits') #info = box.createFormattedText() #info.setMinSize(300, 280) #info.setText(language.translate('about-info')) dialog.focusWidget('ok') dialog.run() elif event.hasId('show-credits'): dialog, area = sb.util.dialog.createButtonDialog( 'about-credits', ['close'], 'close') info = area.createFormattedText() info.setMinSize(290, 230) info.setText(language.translate('credits')) dialog.addEndCommand('close') dialog.run()
def handleCommand(event): if pr.getActive() is pr.getDefaults(): return if event.hasId('play'): # Launch the game with the active profile. startGame(pr.getActive()) elif event.hasId('continue') and resolving: continueResolving() elif event.hasId('view-command-line'): # Generate a command line and display it in a dialog. options = generateOptions(pr.getActive()) if options == None: return # Escape any angle brackets. options = options.replace('<', '<') options = options.replace('>', '>') options = options.replace(' -', '<br>-') # Highlight all the options with a bold font. pos = 0 while pos < len(options): if options[pos:pos + 5] == '<br>-' or \ pos == 0 and options[pos] == '-': options = options[:pos] + '<b>' + options[pos:] pos += 5 while pos < len(options) and \ options[pos] not in string.whitespace: pos += 1 options = options[:pos] + '</b>' + options[pos:] pos += 1 dialog, area = sb.util.dialog.createButtonDialog( 'view-command-line-dialog', ['ok'], 'ok') msg = area.createFormattedText() msg.setMinSize(500, 400) msg.setText('<tt>' + options + '</tt>') dialog.run()
def runWizard(): """Run the wizard dialog.""" # Make sure the help panel isn't updated during the wizard. #events.send(events.Command('freeze')) suggested = { 'doom1': 'DOOM.WAD', 'doom1-share': 'DOOM1.WAD', 'doom1-ultimate': 'DOOM.WAD', 'doom2': 'DOOM2.WAD', 'doom2-tnt': 'TNT.WAD', 'doom2-plut': 'PLUTONIA.WAD', 'heretic-ext': 'HERETIC.WAD', 'heretic-share': 'HERETIC.WAD', 'heretic': 'HERETIC.WAD', 'hexen': 'HEXEN.WAD', 'hexen-demo': 'HEXEN.WAD', 'hexen-dk': 'HEXEN.WAD', 'hacx': 'HACX.WAD', 'chex': 'CHEX.WAD' } events.mute() # Make the Defaults profile active. pr.setActive(pr.getDefaults()) wiz = WizardDialog(language.translate('setup-wizard'), paths.findBitmap('wizard')) # Language selection page. langPage = WizardPage(wiz, 'wizard-language') area = langPage.getArea() area.createText('wizard-language-explanation', maxLineLength=65).resizeToBestSize() sar, languageCheckBox = area.createSetting(st.getSetting('language')) languageCheckBox.getFromProfile(pr.getActive()) # Game selection. gamePage = ProfileWizardPage(wiz, 'wizard-games', None) gamePage.follows(langPage) area = gamePage.getArea() area.createText('wizard-select-games', maxLineLength=65).resizeToBestSize() area.setBorderDirs(ui.BORDER_NOT_BOTTOM) games = area.createList('', style=sb.widget.list.List.STYLE_CHECKBOX) area.setBorderDirs(ui.BORDER_NOT_TOP) games.setMinSize(50, 180) gamePage.setGameList(games) def allGames(): # Check the entire list. for item in games.getItems(): games.checkItem(item, True) def clearGames(): # Uncheck the entire list. for item in games.getItems(): games.checkItem(item, False) controls = area.createArea(alignment=ui.ALIGN_HORIZONTAL, border=2) controls.setWeight(0) button = controls.createButton('wizard-games-all', wb.Button.STYLE_MINI) button.addReaction(allGames) button.resizeToBestSize() button = controls.createButton('wizard-games-clear', wb.Button.STYLE_MINI) button.addReaction(clearGames) button.resizeToBestSize() # The pages will be linked together. previousPage = gamePage deathKingsWad = None # We'll do this dynamically. checkedProfiles = ['doom1', 'doom2', 'heretic', 'hexen'] # Only display the system profiles in the wizard (not any user # profiles). profiles = pr.getProfiles(lambda p: p.isSystemProfile()) for p in profiles: if p is not pr.getDefaults(): games.addItem(p.getId(), p.getId() in checkedProfiles) # Create a page for the profile. page = ProfileWizardPage(wiz, p.getId(), games) # Link the pages together. page.follows(previousPage) previousPage = page area = page.getArea() area.createText('wizard-locate-iwad', maxLineLength=65).resizeToBestSize() # The suggestion. if suggested.has_key(p.getId()): sugArea = area.createArea(alignment=ui.ALIGN_HORIZONTAL, border=2) sugArea.setExpanding(False) sugArea.setWeight(1) sugArea.createText('wizard-suggested-iwad', ':', align=wt.Text.RIGHT) sugArea.setWeight(2) sug = sugArea.createText('') sug.setText(suggested[p.getId()]) sar, page.iwadText = area.createSetting(st.getSetting('iwad')) if p.getId() == 'hexen-dk': area.setBorder(12, ui.BORDER_ALL) area.createLine() area.setBorder(6, ui.BORDER_ALL) area.createText('deathkings-selection-title').setHeadingStyle() # Death Kings is an extension to Hexen. It uses the # same Hexen IWAD, but also an addon IWAD. area.createText('wizard-locate-iwad-deathkings', maxLineLength=65).resizeToBestSize() entry = area.createArea(alignment=ui.ALIGN_HORIZONTAL, border=4) entry.setExpanding(False) entry.setWeight(1) entry.setBorderDirs(ui.BORDER_NOT_LEFT) deathKingsWad = entry.createTextField('') entry.setWeight(0) entry.setBorderDirs(ui.BORDER_TOP_BOTTOM) browseButton = entry.createButton('browse-button', wb.Button.STYLE_MINI) def browseDeathKings(): # Open a file browser. selection = sb.util.dialog.chooseFile('deathkings-selection-title', '', True, [('file-type-wad', 'wad')]) if len(selection) > 0: deathKingsWad.setText(selection) browseButton.addReaction(browseDeathKings) # Addon paths. pathsPage = ProfileWizardPage(wiz, 'wizard-addon-paths', games) pathsPage.follows(previousPage) area = pathsPage.getArea() area.createText('wizard-addon-paths-explanation', maxLineLength=65).resizeToBestSize() area.setBorderDirs(ui.BORDER_NOT_BOTTOM) pathList = area.createList('addon-paths-list') pathList.setMinSize(100, 120) # Insert the current custom paths into the list. for p in paths.getAddonPaths(): pathList.addItem(p) def addAddonPath(): selection = sb.util.dialog.chooseFolder('addon-paths-add-prompt', '') if selection: pathList.addItem(selection) pathList.selectItem(selection) def removeAddonPath(): selection = pathList.getSelectedItem() if selection: pathList.removeItem(selection) area.setWeight(0) area.setBorderDirs(ui.BORDER_NOT_TOP) commands = area.createArea(alignment=ui.ALIGN_HORIZONTAL, border=2) commands.setWeight(0) # Button for adding new paths. button = commands.createButton('new-addon-path', wb.Button.STYLE_MINI) button.addReaction(addAddonPath) # Button for removing a path. button = commands.createButton('delete-addon-path', wb.Button.STYLE_MINI) button.addReaction(removeAddonPath) # Launch options. quitPage = WizardPage(wiz, 'wizard-launching') quitPage.follows(pathsPage) area = quitPage.getArea() area.createText('wizard-launching-explanation').resizeToBestSize() sar, quitCheckBox = area.createSetting(st.getSetting('quit-on-launch')) quitCheckBox.getFromProfile(pr.getActive()) # List of unusable profiles, due to a missing IWAD. unusableProfiles = [] # When the page changes in the wizard, change the active profile. def changeActiveProfile(page): prof = pr.get(page.getId()) if prof: pr.setActive(prof) else: pr.setActive(pr.getDefaults()) # Update page with values from the current profile. page.update() wiz.setPageReaction(changeActiveProfile) if wiz.run(langPage) == 'ok': events.unmute() # Show the profiles that now have an IWAD. for prof in profiles: if prof.getValue('iwad', False) != None: pr.show(prof.getId()) if prof.getId() in unusableProfiles: unusableProfiles.remove(prof.getId()) else: pr.hide(prof.getId()) if prof.getId() not in unusableProfiles and \ prof.getId() in games.getSelectedItems(): unusableProfiles.append(prof.getId()) # Install the Death Kings WAD? if deathKingsWad: try: ident = ao.install(deathKingsWad.getText()) # Attach the WAD as an addon. kingsProfile = pr.get('hexen-dk') kingsProfile.useAddon(ident) except: # TODO: Handle error. pass # Update custom addon paths. currentAddonPaths = paths.getAddonPaths() wasModified = False for path in pathList.getItems(): if path not in currentAddonPaths: paths.addAddonPath(path) wasModified = True for path in currentAddonPaths: if path not in pathList.getItems(): paths.removeAddonPath(path) wasModified = True if wasModified: # Load addons from new paths. ao.refresh() events.send(events.Notify('addon-paths-changed')) # The wizard will only be shown once automatically. pr.getDefaults().setValue(HAS_BEEN_RUN, 'yes', False) else: # Wizard was canceled. events.unmute() pr.refresh() # This'll destroy all the pages of the wizard as well. wiz.destroy() # Enable help panel updates again. #events.send(events.Command('unfreeze')) # Tell the user about unusable profiles. if len(unusableProfiles) > 0: dialog, area = sb.util.dialog.createButtonDialog( 'wizard-unlaunchable-profiles', ['ok'], 'ok', resizable=False) # Compose a list of the unlaunchable profiles. profList = '' unusableProfiles.sort(lambda a, b: cmp(language.translate(a), language.translate(b))) for p in unusableProfiles: profList += "\n" + language.translate(p) msg = area.createText() msg.setText(language.translate('wizard-unlaunchable-profiles-listed') + "\n" + profList) msg.resizeToBestSize() dialog.run()
def run(addon): """Show a dialog box that contains a lot of information (all there is to know) about the addon. @param An addons.Addon object. """ ident = addon.getId() dialog, area = sb.util.dialog.createButtonDialog('addon-inspector-dialog', ['ok'], 'ok', size=(570, 450)) msg = "" msg += '<h3>' + language.translate(ident) + '</h3>' if language.isDefined(ident + '-readme'): msg += "<p>" + language.translate(ident + '-readme') def makeField(header, content): return '<tr><td width="20%" bgcolor="#E8E8E8" align="right"><b>' + header + \ '</b></td><td width="80%">' + content + '</td></tr>' beginTable = '<p><table width="100%" border=0 cellpadding=6 cellspacing=0>' endTable = '</table>' # # General Information # msg += beginTable msg += makeField('Summary:', language.translate(ident + '-summary', '-')) msg += makeField('Version:', language.translate(ident + '-version', '-')) msg += makeField( 'Last Modified:', time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime(addon.getLastModified()))) msg += makeField('Author(s):', language.translate(ident + '-author', '-')) msg += makeField('Contact:', language.translate(ident + '-contact', '-')) msg += makeField('Copyright:', language.translate(ident + '-copyright', '-')) msg += makeField('License:', language.translate(ident + '-license', '-')) msg += makeField('Category:', addon.getCategory().getPath()) msg += makeField('Format:', language.translate(addon.getType())) msg += makeField('Identifier:', addon.getId()) msg += endTable # # Raw Dependencies # msg += '<h3>Dependencies</h3>' + beginTable allDeps = [] # Excluded categories. dep = [] for category in addon.getExcludedCategories(): dep.append(category.getPath()) allDeps.append(('Excluded Categories:', dep)) # Keywords. for type, label in [(sb.addon.EXCLUDES, 'Excludes:'), (sb.addon.REQUIRES, 'Requires:'), (sb.addon.PROVIDES, 'Provides:'), (sb.addon.OFFERS, 'Offers:')]: # Make a copy of the list so we can modify it. dep = [] for kw in addon.getKeywords(type): dep.append(kw) allDeps.append((label, dep)) # Create a table out of each dependency type. for heading, listing in allDeps: msg += makeField(heading, string.join(listing, '<br>')) msg += endTable # # Content Analysis # msg += '<h3>Contents</h3>' + beginTable msg += makeField('Content Path:', addon.getContentPath()) msg += endTable #msg += "<p>format-specific data" #msg += "<br>content analysis, size" #msg += "<br>list of files, if a bundle" #msg += '<h3>Identifiers</h3>' #msg += "<br>all internal identifiers used by the addon" #msg += '<h3>Metadata</h3>' #msg += "<br>metadata analysis, source" text = area.createFormattedText() text.setMinSize(500, 200) text.setText(msg) dialog.run()
def commandHandler(event): """This is called when a Command event is broadcasted.""" global profileListDisabled if event.hasId("freeze"): profileListDisabled = True elif event.hasId("unfreeze"): profileListDisabled = False # notifyHandler(events.Notify('active-profile-changed')) pr.refresh() elif event.hasId("new-profile"): dialog, area = sb.util.dialog.createButtonDialog("new-profile-dialog", ["cancel", "ok"], "ok", resizable=False) dialog.disableWidget("ok") entry = area.createArea(alignment=ALIGN_HORIZONTAL) entry.setExpanding(False) # The name of the profile. entry.setWeight(1) entry.setBorder(4, ui.BORDER_RIGHT) entry.createText("new-profile-name", ":", align=wt.Text.RIGHT) entry.setBorder(0) entry.setWeight(2) nameField = entry.createTextField("") nameField.focus() # Only enable the OK button if there is something in the name field. def buttonEnabler(): dialog.enableWidget("ok", len(nameField.getText()) > 0) nameField.addReaction(buttonEnabler) # The game component. entry = area.createArea(alignment=ALIGN_HORIZONTAL) entry.setExpanding(False) entry.setWeight(1) entry.setBorder(4, ui.BORDER_RIGHT) entry.createText("new-profile-game", ":", align=wt.Text.RIGHT) entry.setBorder(0) entry.setWeight(2) gameDrop = entry.createDropList("") for game in st.getGameComponents(): gameDrop.addItem(game.getId()) gameDrop.sortItems() # Select the first one. gameDrop.selectItem(gameDrop.getItems()[0]) if dialog.run() == "ok": # Get the values from the controls. pr.create(nameField.getText(), gameDrop.getSelectedItem()) elif event.hasId("rename-profile"): dialog, area = sb.util.dialog.createButtonDialog( "rename-profile-dialog", ["cancel", "ok"], "ok", resizable=False ) prof = pr.getActive() # A text field of the new name. entry = area.createArea(alignment=ALIGN_HORIZONTAL) entry.setExpanding(False) # The name of the profile. entry.setWeight(1) entry.setBorder(4, ui.BORDER_RIGHT) entry.createText("rename-profile-name", ":", align=wt.Text.RIGHT) entry.setBorder(0) entry.setWeight(2) nameField = entry.createTextField("") nameField.setText(prof.getName()) nameField.focus() # Only enable the OK button if there is something in the name # field. def buttonEnabler(): dialog.enableWidget("ok", len(nameField.getText()) > 0) nameField.addReaction(buttonEnabler) if dialog.run() == "ok": prof.setName(nameField.getText()) # The profile list needs to be updated, too. events.send(events.ProfileNotify(prof)) pr.refresh() elif event.hasId("reset-profile"): dialog, area = sb.util.dialog.createButtonDialog( "reset-profile-dialog", ["cancel", "reset-profile-values", "reset-profile-addons", "reset-profile-everything"], "cancel", resizable=False, ) text = language.translate("reset-profile-query") message = area.createRichText(language.expand(text, pr.getActive().getName())) # Accept these as dialog-closing commands. dialog.addEndCommand("reset-profile-values") dialog.addEndCommand("reset-profile-addons") dialog.addEndCommand("reset-profile-everything") result = dialog.run() if result == "cancel": return resetValues = True resetAddons = True if result == "reset-profile-values": resetAddons = False elif result == "reset-profile-addons": resetValues = False pr.reset(pr.getActive().getId(), resetValues, resetAddons) pr.refresh() elif event.hasId("delete-profile"): # If this is a system profile, just hide it. if pr.getActive().isSystemProfile(): pr.hide(pr.getActive().getId()) return dialog, area = sb.util.dialog.createButtonDialog("delete-profile-dialog", ["no", "yes"], "no", resizable=False) text = language.translate("delete-profile-query") area.createRichText(language.expand(text, pr.getActive().getName())) if dialog.run() == "yes": # Get the values from the controls. pr.remove(pr.getActive().getId()) elif event.hasId("duplicate-profile"): dialog, area = sb.util.dialog.createButtonDialog( "duplicate-profile-dialog", ["cancel", "ok"], "ok", resizable=False ) text = language.translate("duplicating-profile") area.setWeight(1) area.createRichText(language.expand(text, pr.getActive().getName())) area.setWeight(1) entry = area.createArea(alignment=ALIGN_HORIZONTAL) entry.setExpanding(False) # The name of the profile. entry.setWeight(1) entry.setBorder(4, ui.BORDER_RIGHT) entry.createText("new-profile-name", ":", align=wt.Text.RIGHT) entry.setBorder(0) entry.setWeight(3) nameField = entry.createTextField("") nameField.setText(pr.getActive().getName()) nameField.focus() # Only enable the OK button if there is something in the name field. def buttonEnabler(): dialog.enableWidget("ok", len(nameField.getText()) > 0) nameField.addReaction(buttonEnabler) if dialog.run() == "ok": pr.duplicate(pr.getActive().getId(), nameField.getText()) elif event.hasId("hide-profile"): pr.hide(pr.getActive().getId()) elif event.hasId("unhide-profiles"): # Display a dialog bog for unhiding hidden profiles. hiddenProfiles = pr.getProfiles(lambda p: p.isHidden()) dialog, area = sb.util.dialog.createButtonDialog( "unhide-profile-dialog", ["cancel", "ok"], "ok", resizable=False ) area.setWeight(0) area.createText("unhiding-profiles") area.setWeight(3) area.setBorder(0) profList = area.createList("", sb.widget.list.List.STYLE_CHECKBOX) profList.setMinSize(50, 150) def selectAll(): # Check the entire list. for item in profList.getItems(): profList.checkItem(item, True) def clearAll(): # Uncheck the entire list. for item in profList.getItems(): profList.checkItem(item, False) area.setWeight(0) controls = area.createArea(alignment=ALIGN_HORIZONTAL, border=2) controls.setWeight(0) button = controls.createButton("unhide-select-all", style=sb.widget.button.Button.STYLE_MINI) button.addReaction(selectAll) button.resizeToBestSize() button = controls.createButton("unhide-clear-all", style=sb.widget.button.Button.STYLE_MINI) button.addReaction(clearAll) button.resizeToBestSize() for prof in hiddenProfiles: profList.addItem(prof.getId()) if dialog.run() == "ok": # Unhide all the selected items. selected = profList.getSelectedItems() for sel in selected: pr.show(sel) if len(selected): # Select the first one that was shown. pr.setActive(pr.get(selected[0]))
def chooseAddons(dialogId, title, actionButton): """Opens an addon selection dialog. @param title Title of the dialog. @param actionButton The button that will perform the affirmative action of the dialog. """ dialog, area = sb.util.dialog.createButtonDialog(dialogId, ['cancel', actionButton], actionButton) dialog.addEndCommand('addon-dialog-add-to-custom-folders') # The action button is disabled until a valid selection has been # made. dialog.disableWidget(actionButton) area.setWeight(0) folderArea = area.createArea(alignment=ui.ALIGN_HORIZONTAL) folderArea.setExpanding(False) folderArea.setBorder(2, ui.BORDER_NOT_LEFT) folderArea.setWeight(0) folderArea.createText('addon-dialog-folder').resizeToBestSize() folderArea.setBorderDirs(ui.BORDER_ALL) folderArea.setWeight(1) pathField = folderArea.createTextField('') pathField.setText(os.getcwd()) pathField.select() pathField.focus() folderArea.setWeight(0) folderArea.setBorderDirs(ui.BORDER_NOT_RIGHT) browseButton = folderArea.createButton('addon-dialog-folder-browse', style=wg.Button.STYLE_MINI) #folderArea.addSpacer() #folderArea.setBorderDirs(ui.BORDER_NOT_RIGHT) folderCmdArea = area.createArea(alignment=ui.ALIGN_HORIZONTAL) folderCmdArea.setExpanding(False) folderCmdArea.setBorder(6, ui.BORDER_NOT_TOP) folderCmdArea.setWeight(1) folderCmdArea.addSpacer() folderCmdArea.setWeight(0) uninstButton = folderCmdArea.createButton('addon-dialog-folder-uninstalled') # Add to Custom Folders button. folderCmdArea.setBorder(6, ui.BORDER_LEFT | ui.BORDER_BOTTOM) addToMyButton = folderCmdArea.createButton('addon-dialog-add-to-custom-folders') def goToUninstalled(): pathField.setText(paths.getUserPath(paths.UNINSTALLED)) pathField.select() addToMyButton.disable() uninstButton.addReaction(goToUninstalled) area.createText('addon-dialog-found') area.setWeight(1) foundList = area.createList('', style=sb.widget.list.List.STYLE_COLUMNS) foundList.setMinSize(500, 300) area.setWeight(0) area.createText('addon-dialog-addons-copied', maxLineLength=70).resizeToBestSize() def selectAction(): dialog.enableWidget(actionButton) foundList.addReaction(selectAction) for col, width in [('name', None), ('type', 180)]: foundList.addColumn('addon-dialog-' + col, width) def updateList(): # Update the found addons list. foundList.clear() dialog.disableWidget(actionButton) extensions = ao.getAddonExtensions() + ['manifest'] # This should be done in addons.py. fileNames = os.listdir(pathField.getText()) for name in fileNames: type = '' for ext in extensions: if paths.hasExtension(ext, name): type = ext break if not type: # Unknown files are skipped. continue # Manifests don't appear in the list if the corresponding # addon is in the same directory. if paths.hasExtension('manifest', name): foundSame = False # Identifier of the addon the manifest belongs to. manifestId = paths.getBase(name) # See if the addon is in the list. for other in fileNames: if other == name: continue if manifestId == ao.formIdentifier(other)[0]: foundSame = True break if foundSame: # Don't add it. continue foundList.addItemWithColumns( name, name, language.translate('addon-dialog-type-' + type)) # Update reactions. def pathChanged(): if os.path.exists(pathField.getText()): updateList() if pathField.getText() != paths.getUserPath(paths.UNINSTALLED): addToMyButton.enable() else: addToMyButton.disable() def browseAction(): # Show a directory browser. selection = sb.util.dialog.chooseFolder('addon-dialog-browse-prompt', pathField.getText()) if len(selection): pathField.setText(selection) pathField.select() # The initial contents of the list. updateList() pathField.addReaction(pathChanged) browseButton.addReaction(browseAction) dialog.addEndCommand(actionButton) result = dialog.run() if result == actionButton: addonFiles = map(lambda name: os.path.join(pathField.getText(), name), foundList.getSelectedItems()) # Include any associated manifests. for name in addonFiles: manifest = ao.formIdentifier(name)[0] + '.manifest' manifestFile = os.path.join(pathField.getText(), manifest) if manifest not in addonFiles and os.path.exists(manifestFile): addonFiles.append(manifestFile) #print 'including ' + manifestFile + ' due to ' + name return addonFiles elif result == 'addon-dialog-add-to-custom-folders': paths.addAddonPath(pathField.getText()) events.send(events.Notify('addon-paths-changed')) ao.refresh() return [] # The dialog was canceled. return []
def handleCommand(event): """This is called when someone sends a command event. @param event An events.Command object.""" # Figure out which addon has been currently selected in the addons # tree. The action will target this addon. selected = '' if event.hasId('refresh-addon-database'): ao.refresh() elif event.hasId('install-addon'): tab30.installer.run() elif event.hasId('uninstall-addon'): selectedItems = addonList.getSelectedItems() # Only take the uninstallable addons. addons = filter(lambda i: ao.isUninstallable(i), selectedItems) if len(addons) == 0: return # Make sure the user wants to uninstall. dialog, area = sb.util.dialog.createButtonDialog( 'uninstall-addon-dialog', ['no', 'yes'], 'no', resizable=False) if len(addons) == 1: text = language.translate('uninstall-addon-query') area.setExpanding(True) area.createRichText( language.expand(text, language.translate(addons[0]))) else: area.setWeight(0) area.createText('uninstall-addon-query-several') msg = '<html><ul>' for addon in addons: msg += '<li>' + language.translate(addon) + '</li>' msg += '</ul></html>' ft = area.createFormattedText() ft.setText(msg) ft.setMinSize(400, 150) if dialog.run() == 'yes': for addon in addons: ao.uninstall(addon) ao.refresh() elif event.hasId('addon-info'): sel = addonList.getSelectedItems() if len(sel) > 0: # Show the Addon Inspector. tab30.inspector.run(ao.get(sel[0])) elif event.hasId('addon-settings'): sel = addonList.getSelectedItems() if len(sel) > 0: command = events.Command('show-addon-settings') command.addon = sel[0] events.send(command) elif event.hasId('load-order'): # Open the Load Order dialog. tab30.loadorder.run(pr.getActive()) elif event.hasId('addon-list-check-selected'): for addon in addonList.getSelectedItems(): pr.getActive().useAddon(addon) elif event.hasId('addon-list-uncheck-selected'): for addon in addonList.getSelectedItems(): pr.getActive().dontUseAddon(addon) elif event.hasId('addon-list-check-all'): for addon in addonList.getItems(): pr.getActive().useAddon(addon) elif event.hasId('addon-list-uncheck-all'): for addon in addonList.getItems(): pr.getActive().dontUseAddon(addon) elif event.hasId('addon-show-parent-box'): for addon in addonList.getSelectedItems(): a = ao.get(addon) if a.getBox(): showInAddonList(a.getBox().getId()) break elif event.hasId('addon-show-box-category'): for addon in addonList.getSelectedItems(): a = ao.get(addon) if a.getType() == 'addon-type-box': addonList.deselectAllItems() tree.selectItem(a.getContentCategoryLongId()) refreshListIfVisible() break
def run(profile): """Open the load order dialog. @param profile The profile whose order is being edited. """ dialog, area = sb.util.dialog.createButtonDialog( 'load-order-dialog', ['reset', '', 'cancel', 'ok'], 'ok') dialog.focusWidget('cancel') area.setWeight(0) area.createText('load-order-message') # Create the widgets that will be used to edit the order. area.setWeight(1) top = area.createArea(alignment=ui.ALIGN_HORIZONTAL, border=0) top.setWeight(3) listArea = top.createArea(border=3) listArea.setWeight(1) orderList = listArea.createList('') orderList.setMinSize(200, 200) top.setWeight(1) controlArea = top.createArea(border=3) controlArea.setWeight(0) controlArea.setExpanding(False) upButton = controlArea.createButton('load-order-move-up') downButton = controlArea.createButton('load-order-move-down') controlArea.addSpacer() firstButton = controlArea.createButton('load-order-move-top') lastButton = controlArea.createButton('load-order-move-bottom') def moveSelFirst(): orderList.moveItem(orderList.getSelectedItem(), -65535) def moveSelLast(): orderList.moveItem(orderList.getSelectedItem(), +65535) def moveSelUp(): orderList.moveItem(orderList.getSelectedItem(), -1) def moveSelDown(): orderList.moveItem(orderList.getSelectedItem(), +1) firstButton.addReaction(moveSelFirst) upButton.addReaction(moveSelUp) downButton.addReaction(moveSelDown) lastButton.addReaction(moveSelLast) # The final addons are automatically sorted according to the # profile's load order. finalAddons = profile.getFinalAddons() # Put all the finalized list of loaded addons into the list. for ident in finalAddons: orderList.addItem(ident) if len(finalAddons): orderList.selectItem(finalAddons[0]) # We'll accept 'reset' as a dialog end command as well. dialog.addEndCommand('reset') # Run the dialog and handle the closing command. result = dialog.run() if result == 'ok': # This is the new load order for the profile. profile.setLoadOrder(orderList.getItems()) elif result == 'reset': # Clear the profile's load order. profile.setLoadOrder([]) else: # Nothing is done on cancel. pass
def run(addon): """Show a dialog box that contains a lot of information (all there is to know) about the addon. @param An addons.Addon object. """ ident = addon.getId() dialog, area = sb.util.dialog.createButtonDialog( 'addon-inspector-dialog', ['ok'], 'ok', size=(570, 450)) msg = "" msg += '<h3>' + language.translate(ident) + '</h3>' if language.isDefined(ident + '-readme'): msg += "<p>" + language.translate(ident + '-readme') def makeField(header, content): return '<tr><td width="20%" bgcolor="#E8E8E8" align="right"><b>' + header + \ '</b></td><td width="80%">' + content + '</td></tr>' beginTable = '<p><table width="100%" border=0 cellpadding=6 cellspacing=0>' endTable = '</table>' # # General Information # msg += beginTable msg += makeField('Summary:', language.translate(ident + '-summary', '-')) msg += makeField('Version:', language.translate(ident + '-version', '-')) msg += makeField('Last Modified:', time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime(addon.getLastModified()))) msg += makeField('Author(s):', language.translate(ident + '-author', '-')) msg += makeField('Contact:', language.translate(ident + '-contact', '-')) msg += makeField('Copyright:', language.translate(ident + '-copyright', '-')) msg += makeField('License:', language.translate(ident + '-license', '-')) msg += makeField('Category:', addon.getCategory().getPath()) msg += makeField('Format:', language.translate(addon.getType())) msg += makeField('Identifier:', addon.getId()) msg += endTable # # Raw Dependencies # msg += '<h3>Dependencies</h3>' + beginTable allDeps = [] # Excluded categories. dep = [] for category in addon.getExcludedCategories(): dep.append(category.getPath()) allDeps.append(('Excluded Categories:', dep)) # Keywords. for type, label in [(sb.addon.EXCLUDES, 'Excludes:'), (sb.addon.REQUIRES, 'Requires:'), (sb.addon.PROVIDES, 'Provides:'), (sb.addon.OFFERS, 'Offers:')]: # Make a copy of the list so we can modify it. dep = [] for kw in addon.getKeywords(type): dep.append(kw) allDeps.append((label, dep)) # Create a table out of each dependency type. for heading, listing in allDeps: msg += makeField(heading, string.join(listing, '<br>')) msg += endTable # # Content Analysis # msg += '<h3>Contents</h3>' + beginTable msg += makeField('Content Path:', addon.getContentPath()) msg += endTable #msg += "<p>format-specific data" #msg += "<br>content analysis, size" #msg += "<br>list of files, if a bundle" #msg += '<h3>Identifiers</h3>' #msg += "<br>all internal identifiers used by the addon" #msg += '<h3>Metadata</h3>' #msg += "<br>metadata analysis, source" text = area.createFormattedText() text.setMinSize(500, 200) text.setText(msg) dialog.run()
def commandHandler(event): """This is called when a Command event is broadcasted.""" global profileListDisabled if event.hasId('freeze'): profileListDisabled = True elif event.hasId('unfreeze'): profileListDisabled = False #notifyHandler(events.Notify('active-profile-changed')) pr.refresh() elif event.hasId('new-profile'): dialog, area = sb.util.dialog.createButtonDialog('new-profile-dialog', ['cancel', 'ok'], 'ok', resizable=False) dialog.disableWidget('ok') entry = area.createArea(alignment=ALIGN_HORIZONTAL) entry.setExpanding(False) # The name of the profile. entry.setWeight(1) entry.setBorder(4, ui.BORDER_RIGHT) entry.createText('new-profile-name', ':', align=wt.Text.RIGHT) entry.setBorder(0) entry.setWeight(2) nameField = entry.createTextField('') nameField.focus() # Only enable the OK button if there is something in the name field. def buttonEnabler(): dialog.enableWidget('ok', len(nameField.getText()) > 0) nameField.addReaction(buttonEnabler) # The game component. entry = area.createArea(alignment=ALIGN_HORIZONTAL) entry.setExpanding(False) entry.setWeight(1) entry.setBorder(4, ui.BORDER_RIGHT) entry.createText('new-profile-game', ':', align=wt.Text.RIGHT) entry.setBorder(0) entry.setWeight(2) gameDrop = entry.createDropList('') for game in st.getGameComponents(): gameDrop.addItem(game.getId()) gameDrop.sortItems() # Select the first one. gameDrop.selectItem(gameDrop.getItems()[0]) if dialog.run() == 'ok': # Get the values from the controls. pr.create(nameField.getText(), gameDrop.getSelectedItem()) elif event.hasId('rename-profile'): dialog, area = sb.util.dialog.createButtonDialog( 'rename-profile-dialog', ['cancel', 'ok'], 'ok', resizable=False) prof = pr.getActive() # A text field of the new name. entry = area.createArea(alignment=ALIGN_HORIZONTAL) entry.setExpanding(False) # The name of the profile. entry.setWeight(1) entry.setBorder(4, ui.BORDER_RIGHT) entry.createText('rename-profile-name', ':', align=wt.Text.RIGHT) entry.setBorder(0) entry.setWeight(2) nameField = entry.createTextField('') nameField.setText(prof.getName()) nameField.focus() # Only enable the OK button if there is something in the name # field. def buttonEnabler(): dialog.enableWidget('ok', len(nameField.getText()) > 0) nameField.addReaction(buttonEnabler) if dialog.run() == 'ok': prof.setName(nameField.getText()) # The profile list needs to be updated, too. events.send(events.ProfileNotify(prof)) pr.refresh() elif event.hasId('reset-profile'): dialog, area = sb.util.dialog.createButtonDialog( 'reset-profile-dialog', [ 'cancel', 'reset-profile-values', 'reset-profile-addons', 'reset-profile-everything' ], 'cancel', resizable=False) text = language.translate('reset-profile-query') message = area.createRichText( language.expand(text, pr.getActive().getName())) # Accept these as dialog-closing commands. dialog.addEndCommand('reset-profile-values') dialog.addEndCommand('reset-profile-addons') dialog.addEndCommand('reset-profile-everything') result = dialog.run() if result == 'cancel': return resetValues = True resetAddons = True if result == 'reset-profile-values': resetAddons = False elif result == 'reset-profile-addons': resetValues = False pr.reset(pr.getActive().getId(), resetValues, resetAddons) pr.refresh() elif event.hasId('delete-profile'): # If this is a system profile, just hide it. if pr.getActive().isSystemProfile(): pr.hide(pr.getActive().getId()) return dialog, area = sb.util.dialog.createButtonDialog( 'delete-profile-dialog', ['no', 'yes'], 'no', resizable=False) text = language.translate('delete-profile-query') area.createRichText(language.expand(text, pr.getActive().getName())) if dialog.run() == 'yes': # Get the values from the controls. pr.remove(pr.getActive().getId()) elif event.hasId('duplicate-profile'): dialog, area = sb.util.dialog.createButtonDialog( 'duplicate-profile-dialog', ['cancel', 'ok'], 'ok', resizable=False) text = language.translate('duplicating-profile') area.setWeight(1) area.createRichText(language.expand(text, pr.getActive().getName())) area.setWeight(1) entry = area.createArea(alignment=ALIGN_HORIZONTAL) entry.setExpanding(False) # The name of the profile. entry.setWeight(1) entry.setBorder(4, ui.BORDER_RIGHT) entry.createText('new-profile-name', ':', align=wt.Text.RIGHT) entry.setBorder(0) entry.setWeight(3) nameField = entry.createTextField('') nameField.setText(pr.getActive().getName()) nameField.focus() # Only enable the OK button if there is something in the name field. def buttonEnabler(): dialog.enableWidget('ok', len(nameField.getText()) > 0) nameField.addReaction(buttonEnabler) if dialog.run() == 'ok': pr.duplicate(pr.getActive().getId(), nameField.getText()) elif event.hasId('hide-profile'): pr.hide(pr.getActive().getId()) elif event.hasId('unhide-profiles'): # Display a dialog bog for unhiding hidden profiles. hiddenProfiles = pr.getProfiles(lambda p: p.isHidden()) dialog, area = sb.util.dialog.createButtonDialog( 'unhide-profile-dialog', ['cancel', 'ok'], 'ok', resizable=False) area.setWeight(0) area.createText('unhiding-profiles') area.setWeight(3) area.setBorder(0) profList = area.createList('', sb.widget.list.List.STYLE_CHECKBOX) profList.setMinSize(50, 150) def selectAll(): # Check the entire list. for item in profList.getItems(): profList.checkItem(item, True) def clearAll(): # Uncheck the entire list. for item in profList.getItems(): profList.checkItem(item, False) area.setWeight(0) controls = area.createArea(alignment=ALIGN_HORIZONTAL, border=2) controls.setWeight(0) button = controls.createButton( 'unhide-select-all', style=sb.widget.button.Button.STYLE_MINI) button.addReaction(selectAll) button.resizeToBestSize() button = controls.createButton( 'unhide-clear-all', style=sb.widget.button.Button.STYLE_MINI) button.addReaction(clearAll) button.resizeToBestSize() for prof in hiddenProfiles: profList.addItem(prof.getId()) if dialog.run() == 'ok': # Unhide all the selected items. selected = profList.getSelectedItems() for sel in selected: pr.show(sel) if len(selected): # Select the first one that was shown. pr.setActive(pr.get(selected[0]))
def chooseAddons(dialogId, title, actionButton): """Opens an addon selection dialog. @param title Title of the dialog. @param actionButton The button that will perform the affirmative action of the dialog. """ dialog, area = sb.util.dialog.createButtonDialog(dialogId, ['cancel', actionButton], actionButton) dialog.addEndCommand('addon-dialog-add-to-custom-folders') # The action button is disabled until a valid selection has been # made. dialog.disableWidget(actionButton) area.setWeight(0) folderArea = area.createArea(alignment=ui.ALIGN_HORIZONTAL) folderArea.setExpanding(False) folderArea.setBorder(2, ui.BORDER_NOT_LEFT) folderArea.setWeight(0) folderArea.createText('addon-dialog-folder').resizeToBestSize() folderArea.setBorderDirs(ui.BORDER_ALL) folderArea.setWeight(1) pathField = folderArea.createTextField('') pathField.setText(os.getcwd()) pathField.select() pathField.focus() folderArea.setWeight(0) folderArea.setBorderDirs(ui.BORDER_NOT_RIGHT) browseButton = folderArea.createButton('addon-dialog-folder-browse', style=wg.Button.STYLE_MINI) #folderArea.addSpacer() #folderArea.setBorderDirs(ui.BORDER_NOT_RIGHT) folderCmdArea = area.createArea(alignment=ui.ALIGN_HORIZONTAL) folderCmdArea.setExpanding(False) folderCmdArea.setBorder(6, ui.BORDER_NOT_TOP) folderCmdArea.setWeight(1) folderCmdArea.addSpacer() folderCmdArea.setWeight(0) uninstButton = folderCmdArea.createButton( 'addon-dialog-folder-uninstalled') # Add to Custom Folders button. folderCmdArea.setBorder(6, ui.BORDER_LEFT | ui.BORDER_BOTTOM) addToMyButton = folderCmdArea.createButton( 'addon-dialog-add-to-custom-folders') def goToUninstalled(): pathField.setText(paths.getUserPath(paths.UNINSTALLED)) pathField.select() addToMyButton.disable() uninstButton.addReaction(goToUninstalled) area.createText('addon-dialog-found') area.setWeight(1) foundList = area.createList('', style=sb.widget.list.List.STYLE_COLUMNS) foundList.setMinSize(500, 300) area.setWeight(0) area.createText('addon-dialog-addons-copied', maxLineLength=70).resizeToBestSize() def selectAction(): dialog.enableWidget(actionButton) foundList.addReaction(selectAction) for col, width in [('name', None), ('type', 180)]: foundList.addColumn('addon-dialog-' + col, width) def updateList(): # Update the found addons list. foundList.clear() dialog.disableWidget(actionButton) extensions = ao.getAddonExtensions() + ['manifest'] # This should be done in addons.py. fileNames = os.listdir(pathField.getText()) for name in fileNames: type = '' for ext in extensions: if paths.hasExtension(ext, name): type = ext break if not type: # Unknown files are skipped. continue # Manifests don't appear in the list if the corresponding # addon is in the same directory. if paths.hasExtension('manifest', name): foundSame = False # Identifier of the addon the manifest belongs to. manifestId = paths.getBase(name) # See if the addon is in the list. for other in fileNames: if other == name: continue if manifestId == ao.formIdentifier(other)[0]: foundSame = True break if foundSame: # Don't add it. continue foundList.addItemWithColumns( name, name, language.translate('addon-dialog-type-' + type)) # Update reactions. def pathChanged(): if os.path.exists(pathField.getText()): updateList() if pathField.getText() != paths.getUserPath(paths.UNINSTALLED): addToMyButton.enable() else: addToMyButton.disable() def browseAction(): # Show a directory browser. selection = sb.util.dialog.chooseFolder('addon-dialog-browse-prompt', pathField.getText()) if len(selection): pathField.setText(selection) pathField.select() # The initial contents of the list. updateList() pathField.addReaction(pathChanged) browseButton.addReaction(browseAction) dialog.addEndCommand(actionButton) result = dialog.run() if result == actionButton: addonFiles = map(lambda name: os.path.join(pathField.getText(), name), foundList.getSelectedItems()) # Include any associated manifests. for name in addonFiles: manifest = ao.formIdentifier(name)[0] + '.manifest' manifestFile = os.path.join(pathField.getText(), manifest) if manifest not in addonFiles and os.path.exists(manifestFile): addonFiles.append(manifestFile) #print 'including ' + manifestFile + ' due to ' + name return addonFiles elif result == 'addon-dialog-add-to-custom-folders': paths.addAddonPath(pathField.getText()) events.send(events.Notify('addon-paths-changed')) ao.refresh() return [] # The dialog was canceled. return []
def handleCommand(event): """This is called when someone sends a command event. @param event An events.Command object.""" # Figure out which addon has been currently selected in the addons # tree. The action will target this addon. selected = '' if event.hasId('refresh-addon-database'): ao.refresh() elif event.hasId('install-addon'): tab30.installer.run() elif event.hasId('uninstall-addon'): selectedItems = addonList.getSelectedItems() # Only take the uninstallable addons. addons = filter(lambda i: ao.isUninstallable(i), selectedItems) if len(addons) == 0: return # Make sure the user wants to uninstall. dialog, area = sb.util.dialog.createButtonDialog( 'uninstall-addon-dialog', ['no', 'yes'], 'no', resizable=False) if len(addons) == 1: text = language.translate('uninstall-addon-query') area.setExpanding(True) area.createRichText(language.expand(text, language.translate(addons[0]))) else: area.setWeight(0) area.createText('uninstall-addon-query-several') msg = '<html><ul>' for addon in addons: msg += '<li>' + language.translate(addon) + '</li>' msg += '</ul></html>' ft = area.createFormattedText() ft.setText(msg) ft.setMinSize(400, 150) if dialog.run() == 'yes': for addon in addons: ao.uninstall(addon) ao.refresh() elif event.hasId('addon-info'): sel = addonList.getSelectedItems() if len(sel) > 0: # Show the Addon Inspector. tab30.inspector.run(ao.get(sel[0])) elif event.hasId('addon-settings'): sel = addonList.getSelectedItems() if len(sel) > 0: command = events.Command('show-addon-settings') command.addon = sel[0] events.send(command) elif event.hasId('load-order'): # Open the Load Order dialog. tab30.loadorder.run(pr.getActive()) elif event.hasId('addon-list-check-selected'): for addon in addonList.getSelectedItems(): pr.getActive().useAddon(addon) elif event.hasId('addon-list-uncheck-selected'): for addon in addonList.getSelectedItems(): pr.getActive().dontUseAddon(addon) elif event.hasId('addon-list-check-all'): for addon in addonList.getItems(): pr.getActive().useAddon(addon) elif event.hasId('addon-list-uncheck-all'): for addon in addonList.getItems(): pr.getActive().dontUseAddon(addon) elif event.hasId('addon-show-parent-box'): for addon in addonList.getSelectedItems(): a = ao.get(addon) if a.getBox(): showInAddonList(a.getBox().getId()) break elif event.hasId('addon-show-box-category'): for addon in addonList.getSelectedItems(): a = ao.get(addon) if a.getType() == 'addon-type-box': addonList.deselectAllItems() tree.selectItem(a.getContentCategoryLongId()) refreshListIfVisible() break