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 *
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(self.tr(" days"))
50 self.editCycle.valueChanged.connect(self.slotEditCycleChanged)
52 self.l0=QHBoxLayout(self)
55 l1.addRow(self.tr("Name:"), self.editName)
56 l1.addRow(self.tr("Cycle length:"), self.editCycle)
57 l1.addRow(self.tr("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(self.tr("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(self.tr("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(self.tr("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 ovulation 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(self.tr("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(self.tr("New"))
227 self.buttonSelect=QPushButton(self)
228 self.buttonSelect.setText(self.tr("Select"))
230 self.buttonDelete=QPushButton(self)
231 self.buttonDelete.setText(self.tr("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)
310 def setupUi(self, algo):
311 self.centralwidget=QWidget(self)
312 self.setCentralWidget(self.centralwidget)
314 self.l0=QVBoxLayout(self.centralwidget)
316 self.dg=DaysGraph(algo, self.centralwidget)
317 self.l0.addWidget(self.dg)
320 self.menuconfig=QAction(self.tr('Configure'), self)
321 self.menuconfig.triggered.connect(self.menuConfig)
323 self.menureset=QAction(self.tr('Go to today'), self)
324 self.menureset.triggered.connect(self.menuReset)
326 self.menugirls=QAction(self.tr('Girls'), self)
327 self.menugirls.triggered.connect(self.menuGirls)
329 self.menuabout=QAction(self.tr('About'), self)
330 self.menuabout.triggered.connect(self.menuAbout)
332 self.menuhelp=QAction(self.tr('Help'), self)
333 self.menuhelp.triggered.connect(self.menuHelp)
336 m.addAction(self.menureset)
337 m.addAction(self.menuconfig)
338 m.addAction(self.menugirls)
339 m.addAction(self.menuhelp)
340 m.addAction(self.menuabout)
342 self.setWindowTitle("MaeGirls")
344 def setAlgo(self, algo):
345 self.dg.setAlgo(algo)
347 def setGirl(self, name):
348 cfg=config.loadGirl(name)
350 self.algo.setReference(cfg['day0'], cfg['cycle'])
353 def menuConfig(self):
354 if self.dlgConfig==None:
355 self.dlgConfig=ConfigDialog(self)
359 'cycle': self.algo.cycleLength(),
360 'day0': self.algo.currentDayInCycle()
363 self.dlgConfig.initValues(dt)
365 ret=self.dlgConfig.exec_()
367 if ret==self.dlgConfig.Accepted:
370 name=self.dlgConfig.name
371 day0=today-self.dlgConfig.current
374 'cycle': self.dlgConfig.cycle,
378 config.storeGirl(name, dt)
379 config.setCurrentGirl(name)
381 # If this is a rename, remove the old one
383 config.removeGirl(self.girl)
390 if self.dlgGirls==None:
391 self.dlgGirls=GirlsDialog(self)
393 ret=self.dlgGirls.exec_(self.girl)
395 what=self.dlgGirls.what
396 which=self.dlgGirls.which
398 # Determine a unique name
402 while config.girlExists(name):
404 name="%s%d" % (base, idx)
408 config.setCurrentGirl(name)
412 elif what=='delete' and which!=None:
414 msg=QMessageBox(self)
415 msg.setText(self.tr('You cannot delete the current girl'))
418 config.removeGirl(which)
419 elif what=='select' and which!=None:
420 config.setCurrentGirl(which)
424 if self.dlgAbout==None:
425 self.dlgAbout=AboutDialog(self)
427 ret=self.dlgAbout.exec_()
430 if self.dlgHelp==None:
431 self.dlgHelp=HelpDialog(self)
433 ret=self.dlgHelp.exec_()
443 # Create the application
444 app=QApplication(sys.argv)
448 qttr.load("qt_" + QLocale.system().name(),
449 QLibraryInfo.location(QLibraryInfo.TranslationsPath))
450 app.installTranslator(qttr)
453 maetr.load("maegirls_" + QLocale.system().name(),
454 "/usr/share/maegirls/translations")
456 # Install the translation
457 app.installTranslator(maetr)
459 # One day support portrait mode
460 #app.setAttribute(Qt.WA_Maemo5PortraitOrientation, True);
462 # Create the main window
478 # vim: set ts=8 sts=4 sw=4 noet formatoptions=r ai nocindent: