def handle_response(self, oDialog): """Handle the response from the config dialog""" iResponse = oDialog.run() if iResponse == Gtk.ResponseType.OK: oFile, bDir, bDownload, bDownloadExpansions = oDialog.get_data() if bDir: # New directory if self._accept_path(oFile): # Update preferences self.image_frame.update_config_path(oFile) self._activate_menu() elif oFile: if self._unzip_file(oFile): self._activate_menu() else: do_complaint_error('Unable to successfully unzip data') oFile.close() # clean up temp file else: # Unable to get data do_complaint_error('Unable to configure card images plugin') # Update download option self.set_config_item(DOWNLOAD_IMAGES, bDownload) self.set_config_item(DOWNLOAD_EXPANSIONS, bDownloadExpansions) # Reset expansions settings if needed self.image_frame.check_images() # get rid of the dialog oDialog.destroy()
def _get_cards(self): """Extract card details from the card set.""" oCryptFilter = CryptCardFilter() self.aCrypt = get_cards_filter(self.model, oCryptFilter) self.aLibrary = get_cards_filter(self.model, FilterNot(oCryptFilter)) if len(self.aLibrary) < 7: do_complaint_error('Library needs to be at least as large as the' ' opening hand') return False if len(self.aCrypt) < 4: do_complaint_error('Crypt needs to be at least as large as the' ' opening draw') return False for sType in MultiCardTypeFilter.get_values(): aList = get_cards_filter(self.model, CardTypeFilter(sType)) if aList and aList[0] in self.aLibrary: self.dCardTypes[sType] = set([oC.name for oC in aList]) for sFunction in CardFunctionFilter.get_values(): aList = get_cards_filter(self.model, CardFunctionFilter(sFunction)) if aList: self.dCardProperties[sFunction] = set([oC.name for oC in aList]) return True
def post_set_card_text(self, _sSignal, oPhysCard): """Update the card text pane with the 'show merged', etc. buttons""" self._oAbsCard = oPhysCard.abstractCard self._oFakeCard = None if self._oAbsCard.level is None: if self._oAbsCard not in self._aBaseVamps: return if self._oAbsCard in self._aExcluded: return try: self._oFakeCard = FakeCard(self._oAbsCard, self._dReplaceMap) except SQLObjectNotFound as oExc: do_complaint_error("Unable to created merged vampire for %s" % self._oAbsCard.name) self._aExcluded.add(self._oAbsCard) logging.warning("Merged vampire creation failed (%s).", oExc, exc_info=1) return oCardTextView = self.parent.card_text_pane.view # Button logic # For the normal view, we show the buttons # "Merged" and "Other version" (Base / Advanced) # Because of how add_button_to_text is implemented, we # add the second button first if self._oAbsCard.level is None: oCardTextView.add_button_to_text(self._oAdv, " ") else: oCardTextView.add_button_to_text(self._oBase, " ") oCardTextView.add_button_to_text(self._oMerged, "\n ")
def activate(self, _oWidget): """Generate the PDF file""" oPrintOp = Gtk.PrintOperation() if self._oSettings: oPrintOp.set_print_settings(self._oSettings) oPrintOp.connect("begin-print", self.begin_print) oPrintOp.connect("end-print", self.end_print) oPrintOp.connect("draw-page", self.draw_page) oPrintOp.set_custom_tab_label('Proxy Set Print Settings') dCustomData = {} oPrintOp.connect('create-custom-widget', self._add_print_widgets, dCustomData) oPrintOp.connect('custom-widget-apply', self._get_print_widgets, dCustomData) oRes = oPrintOp.run(Gtk.PrintOperationAction.PRINT_DIALOG, self.parent) if self._aMissing: # We aborted due to missing cards aErrors = [ "Error printing card set.", "Unable to load images for the following cards:" ] aErrors.extend(sorted(self._aMissing)) sErr = '\n'.join(aErrors) do_complaint_error(sErr) elif oRes == Gtk.PrintOperationResult.ERROR: do_complaint_error("Error printing card set:\n" + oPrintOp.get_error()) elif oRes == Gtk.PrintOperationResult.APPLY: self._oSettings = oPrintOp.get_print_settings()
def do_update(self): """Handle the 'download stuff' respone from the startup check""" sPrefsValue = self.get_config_item('twda configured') if sPrefsValue.lower() != 'yes': return aUrls, aDates, aHashes = find_all_data_packs( 'twd', fErrorHandler=gui_error_handler) if not self._get_decks(aUrls, aDates, aHashes): do_complaint_error("Didn't find any TWD data to download")
def find_twda(self, _oWidget, sMode): """Find decks which match the given search""" # Only want the distinct cards - numbers are unimportant aAbsCards = set(self._get_selected_abs_cards()) if not aAbsCards: do_complaint_error('Need to select some cards for this plugin') return if len(aAbsCards) > 20: do_complaint_error('Too many cards selected (%d). Please select ' 'no more than 20 cards' % len(aAbsCards)) return aCardFilters = [] iTotCards = len(aAbsCards) for oCard in aAbsCards: aCardFilters.append(SpecificCardFilter(oCard)) # needs to be OR, since we're matching against the card to card set # mapping table oCardFilter = FilterOrBox(aCardFilters) aNames = self._get_twda_names() oMapFilter = MultiPhysicalCardSetMapFilter(aNames) oFullFilter = FilterAndBox([oCardFilter, oMapFilter]) # pylint: disable=no-member # SQLObject confuses pylint dCardSets = {} for oMapCard in oFullFilter.select(MapPhysicalCardToPhysicalCardSet): oCS = oMapCard.physicalCardSet sCardName = IAbstractCard(oMapCard).name dCardSets.setdefault(oCS, {}) dCardSets[oCS].setdefault(sCardName, 0) dCardSets[oCS][sCardName] += 1 if sMode == 'all' and iTotCards > 1: # This is a little clunky, but, because of how we construct the # filters, we currently have the any match set, so we need to # filter this down to those that match all the cards for oCS in list(dCardSets): if len(dCardSets[oCS]) != iTotCards: # Not all, so drop this one del dCardSets[oCS] sCards = '", "'.join(sorted([x.name for x in aAbsCards])) if sMode == 'any': sMatchText = 'Matching ANY of "%s"' % sCards else: sMatchText = 'Matching ALL of "%s"' % sCards # Create a dialog showing the results if dCardSets: oDlg = self._fill_dlg(dCardSets, sMatchText) else: oDlg = self._empty_dlg(sMatchText) oDlg.set_default_size(700, 600) oDlg.show_all() oDlg.show()
def _get_decks(self, aUrls, aDates, aHashes): """Unzip a file containing the decks.""" aZipHolders = [] aToUnzip, aToReplace = self._get_decks_to_download(aUrls, aDates, aHashes) if not aToUnzip: return False # We download everything first, so we don't delete card sets which # fail to download. oBinLogHandler = BinnedCountLogHandler() oProgressDialog = ProgressDialog() oProgressDialog.set_description("Downloading TWDA data") oLogger = Logger('Download zip files') oLogger.addHandler(oBinLogHandler) oBinLogHandler.set_dialog(oProgressDialog) oBinLogHandler.set_tot_bins(len(aToUnzip)) oProgressDialog.show() # We sort the list of urls to download for cosmetic reasons for sUrl, sTWDA, sHash in sorted(aToUnzip, key=lambda x: x[1]): oFile = urlopen_with_timeout(sUrl, fErrorHandler=gui_error_handler, bBinary=True) oProgressDialog.set_description('Downloading %s' % sTWDA) try: sData = fetch_data(oFile, sHash=sHash, oLogHandler=oBinLogHandler, fErrorHandler=gui_error_handler) except HashError: do_complaint_error("Checksum failed for %s\nSkipping" % sTWDA) # Don't delete this, since we're not replacing it aToReplace.remove(sTWDA) continue oZipFile = ZipFileWrapper(BytesIO(sData)) aZipHolders.append(oZipFile) oBinLogHandler.inc_cur_bin() oProgressDialog.destroy() # Bomb out if we're going to end up doing nothing if not aZipHolders: return False # Delete all TWDA entries in the holders we replace # We do this to handle card sets being removed from the TWDA # correctly aToDelete = [] for oCS in list(PhysicalCardSet.select()): if not oCS.parent: continue if oCS.parent.name in aToReplace: aToDelete.append(oCS.name) return unzip_files_into_db(aZipHolders, "Adding TWDA Data", self.parent, aToDelete)
def handle_response(self, sFilename): """Actually do the export""" if sFilename is None: return oCardSet = self._get_card_set() if not oCardSet: return dDeck = json.loads(DECK_TEMPLATE) aCrypt = [] aLibrary = [] for oCard in oCardSet.cards: # Need to turn name into the JSON file version sJSONName = make_json_name(oCard.abstractCard) sAltName = make_alternative_json_name(oCard.abstractCard) if sJSONName not in self._dTTSData: # Check if it's just using the card name instead if sAltName not in self._dTTSData: do_complaint_error("Unable to find an entry for %s (%s)" % (oCard.abstractCard.name, sJSONName)) logging.warning("Unable to find an entry for %s (%s)", oCard.abstractCard.name, sJSONName) return sJSONName = sAltName if is_crypt_card(oCard.abstractCard): aCrypt.append(sJSONName) else: aLibrary.append(sJSONName) dCrypt = dDeck['ObjectStates'][0] dLibrary = dDeck['ObjectStates'][1] for sName in sorted(aCrypt): oObj = self._dTTSData[sName] dTTSCard = oObj.copy() dTTSCard['Transform'] = CRYPT_TRANSFORM dCrypt['DeckIDs'].append(dTTSCard['CardID']) dCrypt['CustomDeck'].update(dTTSCard['CustomDeck']) dCrypt['ContainedObjects'].append(dTTSCard) for sName in sorted(aLibrary): oObj = self._dTTSData[sName] dTTSCard = oObj.copy() dTTSCard['Transform'] = LIB_TRANSFORM dLibrary['DeckIDs'].append(dTTSCard['CardID']) dLibrary['CustomDeck'].update(dTTSCard['CustomDeck']) dLibrary['ContainedObjects'].append(dTTSCard) with open(sFilename, 'w') as oFile: json.dump(dDeck, oFile, indent=2)
def handle_response(self, oDialog): """Handle the response from the config dialog""" iResponse = oDialog.run() if iResponse == Gtk.ResponseType.OK: sData = oDialog.get_data() (bExcludeStoryDecks, bExcludeDemoDecks) = \ oDialog.get_excluded_decks() if not sData: do_complaint_error('Unable to access zipfile data') elif not self._unzip_file(sData, bExcludeStoryDecks, bExcludeDemoDecks): do_complaint_error('Unable to successfully unzip zipfile') if self.check_enabled(): self.oToggle.set_sensitive(True) else: self.oToggle.set_sensitive(False) # cleanup oDialog.destroy()
def _make_cs(self, _oButton, oDlg): """Create a card set with the given cards""" # pylint: disable=no-member # SQLObject confuses pylint oView = oDlg.get_cur_widget().get_child() aCards = oView.get_selected_cards() if not aCards: do_complaint_error("No cards selected for card set.") return sCSName = create_card_set(self.parent) if sCSName: oCardSet = IPhysicalCardSet(sCSName) for oCard in aCards: # We add with unknown expansion # pylint: disable=no-member # SQLObject confuses pylint oCardSet.addPhysicalCard(IPhysicalCard((oCard, None))) self._open_cs(sCSName, True)
def do_update(self): """Download the starter decks, if requested.""" sPrefsValue = self.get_config_item('show starters') # Only check if we're meant to show the starters if sPrefsValue.lower() != 'yes': return aUrls, aDates, aHashes = find_all_data_packs( 'starters', fErrorHandler=gui_error_handler) if self._check_for_starters_to_download(aUrls[0], aDates[0]): # Check to see if cards are available bExcludeDemoDecks = False bExcludeStorylineDecks = False try: _oSkip = IRarityPair(('White Wolf 2003 Demo', 'Demo')) except SQLObjectNotFound: bExcludeDemoDecks = True try: _oSkip = IRarityPair(('Nergal Storyline', 'Storyline')) except SQLObjectNotFound: bExcludeStorylineDecks = True oHolder = find_holder(STARTER_HOLDERS) if oHolder: # We assume missing Holders are due to user choice, so we # try to honour those. People can always use the explicit # download option to recover accidental deletions if not bExcludeDemoDecks: bExcludeDemoDecks = find_holder(DEMO_HOLDERS) is None if not bExcludeStorylineDecks: bExcludeStorylineDecks = \ find_holder(STORYLINE_HOLDERS) is None oFile = urlopen_with_timeout(aUrls[0], fErrorHandler=gui_error_handler, bBinary=True) if oFile: sData = progress_fetch_data(oFile, None, aHashes[0]) else: sData = None if not sData: do_complaint_error('Unable to access zipfile data') elif not self._unzip_file(sData, bExcludeStorylineDecks, bExcludeDemoDecks): do_complaint_error('Unable to successfully unzip zipfile')
def _check_selection(self, aSelectedCards): """Check that selection is useable.""" bCrypt = False bLibrary = False for oCard in aSelectedCards: # pylint: disable=simplifiable-if-statement # pylint misidentifies this because it misses the loop if is_crypt_card(oCard): bCrypt = True else: bLibrary = True # Check that selection doesn't mix crypt and libraries if bLibrary and bCrypt: do_complaint_error("Can't operate on selections including both" " Crypt and Library cards") return False # Store this for later queries self.bCrypt = bCrypt return True
def _make_pcs_from_cluster(self, iClusterId): """Create a Card Set from the chosen cluster""" sDeckName = '_cluster_deck_%d' % (iClusterId, ) # Check Deck Doesn't Exist if check_cs_exists(sDeckName): do_complaint_error("Card Set %s already exists." % sDeckName) return # Create Deck oDeck = PhysicalCardSet(name=sDeckName) # pylint: disable=no-member # SQLObject confuses pylint aCards = [ IPhysicalCard(self._aCards[x]) for x in self._aClusters[iClusterId] ] self._commit_cards(oDeck, aCards) self._open_cs(sDeckName, True)
def handle_response(self, oDialog): """Handle running and responding to the download dialog""" iResponse = oDialog.run() if iResponse == Gtk.ResponseType.OK: if oDialog.is_url(): aUrls, aDates, aHashes = oDialog.get_url_data() if not aUrls: do_complaint_error('Unable to access TWD data') elif not self._get_decks(aUrls, aDates, aHashes): do_complaint_error( "Didn't find any TWD data to download") else: # Successful download, so we're configured self.set_config_item('twda configured', 'Yes') else: if self._unzip_twda_file(oDialog.get_file_data()): # Success, so we're configured self.set_config_item('twda configured', 'Yes') # cleanup oDialog.destroy()
def activate(self, _oWidget): """Create the dialog. Prompt the user for attributes that are important and so forth """ self.oSelCard = self._get_selected_crypt_card() if not self.oSelCard: do_complaint_error("Please select only 1 crypt card.") return # We treat imbued and vampires differently # pylint: disable=no-member # SQLObject confuses pylint if is_vampire(self.oSelCard): if not self.oSelCard.discipline: do_complaint_error("Please select a vampire with disciplines.") return dGroups = self.find_vampires_like() else: if not self.oSelCard.virtue: do_complaint_error("Please select an Imbued with virtues.") return dGroups = self.find_imbued_like() if dGroups: self.display_results(dGroups)
def _complain_size(self): """Correct complaint about the number of cards.""" if self.bCrypt: do_complaint_error("Crypt must be larger than the opening draw") else: do_complaint_error("Library must be larger than the opening hand")