Use a larger size hint for main widget.
authorv13 <v13>
Fri, 13 Aug 2010 09:49:22 +0000 (09:49 +0000)
committerv13 <v13>
Fri, 13 Aug 2010 09:49:22 +0000 (09:49 +0000)
Allow for configurable menstruation duration and ovulation day.
Provide configuration options for those parameters.
Improve help to describe those options.

trunk/setup.py
trunk/src/algo.py
trunk/src/config.py
trunk/src/graph.py
trunk/src/win.py

index a42ceb1..b42984c 100755 (executable)
@@ -26,7 +26,7 @@ i18n_qm_files=["i18n/maegirls_el.qm"]
 
 setup(
     name='maegirls',
-    version='1.2',
+    version='1.3',
     description="MaeGirls",
     author="Stefanos Harhalakis",
     author_email="v13@v13.gr",
index 06209bd..3078483 100755 (executable)
@@ -24,33 +24,56 @@ __version__ = "$Id: 0.py 2265 2010-02-21 19:16:26Z v13 $"
 
 import time
 
+def today():
+    t=time.time() - time.timezone
+    day=int(t/86400)
+
+    return(day)
+
+# Defaults for a girl
+defaults={
+    'cycle':       28,         # Cycle length
+    'menstr':      5,          # Duration of menstruation
+    'ovday':       -14,        # When ovulation happens. Positive: This number
+                               # of days after the start of the cycle.
+                               # Negative: This number of days before the end
+                               # of the cycle.
+    'day0':        today()
+    }
+
 class Algo(object):
     def __init__(self):
        t=today()
-       self.setReference(t, 28)
+       self.setReference(t, defaults)
 
     # set day "day" as the reference day of starting period cycle
     # day is int(time.time()/86400)
     # cycle is the cycle width in days, starting from 0
-    def setReference(self, day, cycle):
+    def setReference(self, day, cfg):
+       self.cfg=cfg
        self.refday=day
-       self.cycle=cycle
 
     # Convert an arbitary day to a day in cycle
     def dayInCycle(self, day):
-       d=(day-self.refday) % self.cycle
+       d=(day-self.refday) % self.cfg['cycle']
        if d<0:
-           d+=self.cycle
+           d+=self.cycleLength()
 
        return(d)
 
     def cycleLength(self):
-       return(self.cycle)
+       return(self.cfg['cycle'])
 
     def currentDayInCycle(self):
        d=today()
        return(self.dayInCycle(d))
 
+    def menstruationDuration(self):
+       return(self.cfg['menstr'])
+
+    def ovulationDay(self):
+       return(self.cfg['ovday'])
+
     # Return:
     # ret={
     #  'status':   ['ok', 'red']
@@ -63,28 +86,41 @@ class Algo(object):
     def status(self, day):
        d=self.dayInCycle(day)
 
-       ovbefore=14
+       cycle=self.cycleLength()
 
-       if d<5:
+       #ovbefore=14
+       ovday=self.ovulationDay()
+       if ovday>0:
+           ovstart=ovday-3
+           ovmid=ovday
+           ovend=ovday+1
+       else:
+           ovstart=cycle+ovday-3
+           ovmid=cycle+ovday
+           ovend=cycle+ovday+1
+
+       menstr=self.menstruationDuration()
+
+       if d<menstr:
            # Red
            ret={
                'status':   'red',
                'day':      d,
-               'len':      5,
+               'len':      menstr,
                }
-       elif d>=self.cycle-7:
+       elif d>=cycle-7:
            ret={
                'status':   'blue',
-               'day':      7+d-self.cycle,
+               'day':      7+d-cycle,
                'len':      7,
                }
-       elif d>self.cycle-ovbefore-4 and d<=self.cycle-ovbefore:
+       elif d>=ovstart and d<=ovmid:
            ret={
                'status':   'green',
-               'day':      d-self.cycle+ovbefore+3,
+               'day':      d-ovstart,
                'len':      4,
                }
-       elif d>self.cycle-16 and d<=self.cycle-ovbefore+1:
+       elif d>ovmid and d<=ovend:
            ret={
                'status':   'green',
                'day':      2,
@@ -94,17 +130,11 @@ class Algo(object):
            ret={
                'status':   'ok',
                'day':      d,
-               'len':      self.cycle
+               'len':      cycle
                }
 
        return(ret)
 
-def today():
-    t=time.time() - time.timezone
-    day=int(t/86400)
-
-    return(day)
-
 
 # vim: set ts=8 sts=4 sw=4 noet formatoptions=r ai nocindent:
 
index ca82155..725f44e 100755 (executable)
@@ -28,7 +28,7 @@ import pickle
 import time
 import algo
 
-version="1.2"
+version="1.3"
 
 try:
     home=os.environ['HOME']
@@ -37,27 +37,34 @@ except:
 
 fn="%s/.maegirls" % (home, )
 
-# Defaults for a girl
-defaults={
-    'cycle':   28,
-    'day0':    algo.today(),
-    }
-
 # Default config
 defaultcfg={
-    'ver':     1,              # Configuration version
+    'ver':     2,              # Configuration version
     'girls':   {               # List of configured girls
-       'default':  defaults
+       'default':  algo.defaults
        },
     'cur':     "default",      # Current girl
     }
 
+def upgradeConfig(cfg):
+    """ Upgrade the loaded config to the latest version """
+
+    if cfg['ver']==1:
+       cfg['ver']=2
+       for i in cfg['girls']:
+           girl=cfg['girls'][i]
+           girl['menstr']=algo.defaults['menstr']
+           girl['ovday']=algo.defaults['ovday']
+
+    return(cfg)
+
 def loadConfig():
     try:
        f=file(fn, "r")
        st=f.read()
        f.close()
        ret=pickle.loads(st)
+       ret=upgradeConfig(ret)
     except:
        ret={}
 
@@ -66,6 +73,7 @@ def loadConfig():
     return(ret)
 
 def sanitize_before_store(cfg0):
+    """ Ensure that Qt strings (keys) are converted to standard strings """
     cfg={
        'ver':      cfg0['ver'],
        'cur':      str(cfg0['cur']),
@@ -79,7 +87,7 @@ def sanitize_before_store(cfg0):
     return(cfg)
 
 def storeConfig(cfg0):
-    cfg0['ver']=1
+    cfg0['ver']=2
     cfg=sanitize_before_store(cfg0)
 #    print "store:", cfg
     st=pickle.dumps(cfg)
@@ -99,14 +107,14 @@ def storeGirl(name, dt):
     cfg['girls'][name]={
        'cycle':    dt['cycle'],
        'day0':     dt['day0'],
+       'ovday':    dt['ovday'],
+       'menstr':   dt['menstr'],
        }
 
     storeConfig(cfg)
 
 def newGirl(name):
-    global defaults
-
-    storeGirl(name, defaults)
+    storeGirl(name, algo.defaults)
 
 def loadGirls():
     cfg=loadConfig()
@@ -122,7 +130,7 @@ def loadGirl(name):
     if all.has_key(name):
        ret=all[name]
     else:
-       ret=defaults
+       ret=algo.defaults
 
     return(ret)
 
index b476513..23d55c1 100755 (executable)
@@ -278,7 +278,7 @@ class DaysGraph(QWidget):
        self.last_y=pos.y()
 
     def sizeHint(self):
-       return(QSize(100,50))
+       return(QSize(400,200))
 
 # vim: set ts=8 sts=4 sw=4 noet formatoptions=r ai nocindent:
 
index dd1521c..2837fd6 100755 (executable)
@@ -43,10 +43,18 @@ class ConfigDialog(QDialog):
        self.editName=QLineEdit(self)
        self.editCycle=QSpinBox(self)
        self.editCurrent=QSpinBox(self)
+       self.editMenstr=QSpinBox(self)
+       self.editOvday=QSpinBox(self)
+
        self.editCycle.setRange(10,50)
        self.editCurrent.setRange(1,50)
+       self.editMenstr.setRange(3,7)
+       self.editOvday.setRange(-30,+30)
+
        self.editCurrent.setWrapping(True)
        self.editCycle.setSuffix(self.tr(" days"))
+       self.editMenstr.setSuffix(self.tr(' days'))
+       self.editOvday.setSuffix(self.tr(' days'))
 
        self.editCycle.valueChanged.connect(self.slotEditCycleChanged)
 
@@ -56,6 +64,8 @@ class ConfigDialog(QDialog):
        l1.addRow(self.tr("Name:"), self.editName)
        l1.addRow(self.tr("Cycle length:"), self.editCycle)
        l1.addRow(self.tr("Current day in cycle:"), self.editCurrent)
+       l1.addRow(self.tr("Duration of menstruation:"), self.editMenstr)
+       l1.addRow(self.tr("Ovulation day:"), self.editOvday)
 
        self.l0.addLayout(l1)
 
@@ -79,6 +89,8 @@ class ConfigDialog(QDialog):
        self.name=str(self.editName.text())
        self.cycle=self.editCycle.value()
        self.current=self.editCurrent.value()-1
+       self.menstr=self.editMenstr.value()
+       self.ovday=self.editOvday.value()
 
        self.accept()
 
@@ -91,6 +103,8 @@ class ConfigDialog(QDialog):
        self.editName.setText(dt['name'])
        self.editCycle.setValue(dt['cycle'])
        self.editCurrent.setValue(dt['day0']+1)
+       self.editMenstr.setValue(dt['menstr'])
+       self.editOvday.setValue(dt['ovday'])
 
 class MyMsgDialog(QDialog):
     """
@@ -200,27 +214,37 @@ class HelpDialog(MyMsgDialog):
 
        txt=self.tr("""
 <p> MaeGirls shows information about women's cycle using some generic
-guidelines:  It assumes that ovulation happens 14 days before the start
-of the next period and that the period cycle is constant. Also, it assumes
-that sperm can live for 4 days, while an egg can live for 2 days.
+guidelines:  By default it assumes that ovulation happens 14 days before the
+start of the next period and that the period cycle is constant. Also, it
+assumes that sperm can live for 4 days, while an egg can live for 2 days.
+
+<p> Using the configure menu you can change the duration of the cycle,
+the duration of the menstruation and the day the ovulation happens. When
+specifying the ovulation you can use negative numbers to indicate the number
+of days before the end of the period, or positive numbers to indicate the
+number of days after the beginning of the period. Default value for ovulation
+is -14.
+
+<p> MaeGirls supports tracking of multiple women. While there have been a lot
+of negative comments for this option, I find it useful even for women.
+Please don't complain or give negative feedback for an option that you're not
+forced to use.
 
 <p style="color: orange;">
-WARNING!!! This is not always correct. There are FAR TOO MANY exceptions
-to the above rules!!! You MUST consult a doctor in order to get accurate
-predictions!!!
+WARNING!!! The prediction is not always correct. There are FAR TOO MANY
+exceptions to the above rules!!! You MUST consult a doctor in order to get
+accurate predictions!!! Use the program at your own risk!!!
 
 <p> Assuming that you understand the risks of blindly trusting this program,
 you become entitled to read the graph as follows:
 <p> <span style="color: red">In red:</span> The days that menstruation
-happens, assumed to last 5 days.
+happens. Default: 5 days.
 <p> <span style="color: green">In green:</span> The fertile days as described above.
 <p> <span style="color: blue">In blue:</span> The days of PMS
 (Premenstrual Syndrome), assumed to last 7 days.
 
 <p> Navigation is easy: Use left-right finger movement to move the calendar
 view. Use up-down finger movement to zoom in/out.
-
-<p> This program supports the "monitoring" of the cycle of multiple girls/women.
        """)
 
        self.setWindowTitle(self.tr("Help"))
@@ -378,7 +402,8 @@ class MaeGirls(QMainWindow):
     def setGirl(self, name):
        cfg=config.loadGirl(name)
        self.girl=name
-       self.algo.setReference(cfg['day0'], cfg['cycle'])
+       #self.algo.setReference(cfg['day0'], cfg['cycle'])
+       self.algo.setReference(cfg['day0'], cfg)
        self.update()
        self.updateTitle()
 
@@ -389,7 +414,9 @@ class MaeGirls(QMainWindow):
        dt={
            'name':     self.girl,
            'cycle':    self.algo.cycleLength(),
-           'day0':     self.algo.currentDayInCycle()
+           'day0':     self.algo.currentDayInCycle(),
+           'menstr':   self.algo.menstruationDuration(),
+           'ovday':    self.algo.ovulationDay()
            }
 
        self.dlgConfig.initValues(dt)
@@ -405,6 +432,8 @@ class MaeGirls(QMainWindow):
            dt={
                'cycle':        self.dlgConfig.cycle,
                'day0':         day0,
+               'ovday':        self.dlgConfig.ovday,
+               'menstr':       self.dlgConfig.menstr,
                }
 
            config.storeGirl(name, dt)