class MasterTestCase(OfficeTestCase): def setUp(self): super().setUp() self.master = Master(MASTER_LIST_SHEET_NAME) self.actions = self.master.getActions() def testMasterInstance(self): self.assertIsInstance(self.master.data, list) self.assertEqual(self.master.name, MASTER_LIST_SHEET_NAME) self.assertEqual(len(self.master.actionColors), len(self.master.dataRows)) def testGetActions(self): self.assertIsInstance(self.actions, list) self.assertTrue(self.actions) for action in self.actions: self.assertIsInstance(action, Action) def testGetActionsForView(self): actions = self.master.getActions('Target') self.assertTrue(actions[0].name, 'Minotaur (Idle)') def testGetDefaultActions(self): actions = self.master.getActions('Default') self.assertNotEqual(len(self.master.getActions()), len(actions))
def testSetVerticalAlignmentToRange(self): """ A test that sets vertical alignment to a range and then tests if it's what it should be. """ sheet = Master(MASTER_LIST_SHEET_NAME).sheet format.setVerticalAlignmentToRange(sheet, VerticalAlignment.CENTER, 1, 10, 20, 25) cellRange = sheet.getCellRangeByPosition(1, 10, 20, 25) self.assertEqual(cellRange.VertJustify, CENTER)
def testSetHorizontalAlignmentToRange(self): """ A test that sets horizontal alignment to a range and then tests if it's what it should be. """ sheet = Master(MASTER_LIST_SHEET_NAME).sheet format.setHorizontalAlignmentToRange(sheet, HorizontalAlignment.RIGHT, 1, 4) area = cursor.getSheetContent(sheet) cellRange = sheet.getCellRangeByPosition(1, 0, 1 + 4, len(area) - 1) self.assertEqual(cellRange.HoriJustify, RIGHT)
def testActionConditionalFormats(self): masterSheet = Master(MASTER_LIST_SHEET_NAME) detailsUnoSheet = Sheet.getByName(self.detailsName) actionConditionalFormat = conditionalFormat.createActionConditionalFormats( detailsUnoSheet, masterSheet, self.view) self.assertGreater(actionConditionalFormat.getCount(), 0) self.assertIn('Entry1', actionConditionalFormat.getElementNames())
def _readSheetContent(self): # We need master sheet to get number of phases for each Action in the # Detail class. Details sheet doesn't provide enough information. self.masterSheet = Master(MASTER_LIST_SHEET_NAME) self.sheet = Sheet.getByName(self.name) self.data = cursor.getSheetContent(self.sheet) self.nameColumnIndex = helper.getColumnPosition( self.data, 'Action Name', 0) self.modifiersColumnIndex = helper.getColumnPosition( self.data, 'Modifiers', 1) self.inputToCompareColumnIndex = helper.getColumnPosition( self.data, 'Input to Compare', 2) self.notesIndex1 = helper.getColumnPosition(self.data, 'Notes 1', 3) self.notesIndex2 = helper.getColumnPosition(self.data, 'Notes 2', 4) self.notesIndex3 = helper.getColumnPosition(self.data, 'Notes 3', 5) self.dataRows = self._dataRows() self.details = self._readDetails()
def testFilterBy(self): master = Master(MASTER_LIST_SHEET_NAME) filteredRows = filter.filterRows( lambda row: row[master.viewColumnIndex] == 'Default', master.dataRows) self.assertTrue(filteredRows) for row in filteredRows: self.assertEqual(row[master.viewColumnIndex], 'Default')
def updateDetails(*args, **kwargs): """ A macro function that will update one Details-sheet while preserving previous user data. Movelister can have multiple Details-views. To determine which one is updated, the code checks which Overview button was pressed to trigger the macro. """ try: if not Sheet.checkTemplatesExists(): message_box.showWarningWithOk( 'This file doesn\'t seem to have all necessary templates. Can\'t generate.' ) return # Get Overview sheet name from active sheet or from provided kwargs. activeOverviewName = kwargs.get('activeSheet', helper.getActiveSheetName()) # Get view name for the Details. This is presented in Overview sheet name inside parentheses. viewName = names.getViewName(activeOverviewName) detailsSheetName = names.getDetailsName(viewName) previousDetails = Details(viewName) if Sheet.hasByName(detailsSheetName): # Check if user wants to update existing Details-sheet. if not message_box.showSheetUpdateWarning(): return previousDetails = Details.fromSheet(detailsSheetName) modifiersSheet = Modifiers(MODIFIER_LIST_SHEET_NAME) parentOverview = Overview.fromSheet(activeOverviewName) # Create new Details sheet by combining new and existing data. newDetails = UpdateDetails.update(modifiersSheet, parentOverview, previousDetails, viewName) # Delete previous Details-sheet and generate a new one. Sheet.deleteSheetByName(detailsSheetName) formatter = DetailsFormatter(newDetails, parentOverview) unoDetailsSheet = formatter.generate() # Make columns width optimal. length = cursor.getWidth(unoDetailsSheet) format.setOptimalWidthToRange(unoDetailsSheet, 0, length) # Generate data validation. validation.setDataValidationToDetailsSheet(unoDetailsSheet, viewName) # Generate named ranges. about = About(ABOUT_SHEET_NAME) if about.isGenerateNamedRangesOn(): NamedRanges(unoDetailsSheet, 0, viewName).generate() # Generate cell styles used for details sheet. UpdateStyles.update() # Create conditional format ranges to the new details sheet which uses # styles created above. masterSheet = Master(MASTER_LIST_SHEET_NAME) resultsSheet = Results(RESULT_LIST_SHEET_NAME) inputSheet = Inputs(INPUT_LIST_SHEET_NAME) conditionalFormat.createDetailsConditionalFormats( unoDetailsSheet, masterSheet, resultsSheet, inputSheet, viewName) # Set new sheet as currently active sheet. helper.setActiveSheet(unoDetailsSheet) except errors.MovelisterError as e: helper.setActiveSheet(e.activeSheet) message_box.showWarningWithOk(str(e))
def update(cls): """ Remove all old non-default styles and create new ones from sheets Results, Inputs and Master List. """ cls.resultsSheet = Results(RESULT_LIST_SHEET_NAME) cls.inputsSheet = Inputs(INPUT_LIST_SHEET_NAME) cls.masterSheet = Master(MASTER_LIST_SHEET_NAME) cls._removeOldStyles() cls._createStyles()
def testCreateOverview(self): master = Master(MASTER_LIST_SHEET_NAME) viewName = 'Default' overview = OverviewFactory.createOverview(master, viewName) modifiers = [ 'WPN1', 'WPN2', 'WPN3', 'Super', 'FL1', 'FL2', 'PG', 'LAM', 'PAM', 's_b', 't_b' ] actions = [ 'Attack s1', 'Attack s2', 'Attack s3', 'Attack s4', 'Swim', 'Rush' ] self.assertEqual(overview.name, 'Overview ({0})'.format(viewName)) self.assertEqual(overview.viewName, viewName) self.assertTrue( all(modifier.name in modifiers for modifier in overview.modifiers)) self.assertTrue( all(modAction.name in actions for modAction in overview.actions))
def updateOverview(*args, **kwargs): """ A macro function to update or create a new Overview sheet. Updated sheet will include earlier user data in the old Overview if any. """ try: if not Sheet.checkTemplatesExists(): message_box.showWarningWithOk( 'This file doesn\'t seem to have all necessary templates. Can\'t generate.' ) return # Get name of the Overview which user wants to generate. masterSheet = Master(MASTER_LIST_SHEET_NAME) activeSheetName = kwargs.get('activeSheet', '') if activeSheetName == '': viewName = masterSheet.getOverviewName() overviewSheetName = names.getOverviewName(viewName) else: viewName = names.getViewName(activeSheetName) overviewSheetName = activeSheetName # Some error checking. if not viewName: message_box.showWarningWithOk( 'You can\'t generate an Overview if no View-name is set in cell C1.' ) return if viewName not in masterSheet.getViewNames(): message_box.showWarningWithOk( 'You can\'t generate a View that has no Actions. Make sure at least one ' + 'Action uses the View-name written in cell C1 before continuing.' ) return oldOverview = Overview(viewName) # If document has existing Overview, then that is set as previous instead. if Sheet.hasByName(overviewSheetName): # Check if user wants to update existing Overview. if not message_box.showSheetUpdateWarning(): return oldOverview = Overview.fromSheet(overviewSheetName) newOverview = UpdateOverview.update(oldOverview, viewName) # Place new Overview sheet on the same position as the previous one. If previous one # does not exist, then place right of the Master sheet instead. position = Sheet.getPosition(overviewSheetName) if not position: position = Sheet.getPosition(MASTER_LIST_SHEET_NAME) + 1 # Delete old sheet if exists. Sheet.deleteSheetByName(overviewSheetName) # Generate a new one. formatter = OverviewFormatter(newOverview) unoOverviewSheet = formatter.generate(position) # Make columns width optimal. length = cursor.getWidth(unoOverviewSheet) format.setOptimalWidthToRange(unoOverviewSheet, 0, length) # Fix sheet colors. formatter.setOverviewModifierColors(overviewSheetName) # Set new sheet as currently active sheet. helper.setActiveSheet(unoOverviewSheet) except errors.MovelisterError as e: helper.setActiveSheet(e.activeSheet) message_box.showWarningWithOk(str(e))
def setUp(self): super().setUp() self.master = Master(MASTER_LIST_SHEET_NAME)
def setUp(self): super().setUp() self.master = Master(MASTER_LIST_SHEET_NAME) self.actions = self.master.getActions()
def _updateLatestActions(cls, viewName): """ Update latest actions filtered by given view name and add them to new overview. """ masterSheet = Master(MASTER_LIST_SHEET_NAME) cls.newOverview.actions = masterSheet.getActions(viewName)
class Details: def __init__(self, viewName): self.name = names.getDetailsName(viewName) self.viewName = viewName self.details = [] @classmethod def fromSheet(cls, sheetName): """ Build instance of Detail from given sheet name which should represents current details sheet. """ instance = cls(names.getViewName(sheetName)) instance._readSheetContent() return instance def addDetail(self, detail): self.details.append(detail) def findDetail(self, seekedDetail): """ Find given details instance from this Details sheet. Return it if it's found, otherwise return None. """ return next( (detail for detail in self.details if detail == seekedDetail), None) def _readSheetContent(self): # We need master sheet to get number of phases for each Action in the # Detail class. Details sheet doesn't provide enough information. self.masterSheet = Master(MASTER_LIST_SHEET_NAME) self.sheet = Sheet.getByName(self.name) self.data = cursor.getSheetContent(self.sheet) self.nameColumnIndex = helper.getColumnPosition( self.data, 'Action Name', 0) self.modifiersColumnIndex = helper.getColumnPosition( self.data, 'Modifiers', 1) self.inputToCompareColumnIndex = helper.getColumnPosition( self.data, 'Input to Compare', 2) self.notesIndex1 = helper.getColumnPosition(self.data, 'Notes 1', 3) self.notesIndex2 = helper.getColumnPosition(self.data, 'Notes 2', 4) self.notesIndex3 = helper.getColumnPosition(self.data, 'Notes 3', 5) self.dataRows = self._dataRows() self.details = self._readDetails() def _dataRows(self): data = self.data[1:] return helper.stripTrailingEmptyRows(data) def _readDetails(self): # If details sheet is empty return. if not self.dataRows: return [] currentName = '' currentMod = '' tempArray = [] details = [] filteredData = filter.filterRows( lambda row: row[self.nameColumnIndex] != '', self.dataRows) # Create an unused action to the array so that the loop can register all legit actions. emptyRow = helper.createEmptyRow(len(filteredData[0])) emptyRow[self.nameColumnIndex] = 'Unused' emptyRow[self.inputToCompareColumnIndex] = 'Unused' filteredData.append(emptyRow) # Iterate through filteredData to find out which rows contain relevant data for a single Detail. # Then send the relevant rows to _parseArrayIntoDetail function. for row in filteredData: if row[self.nameColumnIndex] != currentName or row[ self.modifiersColumnIndex] != currentMod: currentName = row[self.nameColumnIndex] currentMod = row[self.modifiersColumnIndex] if tempArray != []: detail = self._parseArrayIntoDetail(tempArray) tempArray = [] if not detail: continue details.append(detail) tempArray.append(row) return details def _parseArrayIntoDetail(self, data): """ This function goes through rows to parse everything that belongs to a single Detail, then returns the data inside a Detail object. """ # TODO: Clean this up to separate functions. # collect Input column. inputList = [] for line in data: inputList.append(line[2]) # collect everything from the phases. Data won't be ordered. phasesList = {} notesList = {} for line in data: cellNum = 2 counter = -1 for cell in line: counter = counter + 1 cellNum = cellNum + 1 # stops the loop and gathers notes-related data once the phases end. if cellNum == self.notesIndex1: notesList[line[2]] = [ line[self.notesIndex1], line[self.notesIndex2], line[self.notesIndex3] ] break # ensures the data is taken from the first column of a phase. if counter == 3: counter = 0 # takes data from the three cells of a single phase and places them in a list inside the dict. if counter == 0: if line[2] not in phasesList: phasesList[line[2]] = [] phasesList[line[2]].append( Result(line[cellNum], line[cellNum + 1], line[cellNum + 2])) modifiers = self._parseModifiers(data[0][self.modifiersColumnIndex]) action = self.masterSheet.findAction(self.viewName, data[0][self.nameColumnIndex]) # If Action instance was not found then user must have removed it. if not action: return None detail = Detail(action, modifiers) detail.inputs = inputList detail.phases = phasesList detail.notes = notesList return detail def _parseModifiers(self, modifierCell): """ Parse string of modifier names to list of Modifier instances. For example 'WPN1 WPN2' will be two Modifier instances. """ modifiers = [] pattern = re.compile(r'\b\w+\b') for name in re.findall(pattern, modifierCell): modifiers.append(Modifier(name)) return modifiers