# -*- coding: utf-8 -*- from __future__ import unicode_literals from functools import reduce import uno from com.sun.star.awt.MessageBoxType import MESSAGEBOX, INFOBOX, WARNINGBOX, ERRORBOX, QUERYBOX from com.sun.star.awt.MessageBoxButtons import BUTTONS_OK, BUTTONS_OK_CANCEL, BUTTONS_YES_NO, BUTTONS_YES_NO_CANCEL, BUTTONS_RETRY_CANCEL, BUTTONS_ABORT_IGNORE_RETRY from com.sun.star.awt.MessageBoxResults import OK, YES, NO, CANCEL from com.sun.star.sheet import CellFlags if 'XSCRIPTCONTEXT' in globals(): def getModel(): return XSCRIPTCONTEXT.getDocument() def debug(msg): return else: print("dev") from dev import getModel, debug def Main(*args): doc = getModel() profilSheet = doc.Sheets[0] valueSheet = doc.Sheets[1] rankingSheet = doc.Sheets[2] ClearSheet(valueSheet) ClearSheet(rankingSheet) profilCursor = getUsedArea(profilSheet) profilRange = profilCursor.RangeAddress profilData = list(map(lambda x: list(x), list(profilCursor.getDataArray()))) nChoices = len(profilData) - 1 nGrades = len(profilData[0]) - 1 nJudges = sumCells(profilData[1][1:nGrades+1]) debug("nJudges:"+str(nJudges)) debug("profilData:"+str(profilData)) valueData = [] for choice in range(1,nChoices+1): choiceGrades = profilData[choice] choiceJudges = sumCells(choiceGrades[1:nGrades+1]) debug("choice:"+str(choice)) debug(" choiceJudges:"+str(choiceJudges)) debug(" choiceGrades:"+str(choiceGrades)) # Check profilData consistency if choiceJudges != nJudges: MsgBox(ERRORBOX, BUTTONS_OK, "MajorityJudgment", \ "Choice "+choiceGrades[0]+" has "+str(choiceJudges)+" judgments" \ + "\nbut the first choice has "+str(nJudges)+" judgments." \ + "\nAborting. Fix the profil and retry.") return -1 # Seek medianGrade nJudgesLower = 0 medianGrade = 0 while nJudgesLower*2 < nJudges: medianGrade = medianGrade + 1 nJudgesLower = nJudgesLower + intOfCell(choiceGrades[medianGrade]) debug(" medianGrade:"+str(medianGrade)) # Extend choiceValue with the overflow of the lower judgments choiceValue = [choiceGrades[0]] valueCol = 1 lowerMedianGrade = medianGrade higherMedianGrade = medianGrade + 1 nJudgesHigher = nJudges - nJudgesLower while nJudgesLower > nJudgesHigher: while intOfCell(choiceGrades[lowerMedianGrade]) == 0: lowerMedianGrade -= 1 choiceGrades[lowerMedianGrade] -= 1 choiceValue.append(lowerMedianGrade-1) nJudgesLower -= 1 valueCol += 1 # Extend choiceValue by alterning between lower and higher judgments while valueCol < nJudges: valueCol += 2 while intOfCell(choiceGrades[lowerMedianGrade]) == 0: lowerMedianGrade -= 1 while intOfCell(choiceGrades[higherMedianGrade]) == 0: higherMedianGrade += 1 choiceValue.append(lowerMedianGrade-1) choiceValue.append(higherMedianGrade-1) choiceGrades[lowerMedianGrade] -= 1 choiceGrades[higherMedianGrade] -= 1 # Fill valueData valueData.append(choiceValue) # Write into rankingSheet the profilData sorted according to valueData profilData = list(profilCursor.getDataArray()) rankingData = list(zip(profilData[1:nChoices+1], valueData)) rankingData.sort(key=lambda data: data[1][1:nJudges+1]) rankingData.reverse() valueData = list(map(lambda data: data[1], rankingData)) rankingData = [list(profilData[0])]+list(map(lambda data: data[0], rankingData)) debug("rankingData:"+str(rankingData)) rankingRange = rankingSheet.getCellRangeByPosition( \ profilRange.StartColumn, \ profilRange.StartRow, \ profilRange.EndColumn, \ profilRange.EndRow ) rankingRange.setDataArray(rankingData) # Write valueData into valueSheet debug("valueData:"+str(valueData)) for value in valueData: base = nGrades debug("base:"+str(base)) digits = list(map(lambda v: v, value[1:nJudges+1])) rank = inBase(base, digits) rankMax = base ** nJudges - 1 debug("digits:"+str(digits)) debug("rank:"+str(rank)) debug("rankMax:"+str(rankMax)) value.insert(1,rank / rankMax) debug("valueData:"+str(valueData)) valueRange = valueSheet.getCellRangeByPosition( \ profilRange.StartColumn, \ 1+profilRange.StartRow, \ profilRange.StartColumn + 1 + nJudges, \ profilRange.EndRow ) valueRange.setDataArray(valueData) def inBase(base, digits): acc = 0 for digit in digits: acc = digit + (base * acc) return acc def intOfCell(cell): return int(cell) if cell != '' else 0 def sumCells(cells): return reduce(lambda x,y: intOfCell(x) + intOfCell(y), cells) def getUsedArea(sheet): profilCursor = sheet.createCursor() profilCursor.gotoStartOfUsedArea(False) profilCursor.gotoEndOfUsedArea(True) return profilCursor def ClearSheet(sheet): cursor = sheet.createCursor() cursor.gotoStartOfUsedArea(False) cursor.gotoEndOfUsedArea(True) rangeAddress = cursor.RangeAddress range = sheet.getCellRangeByPosition( \ rangeAddress.StartColumn, \ rangeAddress.StartRow, \ rangeAddress.EndColumn, \ rangeAddress.EndRow ) flags = CellFlags.VALUE | \ CellFlags.DATETIME | \ CellFlags.STRING | \ CellFlags.ANNOTATION | \ CellFlags.FORMULA | \ CellFlags.HARDATTR | \ CellFlags.STYLES | \ CellFlags.OBJECTS | \ CellFlags.EDITATTR range.clearContents(flags) def MsgBox(msgtype, buttons, title, message): doc = getModel() parentwin = doc.CurrentController.Frame.ContainerWindow toolkit = parentwin.getToolkit() msgbox = toolkit.createMessageBox(parentwin, msgtype, buttons, title, message) ret = msgbox.execute() msgbox.dispose() return ret