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)
273 # Give if focus to show the current selection - is this normal?
274 self.lst.setFocus(Qt.OtherFocusReason)
284 def slotDelete(self):
286 self.which=self._get_selection()
289 def slotSelect(self):
291 self.which=self._get_selection()
294 class MaeGirls(QMainWindow):
295 def __init__(self, algo):
296 QMainWindow.__init__(self)
300 self.dlgConfig=ConfigDialog(self)
301 self.dlgAbout=AboutDialog(self)
302 self.dlgHelp=HelpDialog(self)
307 def setupUi(self, algo):
308 self.centralwidget=QWidget(self)
309 self.setCentralWidget(self.centralwidget)
311 self.l0=QVBoxLayout(self.centralwidget)
313 self.dg=DaysGraph(algo, self.centralwidget)
314 self.l0.addWidget(self.dg)
317 self.menuconfig=QAction('Configure', self)
318 self.menuconfig.triggered.connect(self.menuConfig)
320 self.menureset=QAction('Go to today', self)
321 self.menureset.triggered.connect(self.menuReset)
323 self.menugirls=QAction('Girls', self)
324 self.menugirls.triggered.connect(self.menuGirls)
326 self.menuabout=QAction('About', self)
327 self.menuabout.triggered.connect(self.menuAbout)
329 self.menuhelp=QAction('Help', self)
330 self.menuhelp.triggered.connect(self.menuHelp)
333 m.addAction(self.menuconfig)
334 m.addAction(self.menureset)
335 m.addAction(self.menugirls)
336 m.addAction(self.menuhelp)
337 m.addAction(self.menuabout)
339 self.setWindowTitle("MaeGirls")
341 def setAlgo(self, algo):
342 self.dg.setAlgo(algo)
344 def setGirl(self, name):
345 cfg=config.loadGirl(name)
347 self.algo.setReference(cfg['day0'], cfg['cycle'])
350 def menuConfig(self):
351 if self.dlgConfig==None:
352 self.dlgConfig=ConfigDialog(self)
356 'cycle': self.algo.cycleLength(),
357 'day0': self.algo.currentDayInCycle()
360 self.dlgConfig.initValues(dt)
362 ret=self.dlgConfig.exec_()
364 if ret==self.dlgConfig.Accepted:
367 name=self.dlgConfig.name
368 day0=today-self.dlgConfig.current
371 'cycle': self.dlgConfig.cycle,
375 config.storeGirl(name, dt)
376 config.setCurrentGirl(name)
378 # If this is a rename, remove the old one
380 config.removeGirl(self.girl)
387 if self.dlgGirls==None:
388 self.dlgGirls=GirlsDialog(self)
390 ret=self.dlgGirls.exec_(self.girl)
392 what=self.dlgGirls.what
393 which=self.dlgGirls.which
395 # Determine a unique name
399 while config.girlExists(name):
401 name="%s%d" % (base, idx)
405 config.setCurrentGirl(name)
409 elif what=='delete' and which!=None:
411 msg=QMessageBox(self)
412 msg.setText("You cannot delete the current girl")
415 config.removeGirl(which)
416 elif what=='select' and which!=None:
417 config.setCurrentGirl(which)
421 if self.dlgAbout==None:
422 self.dlgAbout=AboutDialog(self)
424 ret=self.dlgAbout.exec_()
427 if self.dlgHelp==None:
428 self.dlgHelp=HelpDialog(self)
430 ret=self.dlgHelp.exec_()
439 app=QApplication(sys.argv)
440 #app.setAttribute(Qt.WA_Maemo5PortraitOrientation, True);
456 # vim: set ts=8 sts=4 sw=4 noet formatoptions=r ai nocindent: