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 <http://www.gnu.org/licenses/>.
174 self.setWindowTitle(self.tr("About MaeGirls"))
176 self.ltitle=QLabel("MaeGirls v" + config.version, self.w)
177 self.ltitle.setObjectName("title")
178 self.ltitle.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
179 self.ltitle.setAlignment(Qt.AlignCenter)
180 self.l.addWidget(self.ltitle)
182 self.label=QLabel(txt, self.w)
183 self.label.setWordWrap(True)
184 self.label.setTextFormat(Qt.RichText)
185 self.label.setAlignment(Qt.AlignJustify)
186 self.l.addWidget(self.label)
188 self.ltitle.setStyleSheet("""
191 color: rgb(192,192,192);
192 margin-bottom: 0.5ex;
196 class HelpDialog(MyMsgDialog):
197 def __init__(self, *args, **kwargs):
198 MyMsgDialog.__init__(self, *args, **kwargs)
201 <p> MaeGirls shows information about women's cycle using some generic
202 guidelines: It assumes that the ovulation happens 14 days before the start
203 of the next period and that the period cycle is constant. Also, it assumes
204 that sperm can live for 4 days, while an egg can live for 2 days.
206 <p style="color: orange;">
207 WARNING!!! This is not always correct. There are FAR TOO MANY exceptions
208 to the above rules!!! You MUST consult a doctor in order to get accurate
211 <p> Assuming that you understand the risks of blindly trusting this program,
212 you become entitled to read the graph as follows:
213 <p> <span style="color: red">In red:</span> The days that menstruation
214 happens, assumed to last 5 days.
215 <p> <span style="color: green">In green:</span> The fertile days as described above.
216 <p> <span style="color: blue">In blue:</span> The days of PMS
217 (Premenstrual Syndrome), assumed to last 7 days.
219 <p> Navigation is easy: Use left-right finger movement to move the calendar
220 view. Use up-down finger movement to zoom in/out.
222 <p> This program allows for "monitoring" the cycle of multiple girls.
225 self.setWindowTitle(self.tr("Help"))
227 self.label=QLabel(txt, self.w)
228 self.label.setWordWrap(True)
229 self.label.setTextFormat(Qt.RichText)
230 self.label.setAlignment(Qt.AlignJustify)
231 self.l.addWidget(self.label)
233 class GirlsDialog(QDialog):
234 def __init__(self, *args, **kwargs):
235 QDialog.__init__(self, *args, **kwargs)
237 self.l0=QHBoxLayout(self)
239 self.lstm=QStringListModel()
240 self.lst=QListView(self)
241 self.lst.setModel(self.lstm)
243 self.lst.setProperty("FingerScrollable", True)
245 self.l0.addWidget(self.lst)
247 self.buttonNew=QPushButton(self)
248 self.buttonNew.setText(self.tr("New"))
250 self.buttonSelect=QPushButton(self)
251 self.buttonSelect.setText(self.tr("Select"))
253 self.buttonDelete=QPushButton(self)
254 self.buttonDelete.setText(self.tr("Delete"))
256 spacer=QSpacerItem(20, 20, QSizePolicy.Minimum,QSizePolicy.Expanding)
258 self.l1=QVBoxLayout()
259 self.l0.addLayout(self.l1)
260 self.l1.addWidget(self.buttonNew)
261 self.l1.addWidget(self.buttonSelect)
262 self.l1.addWidget(self.buttonDelete)
263 self.l1.addItem(spacer)
265 self.buttonNew.clicked.connect(self.slotNew)
266 self.buttonDelete.clicked.connect(self.slotDelete)
267 self.buttonSelect.clicked.connect(self.slotSelect)
269 def _get_selection(self):
270 sel=self.lst.selectedIndexes()
273 ret=str(d.data().toString())
279 def exec_(self, current):
281 girls=config.loadGirls()
284 self.lstm.setStringList(dt)
289 # Set current selection
290 idx=dt.index(current)
292 # Either I'm doing something stupid, or this is a QT bug
293 # The selection works but isn't shown
294 idx2=self.lstm.index(idx, 0)
295 self.lst.setCurrentIndex(idx2)
296 # Give if focus to show the current selection - is this normal?
297 self.lst.setFocus(Qt.OtherFocusReason)
307 def slotDelete(self):
309 self.which=self._get_selection()
312 def slotSelect(self):
314 self.which=self._get_selection()
317 class MaeGirls(QMainWindow):
318 def __init__(self, algo):
319 QMainWindow.__init__(self)
323 # self.dlgConfig=ConfigDialog(self)
324 # self.dlgAbout=AboutDialog(self)
325 # self.dlgHelp=HelpDialog(self)
333 def setupUi(self, algo):
334 self.centralwidget=QWidget(self)
335 self.setCentralWidget(self.centralwidget)
337 self.l0=QVBoxLayout(self.centralwidget)
339 self.dg=DaysGraph(algo, self.centralwidget)
340 self.l0.addWidget(self.dg)
343 self.menuconfig=QAction(self.tr('Configure'), self)
344 self.menuconfig.triggered.connect(self.menuConfig)
346 self.menureset=QAction(self.tr('Go to today'), self)
347 self.menureset.triggered.connect(self.menuReset)
349 self.menugirls=QAction(self.tr('Girls'), self)
350 self.menugirls.triggered.connect(self.menuGirls)
352 self.menuabout=QAction(self.tr('About'), self)
353 self.menuabout.triggered.connect(self.menuAbout)
355 self.menuhelp=QAction(self.tr('Help'), self)
356 self.menuhelp.triggered.connect(self.menuHelp)
359 m.addAction(self.menureset)
360 m.addAction(self.menuconfig)
361 m.addAction(self.menugirls)
362 m.addAction(self.menuhelp)
363 m.addAction(self.menuabout)
365 def updateTitle(self):
366 txt="MaeGirls - %s" % (self.girl, )
367 self.setWindowTitle(txt)
369 def setAlgo(self, algo):
370 self.dg.setAlgo(algo)
372 def setGirl(self, name):
373 cfg=config.loadGirl(name)
375 self.algo.setReference(cfg['day0'], cfg['cycle'])
379 def menuConfig(self):
380 if self.dlgConfig==None:
381 self.dlgConfig=ConfigDialog(self)
385 'cycle': self.algo.cycleLength(),
386 'day0': self.algo.currentDayInCycle()
389 self.dlgConfig.initValues(dt)
391 ret=self.dlgConfig.exec_()
393 if ret==self.dlgConfig.Accepted:
396 name=self.dlgConfig.name
397 day0=today-self.dlgConfig.current
400 'cycle': self.dlgConfig.cycle,
404 config.storeGirl(name, dt)
405 config.setCurrentGirl(name)
407 # If this is a rename, remove the old one
409 config.removeGirl(self.girl)
416 if self.dlgGirls==None:
417 self.dlgGirls=GirlsDialog(self)
419 ret=self.dlgGirls.exec_(self.girl)
421 what=self.dlgGirls.what
422 which=self.dlgGirls.which
424 # Determine a unique name
428 while config.girlExists(name):
430 name="%s%d" % (base, idx)
434 config.setCurrentGirl(name)
438 elif what=='delete' and which!=None:
440 msg=QMessageBox(self)
441 msg.setText(self.tr('You cannot delete the current girl'))
444 config.removeGirl(which)
445 elif what=='select' and which!=None:
446 config.setCurrentGirl(which)
450 if self.dlgAbout==None:
451 self.dlgAbout=AboutDialog(self)
453 ret=self.dlgAbout.exec_()
456 if self.dlgHelp==None:
457 self.dlgHelp=HelpDialog(self)
459 ret=self.dlgHelp.exec_()
469 # Create the application
470 app=QApplication(sys.argv)
472 # This returns the country and *NOT* the required locale
473 # This means that if you have'set language==en_GB and countr==Greece
474 # it will return el_GR.
475 # IOW: If you want english messages this will not work
476 #loc=QLocale.system().name()
478 loc=locale.setlocale(locale.LC_MESSAGES, '')
482 qttr.load("qt_" + loc,
483 QLibraryInfo.location(QLibraryInfo.TranslationsPath))
484 app.installTranslator(qttr)
487 maetr.load("maegirls_" + loc,
488 "/usr/share/maegirls/translations")
490 # Install the translation
491 app.installTranslator(maetr)
493 # One day support portrait mode
494 #app.setAttribute(Qt.WA_Maemo5PortraitOrientation, True);
496 # Create the main window
512 # vim: set ts=8 sts=4 sw=4 noet formatoptions=r ai nocindent: