]> Git — Sourcephile - reloto-libreoffice.git/blob - MajorityJudgment.py
init
[reloto-libreoffice.git] / MajorityJudgment.py
1 # -*- coding: utf-8 -*-
2 from __future__ import unicode_literals
3 from functools import reduce
4 import uno
5 from com.sun.star.awt.MessageBoxType import MESSAGEBOX, INFOBOX, WARNINGBOX, ERRORBOX, QUERYBOX
6 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
7 from com.sun.star.awt.MessageBoxResults import OK, YES, NO, CANCEL
8 from com.sun.star.sheet import CellFlags
9
10 if 'XSCRIPTCONTEXT' in globals():
11 def getModel():
12 return XSCRIPTCONTEXT.getDocument()
13 def debug(msg):
14 return
15 else:
16 print("dev")
17 from dev import getModel, debug
18
19 def Main(*args):
20 doc = getModel()
21
22 profilSheet = doc.Sheets[0]
23 valueSheet = doc.Sheets[1]
24 rankingSheet = doc.Sheets[2]
25 ClearSheet(valueSheet)
26 ClearSheet(rankingSheet)
27
28 profilCursor = getUsedArea(profilSheet)
29 profilRange = profilCursor.RangeAddress
30 profilData = list(map(lambda x: list(x), list(profilCursor.getDataArray())))
31
32 nChoices = len(profilData) - 1
33 nGrades = len(profilData[0]) - 1
34 nJudges = sumCells(profilData[1][1:nGrades+1])
35 debug("nJudges:"+str(nJudges))
36 debug("profilData:"+str(profilData))
37 valueData = []
38 for choice in range(1,nChoices+1):
39 choiceGrades = profilData[choice]
40 choiceJudges = sumCells(choiceGrades[1:nGrades+1])
41 debug("choice:"+str(choice))
42 debug(" choiceJudges:"+str(choiceJudges))
43 debug(" choiceGrades:"+str(choiceGrades))
44
45 # Check profilData consistency
46 if choiceJudges != nJudges:
47 MsgBox(ERRORBOX, BUTTONS_OK, "MajorityJudgment", \
48 "Choice "+choiceGrades[0]+" has "+str(choiceJudges)+" judgments" \
49 + "\nbut the first choice has "+str(nJudges)+" judgments." \
50 + "\nAborting. Fix the profil and retry.")
51 return -1
52
53 # Seek medianGrade
54 nJudgesLower = 0
55 medianGrade = 0
56 while nJudgesLower*2 < nJudges:
57 medianGrade = medianGrade + 1
58 nJudgesLower = nJudgesLower + intOfCell(choiceGrades[medianGrade])
59 debug(" medianGrade:"+str(medianGrade))
60
61 # Extend choiceValue with the overflow of the lower judgments
62 choiceValue = [choiceGrades[0]]
63 valueCol = 1
64 lowerMedianGrade = medianGrade
65 higherMedianGrade = medianGrade + 1
66 nJudgesHigher = nJudges - nJudgesLower
67 while nJudgesLower > nJudgesHigher:
68 while intOfCell(choiceGrades[lowerMedianGrade]) == 0:
69 lowerMedianGrade -= 1
70 choiceGrades[lowerMedianGrade] -= 1
71 choiceValue.append(lowerMedianGrade-1)
72 nJudgesLower -= 1
73 valueCol += 1
74
75 # Extend choiceValue by alterning between lower and higher judgments
76 while valueCol < nJudges:
77 valueCol += 2
78 while intOfCell(choiceGrades[lowerMedianGrade]) == 0:
79 lowerMedianGrade -= 1
80 while intOfCell(choiceGrades[higherMedianGrade]) == 0:
81 higherMedianGrade += 1
82 choiceValue.append(lowerMedianGrade-1)
83 choiceValue.append(higherMedianGrade-1)
84 choiceGrades[lowerMedianGrade] -= 1
85 choiceGrades[higherMedianGrade] -= 1
86
87 # Fill valueData
88 valueData.append(choiceValue)
89
90 # Write into rankingSheet the profilData sorted according to valueData
91 profilData = list(profilCursor.getDataArray())
92 rankingData = list(zip(profilData[1:nChoices+1], valueData))
93 rankingData.sort(key=lambda data: data[1][1:nJudges+1])
94 rankingData.reverse()
95 valueData = list(map(lambda data: data[1], rankingData))
96 rankingData = [list(profilData[0])]+list(map(lambda data: data[0], rankingData))
97 debug("rankingData:"+str(rankingData))
98 rankingRange = rankingSheet.getCellRangeByPosition( \
99 profilRange.StartColumn, \
100 profilRange.StartRow, \
101 profilRange.EndColumn, \
102 profilRange.EndRow )
103 rankingRange.setDataArray(rankingData)
104
105 # Write valueData into valueSheet
106 debug("valueData:"+str(valueData))
107 for value in valueData:
108 base = nGrades
109 debug("base:"+str(base))
110 digits = list(map(lambda v: v, value[1:nJudges+1]))
111 rank = inBase(base, digits)
112 rankMax = base ** nJudges - 1
113 debug("digits:"+str(digits))
114 debug("rank:"+str(rank))
115 debug("rankMax:"+str(rankMax))
116 value.insert(1,rank / rankMax)
117 debug("valueData:"+str(valueData))
118 valueRange = valueSheet.getCellRangeByPosition( \
119 profilRange.StartColumn, \
120 1+profilRange.StartRow, \
121 profilRange.StartColumn + 1 + nJudges, \
122 profilRange.EndRow )
123 valueRange.setDataArray(valueData)
124
125 def inBase(base, digits):
126 acc = 0
127 for digit in digits:
128 acc = digit + (base * acc)
129 return acc
130
131 def intOfCell(cell):
132 return int(cell) if cell != '' else 0
133 def sumCells(cells):
134 return reduce(lambda x,y: intOfCell(x) + intOfCell(y), cells)
135 def getUsedArea(sheet):
136 profilCursor = sheet.createCursor()
137 profilCursor.gotoStartOfUsedArea(False)
138 profilCursor.gotoEndOfUsedArea(True)
139 return profilCursor
140 def ClearSheet(sheet):
141 cursor = sheet.createCursor()
142 cursor.gotoStartOfUsedArea(False)
143 cursor.gotoEndOfUsedArea(True)
144 rangeAddress = cursor.RangeAddress
145 range = sheet.getCellRangeByPosition( \
146 rangeAddress.StartColumn, \
147 rangeAddress.StartRow, \
148 rangeAddress.EndColumn, \
149 rangeAddress.EndRow )
150 flags = CellFlags.VALUE | \
151 CellFlags.DATETIME | \
152 CellFlags.STRING | \
153 CellFlags.ANNOTATION | \
154 CellFlags.FORMULA | \
155 CellFlags.HARDATTR | \
156 CellFlags.STYLES | \
157 CellFlags.OBJECTS | \
158 CellFlags.EDITATTR
159 range.clearContents(flags)
160 def MsgBox(msgtype, buttons, title, message):
161 doc = getModel()
162 parentwin = doc.CurrentController.Frame.ContainerWindow
163 toolkit = parentwin.getToolkit()
164 msgbox = toolkit.createMessageBox(parentwin, msgtype, buttons, title, message)
165 ret = msgbox.execute()
166 msgbox.dispose()
167 return ret