4 # Copyright (C) 2010 Stefanos Harhalakis
6 # This file is part of mydays.
8 # mydays 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 # mydays 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 mydays. 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 *
31 from graph import DaysGraph
38 class ConfigDialog(QDialog):
39 def __init__(self, *args, **kwargs):
40 QDialog.__init__(self, *args, **kwargs)
42 self.editName=QLineEdit(self)
43 self.editCycle=QSpinBox(self)
44 self.editCurrent=QSpinBox(self)
45 self.editCycle.setRange(10,50)
46 self.editCurrent.setRange(1,50)
47 self.editCurrent.setWrapping(True)
48 self.editCycle.setSuffix(" days")
50 self.editCycle.valueChanged.connect(self.slotEditCycleChanged)
52 self.l0=QHBoxLayout(self)
55 l1.addRow("Name:", self.editName)
56 l1.addRow("Cycle length:", self.editCycle)
57 l1.addRow("Current day in cycle:", self.editCurrent)
61 spacer=QSpacerItem(20, 20, QSizePolicy.Expanding)
62 self.l0.addItem(spacer)
67 self.buttonOk=QPushButton(self)
68 self.buttonOk.setText("OK")
69 self.buttonOk.clicked.connect(self.slotButOk)
70 l2.addWidget(self.buttonOk)
72 spacer=QSpacerItem(20, 20, QSizePolicy.Minimum,QSizePolicy.Expanding)
75 self.setWindowTitle("Configuration")
78 self.name=str(self.editName.text())
79 self.cycle=self.editCycle.value()
80 self.current=self.editCurrent.value()-1
84 def slotEditCycleChanged(self, value):
85 self.editCurrent.setMaximum(value)
87 # current starts from 0
88 def initValues(self, dt):
90 self.editName.setText(dt['name'])
91 self.editCycle.setValue(dt['cycle'])
92 self.editCurrent.setValue(dt['day0']+1)
94 class MyMsgDialog(QDialog):
96 A Dialog to show a finger-scrollable message
100 class Koko(MyMsgDialog):
102 MyMsgDialog.__init__(....)
105 self.setWindowTitle("My title")
107 l1=QLabel("koko", self.w)
111 self.l is a QVBoxLayout. Add everything there.
112 self.w is a QWidget. Use it as parent.
115 def __init__(self, *args, **kwargs):
116 QDialog.__init__(self, *args, **kwargs)
118 # This freaking thing is hard
119 # It needs two layouts, one extra widget, the fingerscrollable
120 # property set to true *and* setWidgetResizable(True)
121 self._mm_l0=QVBoxLayout(self)
123 self._mm_q=QScrollArea(self)
124 self._mm_q.setWidgetResizable(True)
125 self._mm_q.setProperty('FingerScrollable', True)
127 self.w=QWidget(self._mm_q)
129 self.l=QVBoxLayout(self.w)
130 self._mm_q.setWidget(self.w)
131 self._mm_l0.addWidget(self._mm_q)
133 class AboutDialog(MyMsgDialog):
134 def __init__(self, *args, **kwargs):
135 MyMsgDialog.__init__(self, *args, **kwargs)
138 <p> A program to monitor the women's cycle. Good for planning (or acting ;-).
139 Inspired by "MyGirls" app which is (was?) available for Java ME capable phones.
141 <p style="color: orange;">
142 WARNING!!! This is not accurate nor correct! You cannot trust
143 this program (or any other program) for accurate predictions!
144 (after all, this is about women... how can one be sure :-).
146 <p> Copyright © 2010, Stefanos Harhalakis <v13@v13.gr>
148 <p> Send comments and bug reports to the above address.
150 <p> This program can be distributed under the terms of the GNU public
151 license, version 3 or any later.
154 self.setWindowTitle("About MaeGirls")
156 self.ltitle=QLabel("MaeGirls", self.w)
157 self.ltitle.setObjectName("title")
158 self.ltitle.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
159 self.ltitle.setAlignment(Qt.AlignCenter)
160 self.l.addWidget(self.ltitle)
162 self.label=QLabel(txt, self.w)
163 self.label.setWordWrap(True)
164 self.label.setTextFormat(Qt.RichText)
165 self.label.setAlignment(Qt.AlignJustify)
166 self.l.addWidget(self.label)
168 self.ltitle.setStyleSheet("""
171 color: rgb(192,192,192);
172 margin-bottom: 0.5ex;
176 class HelpDialog(MyMsgDialog):
177 def __init__(self, *args, **kwargs):
178 MyMsgDialog.__init__(self, *args, **kwargs)
181 <p> MaeGirls shows information about women's cycle using some generic
182 guidelines. It assumes that the ovolution happens 14 days before the start
183 of the next period and that the period cycle is constant. Also, it assumes
184 that sperm can live for 4 days, while an egg can live for 2 days.
186 <p style="color: orange;">
187 WARNING!!! This is not always correct. There are FAR TOO MANY exceptions
188 to the above rules!!!
190 <p> Assuming that you understand the risk of being wrong, you become
191 entitled to read the graph as follows:
192 <p> <span style="color: red">In red:</span> The days that menstruation
194 <p> <span style="color: green">In green:</span> The fertile days.
195 <p> <span style="color: blue">In blue:</span> The days of PMS
196 (Premenstrual Syndrome).
198 <p> Navigation is easy: Use left-right finger movement to move the calendar
199 view. Use up-down finger movement to zoom in/out.
202 self.setWindowTitle("Help")
204 self.label=QLabel(txt, self.w)
205 self.label.setWordWrap(True)
206 self.label.setTextFormat(Qt.RichText)
207 self.label.setAlignment(Qt.AlignJustify)
208 self.l.addWidget(self.label)
210 class GirlsDialog(QDialog):
211 def __init__(self, *args, **kwargs):
212 QDialog.__init__(self, *args, **kwargs)
214 self.l0=QHBoxLayout(self)
216 self.lstm=QStringListModel()
217 self.lst=QListView(self)
218 self.lst.setModel(self.lstm)
220 self.lst.setProperty("FingerScrollable", True)
222 self.l0.addWidget(self.lst)
224 self.buttonNew=QPushButton(self)
225 self.buttonNew.setText("New")
227 self.buttonSelect=QPushButton(self)
228 self.buttonSelect.setText("Select")
230 self.buttonDelete=QPushButton(self)
231 self.buttonDelete.setText("Delete")
233 spacer=QSpacerItem(20, 20, QSizePolicy.Minimum,QSizePolicy.Expanding)
235 self.l1=QVBoxLayout()
236 self.l0.addLayout(self.l1)
237 self.l1.addWidget(self.buttonNew)
238 self.l1.addWidget(self.buttonSelect)
239 self.l1.addWidget(self.buttonDelete)
240 self.l1.addItem(spacer)
242 self.buttonNew.clicked.connect(self.slotNew)
243 self.buttonDelete.clicked.connect(self.slotDelete)
244 self.buttonSelect.clicked.connect(self.slotSelect)
246 def _get_selection(self):
247 sel=self.lst.selectedIndexes()
250 ret=str(d.data().toString())
256 def exec_(self, current):
258 girls=config.loadGirls()
261 self.lstm.setStringList(dt)
266 # Set current selection
267 idx=dt.index(current)
269 # Either I'm doing something stupid, or this is a QT bug
270 # The selection works but isn't shown
271 idx2=self.lstm.index(idx, 0)
272 self.lst.setCurrentIndex(idx2)
282 def slotDelete(self):
284 self.which=self._get_selection()
287 def slotSelect(self):
289 self.which=self._get_selection()
292 class MaeGirls(QMainWindow):
293 def __init__(self, algo):
294 QMainWindow.__init__(self)
298 self.dlgConfig=ConfigDialog(self)
299 self.dlgAbout=AboutDialog(self)
300 self.dlgHelp=HelpDialog(self)
305 def setupUi(self, algo):
306 self.centralwidget=QWidget(self)
307 self.setCentralWidget(self.centralwidget)
309 self.l0=QVBoxLayout(self.centralwidget)
311 self.dg=DaysGraph(algo, self.centralwidget)
312 self.l0.addWidget(self.dg)
315 self.menuconfig=QAction('Configure', self)
316 self.menuconfig.triggered.connect(self.menuConfig)
318 self.menureset=QAction('Go to today', self)
319 self.menureset.triggered.connect(self.menuReset)
321 self.menugirls=QAction('Girls', self)
322 self.menugirls.triggered.connect(self.menuGirls)
324 self.menuabout=QAction('About', self)
325 self.menuabout.triggered.connect(self.menuAbout)
327 self.menuhelp=QAction('Help', self)
328 self.menuhelp.triggered.connect(self.menuHelp)
331 m.addAction(self.menuconfig)
332 m.addAction(self.menureset)
333 m.addAction(self.menugirls)
334 m.addAction(self.menuhelp)
335 m.addAction(self.menuabout)
337 self.setWindowTitle("MaeGirls")
339 def setAlgo(self, algo):
340 self.dg.setAlgo(algo)
342 def setGirl(self, name):
343 cfg=config.loadGirl(name)
345 self.algo.setReference(cfg['day0'], cfg['cycle'])
348 def menuConfig(self):
349 if self.dlgConfig==None:
350 self.dlgConfig=ConfigDialog(self)
354 'cycle': self.algo.cycleLength(),
355 'day0': self.algo.currentDayInCycle()
358 self.dlgConfig.initValues(dt)
360 ret=self.dlgConfig.exec_()
362 if ret==self.dlgConfig.Accepted:
365 name=self.dlgConfig.name
366 day0=today-self.dlgConfig.current
369 'cycle': self.dlgConfig.cycle,
373 config.storeGirl(name, dt)
374 config.setCurrentGirl(name)
376 # If this is a rename, remove the old one
378 config.removeGirl(self.girl)
385 if self.dlgGirls==None:
386 self.dlgGirls=GirlsDialog(self)
388 ret=self.dlgGirls.exec_(self.girl)
390 what=self.dlgGirls.what
391 which=self.dlgGirls.which
393 # Determine a unique name
397 while config.girlExists(name):
399 name="%s%d" % (base, idx)
403 config.setCurrentGirl(name)
407 elif what=='delete' and which!=None:
409 msg=QMessageBox(self)
410 msg.setText("You cannot delete the current girl")
413 config.removeGirl(which)
414 elif what=='select' and which!=None:
415 config.setCurrentGirl(which)
419 if self.dlgAbout==None:
420 self.dlgAbout=AboutDialog(self)
422 ret=self.dlgAbout.exec_()
425 if self.dlgHelp==None:
426 self.dlgHelp=HelpDialog(self)
428 ret=self.dlgHelp.exec_()
437 app=QApplication(sys.argv)
438 #app.setAttribute(Qt.WA_Maemo5PortraitOrientation, True);
454 # vim: set ts=8 sts=4 sw=4 noet formatoptions=r ai nocindent: