4 # Copyright (C) 2010 Stefanos Harhalakis
6 # This file is part of maegirls.
8 # maegirls is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
13 # maegirls is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with maegirls. If not, see <http://www.gnu.org/licenses/>.
21 # $Id: 0.py 2265 2010-02-21 19:16:26Z v13 $
23 __version__ = "$Id: 0.py 2265 2010-02-21 19:16:26Z v13 $"
25 from PyQt4.QtGui import *
26 from PyQt4.QtCore import *
32 from graph import DaysGraph
39 class ConfigDialog(QDialog):
40 def __init__(self, *args, **kwargs):
41 QDialog.__init__(self, *args, **kwargs)
43 self.editName=QLineEdit(self)
44 self.editCycle=QSpinBox(self)
45 self.editCurrent=QSpinBox(self)
46 self.editCycle.setRange(10,50)
47 self.editCurrent.setRange(1,50)
48 self.editCurrent.setWrapping(True)
49 self.editCycle.setSuffix(self.tr(" days"))
51 self.editCycle.valueChanged.connect(self.slotEditCycleChanged)
53 self.l0=QHBoxLayout(self)
56 l1.addRow(self.tr("Name:"), self.editName)
57 l1.addRow(self.tr("Cycle length:"), self.editCycle)
58 l1.addRow(self.tr("Current day in cycle:"), self.editCurrent)
62 spacer=QSpacerItem(20, 20, QSizePolicy.Expanding)
63 self.l0.addItem(spacer)
68 self.buttonOk=QPushButton(self)
69 self.buttonOk.setText(self.tr("OK"))
70 self.buttonOk.clicked.connect(self.slotButOk)
71 l2.addWidget(self.buttonOk)
73 spacer=QSpacerItem(20, 20, QSizePolicy.Minimum,QSizePolicy.Expanding)
76 self.setWindowTitle(self.tr("Configuration"))
79 self.name=str(self.editName.text())
80 self.cycle=self.editCycle.value()
81 self.current=self.editCurrent.value()-1
85 def slotEditCycleChanged(self, value):
86 self.editCurrent.setMaximum(value)
88 # current starts from 0
89 def initValues(self, dt):
91 self.editName.setText(dt['name'])
92 self.editCycle.setValue(dt['cycle'])
93 self.editCurrent.setValue(dt['day0']+1)
95 class MyMsgDialog(QDialog):
97 A Dialog to show a finger-scrollable message
101 class Koko(MyMsgDialog):
103 MyMsgDialog.__init__(....)
106 self.setWindowTitle("My title")
108 l1=QLabel("koko", self.w)
112 self.l is a QVBoxLayout. Add everything there.
113 self.w is a QWidget. Use it as parent.
116 def __init__(self, *args, **kwargs):
117 QDialog.__init__(self, *args, **kwargs)
119 # This freaking thing is hard
120 # It needs two layouts, one extra widget, the fingerscrollable
121 # property set to true *and* setWidgetResizable(True)
122 self._mm_l0=QVBoxLayout(self)
124 self._mm_q=QScrollArea(self)
125 self._mm_q.setWidgetResizable(True)
126 self._mm_q.setProperty('FingerScrollable', True)
128 self.w=QWidget(self._mm_q)
130 self.l=QVBoxLayout(self.w)
131 self._mm_q.setWidget(self.w)
132 self._mm_l0.addWidget(self._mm_q)
134 class AboutDialog(MyMsgDialog):
135 def __init__(self, *args, **kwargs):
136 MyMsgDialog.__init__(self, *args, **kwargs)
141 text-decoration: underline;
145 <p> A program to monitor the women's cycle. Good for planning (or acting ;-).
146 Inspired by "MyGirls" app which is (was?) available for Java ME capable phones.
148 <p style="color: orange;">
149 WARNING!!! This app is not guaranteed to be accurate or correct! You cannot
150 trust this program, or any program, to give accurate predictions!
151 The whole women-cycle-thing highly depends on a number of factors that
152 only a doctor can tell.
154 <div class="title">Copyright</div>
155 <p> Copyright © 2010, Stefanos Harhalakis <v13@v13.gr>
157 <p> Send comments and bug reports to the above address.
159 <div class="title">License</div>
160 <p> This program is free software: you can redistribute it and/or modify
161 it under the terms of the GNU General Public License as published by
162 the Free Software Foundation, either version 3 of the License, or
163 (at your option) any later version.
164 <p> This program is distributed in the hope that it will be useful,
165 but WITHOUT ANY WARRANTY; without even the implied warranty of
166 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
167 GNU General Public License for more details.
168 <p> You should have received a copy of the GNU General Public License
169 along with this program. If not, see
170 <a href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
175 self.setWindowTitle(self.tr("About MaeGirls"))
177 self.ltitle=QLabel("MaeGirls v" + config.version, self.w)
178 self.ltitle.setObjectName("title")
179 self.ltitle.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
180 self.ltitle.setAlignment(Qt.AlignCenter)
181 self.l.addWidget(self.ltitle)
183 self.label=QLabel(txt, self.w)
184 self.label.setWordWrap(True)
185 self.label.setTextFormat(Qt.RichText)
186 self.label.setAlignment(Qt.AlignJustify)
187 self.l.addWidget(self.label)
189 self.ltitle.setStyleSheet("""
192 color: rgb(192,192,192);
193 margin-bottom: 0.5ex;
197 class HelpDialog(MyMsgDialog):
198 def __init__(self, *args, **kwargs):
199 MyMsgDialog.__init__(self, *args, **kwargs)
202 <p> MaeGirls shows information about women's cycle using some generic
203 guidelines: It assumes that ovulation happens 14 days before the start
204 of the next period and that the period cycle is constant. Also, it assumes
205 that sperm can live for 4 days, while an egg can live for 2 days.
207 <p style="color: orange;">
208 WARNING!!! This is not always correct. There are FAR TOO MANY exceptions
209 to the above rules!!! You MUST consult a doctor in order to get accurate
212 <p> Assuming that you understand the risks of blindly trusting this program,
213 you become entitled to read the graph as follows:
214 <p> <span style="color: red">In red:</span> The days that menstruation
215 happens, assumed to last 5 days.
216 <p> <span style="color: green">In green:</span> The fertile days as described above.
217 <p> <span style="color: blue">In blue:</span> The days of PMS
218 (Premenstrual Syndrome), assumed to last 7 days.
220 <p> Navigation is easy: Use left-right finger movement to move the calendar
221 view. Use up-down finger movement to zoom in/out.
223 <p> This program allows for "monitoring" the cycle of multiple girls.
226 self.setWindowTitle(self.tr("Help"))
228 self.label=QLabel(txt, self.w)
229 self.label.setWordWrap(True)
230 self.label.setTextFormat(Qt.RichText)
231 self.label.setAlignment(Qt.AlignJustify)
232 self.l.addWidget(self.label)
234 class GirlsDialog(QDialog):
235 def __init__(self, *args, **kwargs):
236 QDialog.__init__(self, *args, **kwargs)
238 self.l0=QHBoxLayout(self)
240 self.lstm=QStringListModel()
241 self.lst=QListView(self)
242 self.lst.setModel(self.lstm)
244 self.lst.setProperty("FingerScrollable", True)
246 self.l0.addWidget(self.lst)
248 self.buttonNew=QPushButton(self)
249 self.buttonNew.setText(self.tr("New"))
251 self.buttonSelect=QPushButton(self)
252 self.buttonSelect.setText(self.tr("Select"))
254 self.buttonDelete=QPushButton(self)
255 self.buttonDelete.setText(self.tr("Delete"))
257 spacer=QSpacerItem(20, 20, QSizePolicy.Minimum,QSizePolicy.Expanding)
259 self.l1=QVBoxLayout()
260 self.l0.addLayout(self.l1)
261 self.l1.addWidget(self.buttonNew)
262 self.l1.addWidget(self.buttonSelect)
263 self.l1.addWidget(self.buttonDelete)
264 self.l1.addItem(spacer)
266 self.buttonNew.clicked.connect(self.slotNew)
267 self.buttonDelete.clicked.connect(self.slotDelete)
268 self.buttonSelect.clicked.connect(self.slotSelect)
270 def _get_selection(self):
271 sel=self.lst.selectedIndexes()
274 ret=str(d.data().toString())
280 def exec_(self, current):
282 girls=config.loadGirls()
285 self.lstm.setStringList(dt)
290 # Set current selection
291 idx=dt.index(current)
293 # Either I'm doing something stupid, or this is a QT bug
294 # The selection works but isn't shown
295 idx2=self.lstm.index(idx, 0)
296 self.lst.setCurrentIndex(idx2)
297 # Give if focus to show the current selection - is this normal?
298 self.lst.setFocus(Qt.OtherFocusReason)
308 def slotDelete(self):
310 self.which=self._get_selection()
313 def slotSelect(self):
315 self.which=self._get_selection()
318 class MaeGirls(QMainWindow):
319 def __init__(self, algo):
320 QMainWindow.__init__(self)
324 # self.dlgConfig=ConfigDialog(self)
325 # self.dlgAbout=AboutDialog(self)
326 # self.dlgHelp=HelpDialog(self)
334 def setupUi(self, algo):
335 self.centralwidget=QWidget(self)
336 self.setCentralWidget(self.centralwidget)
338 self.l0=QVBoxLayout(self.centralwidget)
340 self.dg=DaysGraph(algo, self.centralwidget)
341 self.l0.addWidget(self.dg)
344 self.menuconfig=QAction(self.tr('Configure'), self)
345 self.menuconfig.triggered.connect(self.menuConfig)
347 self.menureset=QAction(self.tr('Go to today'), self)
348 self.menureset.triggered.connect(self.menuReset)
350 self.menugirls=QAction(self.tr('Girls'), self)
351 self.menugirls.triggered.connect(self.menuGirls)
353 self.menuabout=QAction(self.tr('About'), self)
354 self.menuabout.triggered.connect(self.menuAbout)
356 self.menuhelp=QAction(self.tr('Help'), self)
357 self.menuhelp.triggered.connect(self.menuHelp)
360 m.addAction(self.menureset)
361 m.addAction(self.menuconfig)
362 m.addAction(self.menugirls)
363 m.addAction(self.menuhelp)
364 m.addAction(self.menuabout)
366 def updateTitle(self):
367 txt="MaeGirls - %s" % (self.girl, )
368 self.setWindowTitle(txt)
370 def setAlgo(self, algo):
371 self.dg.setAlgo(algo)
373 def setGirl(self, name):
374 cfg=config.loadGirl(name)
376 self.algo.setReference(cfg['day0'], cfg['cycle'])
380 def menuConfig(self):
381 if self.dlgConfig==None:
382 self.dlgConfig=ConfigDialog(self)
386 'cycle': self.algo.cycleLength(),
387 'day0': self.algo.currentDayInCycle()
390 self.dlgConfig.initValues(dt)
392 ret=self.dlgConfig.exec_()
394 if ret==self.dlgConfig.Accepted:
397 name=self.dlgConfig.name
398 day0=today-self.dlgConfig.current
401 'cycle': self.dlgConfig.cycle,
405 config.storeGirl(name, dt)
406 config.setCurrentGirl(name)
408 # If this is a rename, remove the old one
410 config.removeGirl(self.girl)
417 if self.dlgGirls==None:
418 self.dlgGirls=GirlsDialog(self)
420 ret=self.dlgGirls.exec_(self.girl)
422 what=self.dlgGirls.what
423 which=self.dlgGirls.which
425 # Determine a unique name
429 while config.girlExists(name):
431 name="%s%d" % (base, idx)
435 config.setCurrentGirl(name)
439 elif what=='delete' and which!=None:
441 msg=QMessageBox(self)
442 msg.setText(self.tr('You cannot delete the current girl'))
445 config.removeGirl(which)
446 elif what=='select' and which!=None:
447 config.setCurrentGirl(which)
451 if self.dlgAbout==None:
452 self.dlgAbout=AboutDialog(self)
454 ret=self.dlgAbout.exec_()
457 if self.dlgHelp==None:
458 self.dlgHelp=HelpDialog(self)
460 ret=self.dlgHelp.exec_()
470 # Create the application
471 app=QApplication(sys.argv)
473 # This returns the country and *NOT* the required locale
474 # This means that if you have'set language==en_GB and countr==Greece
475 # it will return el_GR.
476 # IOW: If you want english messages this will not work
477 #loc=QLocale.system().name()
479 loc=locale.setlocale(locale.LC_MESSAGES, '')
483 qttr.load("qt_" + loc,
484 QLibraryInfo.location(QLibraryInfo.TranslationsPath))
485 app.installTranslator(qttr)
488 maetr.load("maegirls_" + loc,
489 "/usr/share/maegirls/translations")
491 # Install the translation
492 app.installTranslator(maetr)
494 # One day support portrait mode
495 #app.setAttribute(Qt.WA_Maemo5PortraitOrientation, True);
497 # Create the main window
513 # vim: set ts=8 sts=4 sw=4 noet formatoptions=r ai nocindent: