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 the 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: