Added multi-girl support
authorv13 <v13>
Fri, 26 Feb 2010 15:04:39 +0000 (15:04 +0000)
committerv13 <v13>
Fri, 26 Feb 2010 15:04:39 +0000 (15:04 +0000)
trunk/src/config.py
trunk/src/main.py
trunk/src/win.py

index 30a3f50..64cb787 100755 (executable)
 
 __version__ = "$Id: 0.py 2265 2010-02-21 19:16:26Z v13 $"
 
+import os
+
 import pickle
 import time
 import algo
 
-fn="/home/user/.maedays"
+try:
+    home=os.environ['HOME']
+except:
+    home="/home/user"
+
+fn="%s/.maegirls" % (home, )
 
+# Defaults for a girl
 defaults={
     'cycle':   28,
     'day0':    algo.today(),
     }
 
-def store(name, cycle, day0):
-    # Load old
-    all=loadAll()
-    # Override
-    all[name]={
-       'cycle':    cycle,
-       'day0':     day0,
+# Default config
+defaultcfg={
+    'ver':     1,              # Configuration version
+    'girls':   {               # List of configured girls
+       'default':  defaults
+       },
+    'cur':     "default",      # Current girl
+    }
+
+def loadConfig():
+    try:
+       f=file(fn, "r")
+       st=f.read()
+       f.close()
+       ret=pickle.loads(st)
+    except:
+       ret={}
+
+#    print "load:", ret
+
+    return(ret)
+
+def sanitize_before_store(cfg0):
+    cfg={
+       'ver':      cfg0['ver'],
+       'cur':      str(cfg0['cur']),
+       'girls':    {}
        }
 
-    st=pickle.dumps(all)
+    if cfg0.has_key('girls'):
+       for i in cfg0['girls']:
+           cfg['girls'][str(i)]=cfg0['girls'][i]
+
+    return(cfg)
+
+def storeConfig(cfg0):
+    cfg0['ver']=1
+    cfg=sanitize_before_store(cfg0)
+#    print "store:", cfg
+    st=pickle.dumps(cfg)
     f=file(fn, "w")
     f.write(st)
     f.close()
 
-def loadOne(name):
-    all=loadAll()
+def storeGirl(name, dt):
+    # Load old
+    cfg=loadConfig()
+
+    # Ensure
+    if not cfg.has_key('girls'):
+       cfg['girls']={}
+
+    # Override
+    cfg['girls'][name]={
+       'cycle':    dt['cycle'],
+       'day0':     dt['day0'],
+       }
+
+    storeConfig(cfg)
+
+def newGirl(name):
+    global defaults
+
+    storeGirl(name, defaults)
+
+def loadGirls():
+    cfg=loadConfig()
+    try:
+       ret=cfg['girls']
+    except:
+       ret={}
+
+    return(ret)
+
+def loadGirl(name):
+    all=loadGirls()
     if all.has_key(name):
        ret=all[name]
     else:
@@ -56,16 +124,33 @@ def loadOne(name):
 
     return(ret)
 
-def loadAll():
+def girlExists(name):
+    all=loadGirls()
+    if all.has_key(name):
+       ret=True
+    else:
+       ret=False
+    return(ret)
+
+def setCurrentGirl(name):
+    cfg=loadConfig()
+    cfg['cur']=name
+    storeConfig(cfg)
+
+def getCurrentGirl():
+    cfg=loadConfig()
     try:
-       f=file(fn, "r")
-       st=f.read()
-       f.close()
-       ret=pickle.loads(st)
+       ret=cfg['cur']
     except:
-       ret={}
+       ret='default'
 
     return(ret)
 
+def removeGirl(name):
+    cfg=loadConfig()
+    if cfg['girls'].has_key(name):
+       cfg['girls'].pop(name)
+       storeConfig(cfg)
+
 # vim: set ts=8 sts=4 sw=4 noet formatoptions=r ai nocindent:
 
index 9e0b50f..f4bdcf5 100755 (executable)
@@ -32,8 +32,11 @@ def init():
     al=algo.Algo()
     win.init(al)
 
-    dt=config.loadOne("default")
-    al.setReference(dt['day0'], dt['cycle'])
+    girl=config.getCurrentGirl()
+    win.setGirl(girl)
+
+#    dt=config.loadCurrentGirl()
+#    al.setReference(dt['day0'], dt['cycle'])
 
 init()
 
index 17dbca0..0f50111 100755 (executable)
@@ -39,6 +39,7 @@ class ConfigDialog(QDialog):
     def __init__(self, *args, **kwargs):
        QDialog.__init__(self, *args, **kwargs)
 
+       self.editName=QLineEdit(self)
        self.editCycle=QSpinBox(self)
        self.editCurrent=QSpinBox(self)
        self.editCycle.setRange(10,50)
@@ -51,6 +52,7 @@ class ConfigDialog(QDialog):
        self.l0=QHBoxLayout(self)
 
        l1=QFormLayout()
+       l1.addRow("Name:", self.editName)
        l1.addRow("Cycle length:", self.editCycle)
        l1.addRow("Current day in cycle:", self.editCurrent)
 
@@ -73,6 +75,7 @@ class ConfigDialog(QDialog):
        self.setWindowTitle("Configuration")
 
     def slotButOk(self):
+       self.name=str(self.editName.text())
        self.cycle=self.editCycle.value()
        self.current=self.editCurrent.value()-1
 
@@ -82,11 +85,11 @@ class ConfigDialog(QDialog):
        self.editCurrent.setMaximum(value)
 
     # current starts from 0
-    def initValues(self, cycle, current):
-       self.cycle=cycle
-       self.current=current
-       self.editCycle.setValue(cycle)
-       self.editCurrent.setValue(current+1)
+    def initValues(self, dt):
+       self.dt=dt
+       self.editName.setText(dt['name'])
+       self.editCycle.setValue(dt['cycle'])
+       self.editCurrent.setValue(dt['day0']+1)
 
 class MyMsgDialog(QDialog):
     """
@@ -127,70 +130,13 @@ class MyMsgDialog(QDialog):
        self._mm_q.setWidget(self.w)
        self._mm_l0.addWidget(self._mm_q)
 
-class AboutDialog2(QDialog):
-    def __init__(self, *args, **kwargs):
-       QDialog.__init__(self, *args, **kwargs)
-
-       txt="""
-<p> A program to monitor the women's cycle.  Good for planning (or acting ;-).
-Inspired by "MyDays" app which is (was?) available for Java ME capable phones.
-
-<p> WARNING!!! This is not accurate nor correct! You cannot trust
-this program (or any other program) for accurate predictions!
-(after all, this is about women... how can one be sure :-).
-
-<p> Copyright &copy; 2010, Stefanos Harhalakis &lt;v13@v13.gr&gt;
-
-<p> Send comments and bug reports to the above address.
-
-<p> This program can be distributed under the terms of the GNU public
-license, version 3 or any later.
-       """
-
-       self.setWindowTitle("About MaeDays")
-
-       # This freaking thing is hard
-       # It needs two layouts, one extra widget, the fingerscrollable
-       # property set to true *and* setWidgetResizable(True)
-       self.l0=QVBoxLayout(self)
-
-       self.q=QScrollArea(self)
-       self.q.setWidgetResizable(True)
-       self.q.setProperty('FingerScrollable', True)
-       self.w1=QWidget(self.q)
-
-       self.l=QVBoxLayout(self.w1)
-
-       self.ltitle=QLabel("MaeDays", self.w1)
-       self.ltitle.setObjectName("title")
-       self.ltitle.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
-       self.ltitle.setAlignment(Qt.AlignCenter)
-       self.l.addWidget(self.ltitle)
-
-       self.label=QLabel(txt, self.w1)
-       self.label.setWordWrap(True)
-       self.label.setTextFormat(Qt.RichText)
-       self.label.setAlignment(Qt.AlignJustify)
-
-       self.l.addWidget(self.label)
-       self.q.setWidget(self.w1)
-       self.l0.addWidget(self.q)
-
-       self.ltitle.setStyleSheet("""
-       QLabel {
-           font-size:      25pt;
-           color:          rgb(192,192,192);
-           margin-bottom:  0.5ex;
-           }
-       """)
-
 class AboutDialog(MyMsgDialog):
     def __init__(self, *args, **kwargs):
        MyMsgDialog.__init__(self, *args, **kwargs)
 
        txt="""
 <p> A program to monitor the women's cycle.  Good for planning (or acting ;-).
-Inspired by "MyDays" app which is (was?) available for Java ME capable phones.
+Inspired by "MyGirls" app which is (was?) available for Java ME capable phones.
 
 <p style="color: orange;">
 WARNING!!! This is not accurate nor correct! You cannot trust
@@ -205,9 +151,9 @@ this program (or any other program) for accurate predictions!
 license, version 3 or any later.
        """
 
-       self.setWindowTitle("About MaeDays")
+       self.setWindowTitle("About MaeGirls")
 
-       self.ltitle=QLabel("MaeDays", self.w)
+       self.ltitle=QLabel("MaeGirls", self.w)
        self.ltitle.setObjectName("title")
        self.ltitle.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        self.ltitle.setAlignment(Qt.AlignCenter)
@@ -232,7 +178,7 @@ class HelpDialog(MyMsgDialog):
        MyMsgDialog.__init__(self, *args, **kwargs)
 
        txt="""
-<p> MaeDays shows information about women's cycle using some generic
+<p> MaeGirls shows information about women's cycle using some generic
 guidelines.  It assumes that the ovolution 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.
@@ -242,12 +188,12 @@ WARNING!!! This is not always correct. There are FAR TOO MANY exceptions
 to the above rules!!!
 
 <p> Assuming that you understand the risk of being wrong, you become
-entitle to read the graph as follows:
+entitled to read the graph as follows:
 <p> <span style="color: red">In red:</span> The days that menstruation
 happens.
 <p> <span style="color: green">In green:</span> The fertile days.
 <p> <span style="color: blue">In blue:</span> The days of PMS
-(Premenstrual Syndrome)
+(Premenstrual Syndrome).
 
 <p> Navigation is easy: Use left-right finger movement to move the calendar
 view. Use up-down finger movement to zoom in/out.
@@ -261,7 +207,83 @@ view. Use up-down finger movement to zoom in/out.
        self.label.setAlignment(Qt.AlignJustify)
        self.l.addWidget(self.label)
 
-class MyDays(QMainWindow):
+class GirlsDialog(QDialog):
+    def __init__(self, *args, **kwargs):
+       QDialog.__init__(self, *args, **kwargs)
+
+       self.l0=QHBoxLayout(self)
+
+       self.lstm=QStringListModel()
+       self.lst=QListView(self)
+       self.lst.setModel(self.lstm)
+
+       self.l0.addWidget(self.lst)
+
+       self.buttonNew=QPushButton(self)
+       self.buttonNew.setText("New")
+
+       self.buttonSelect=QPushButton(self)
+       self.buttonSelect.setText("Select")
+
+       self.buttonDelete=QPushButton(self)
+       self.buttonDelete.setText("Delete")
+
+       spacer=QSpacerItem(20, 20, QSizePolicy.Minimum,QSizePolicy.Expanding)
+
+       self.l1=QVBoxLayout()
+       self.l0.addLayout(self.l1)
+       self.l1.addWidget(self.buttonNew)
+       self.l1.addWidget(self.buttonSelect)
+       self.l1.addWidget(self.buttonDelete)
+       self.l1.addItem(spacer)
+
+       self.buttonNew.clicked.connect(self.slotNew)
+       self.buttonDelete.clicked.connect(self.slotDelete)
+       self.buttonSelect.clicked.connect(self.slotSelect)
+
+       self.what=""
+       self.which=None
+
+    def _get_selection(self):
+       sel=self.lst.selectedIndexes()
+       if len(sel)==1:
+           d=sel[0]
+           ret=str(d.data().toString())
+       else:
+           ret=None
+
+       return(ret)
+
+    def exec_(self, current):
+       # Set data
+       girls=config.loadGirls()
+       dt=girls.keys()
+       dt.sort()
+       self.lstm.setStringList(dt)
+
+       # Set current selection
+       idx=dt.index(current)
+       self.lst.setCurrentIndex(self.lstm.index(idx))
+
+       # Run
+       QDialog.exec_(self)
+
+    def slotNew(self):
+       self.what="new"
+       self.which=None
+       self.accept()
+
+    def slotDelete(self):
+       self.what="delete"
+       self.which=self._get_selection()
+       self.accept()
+       
+    def slotSelect(self):
+       self.what="select"
+       self.which=self._get_selection()
+       self.accept()
+
+class MaeGirls(QMainWindow):
     def __init__(self, algo):
        QMainWindow.__init__(self)
 
@@ -270,6 +292,7 @@ class MyDays(QMainWindow):
        self.dlgConfig=ConfigDialog(self)
        self.dlgAbout=AboutDialog(self)
        self.dlgHelp=HelpDialog(self)
+       self.dlgGirls=None
 
        self.algo=algo
 
@@ -289,6 +312,9 @@ class MyDays(QMainWindow):
        self.menureset=QAction('Go to today', self)
        self.menureset.triggered.connect(self.menuReset)
 
+       self.menugirls=QAction('Girls', self)
+       self.menugirls.triggered.connect(self.menuGirls)
+
        self.menuabout=QAction('About', self)
        self.menuabout.triggered.connect(self.menuAbout)
 
@@ -298,30 +324,91 @@ class MyDays(QMainWindow):
        m=self.menuBar()
        m.addAction(self.menuconfig)
        m.addAction(self.menureset)
-       m.addAction(self.menuabout)
+       m.addAction(self.menugirls)
        m.addAction(self.menuhelp)
+       m.addAction(self.menuabout)
 
-       self.setWindowTitle("MaeDays")
+       self.setWindowTitle("MaeGirls")
 
     def setAlgo(self, algo):
        self.dg.setAlgo(algo)
 
+    def setGirl(self, name):
+       cfg=config.loadGirl(name)
+       self.girl=name
+       self.algo.setReference(cfg['day0'], cfg['cycle'])
+       self.repaint()
+
     def menuConfig(self):
        if self.dlgConfig==None:
            self.dlgConfig=ConfigDialog(self)
 
-       self.dlgConfig.initValues(self.algo.cycleLength(),
-           self.algo.currentDayInCycle())
+       dt={
+           'name':     self.girl,
+           'cycle':    self.algo.cycleLength(),
+           'day0':     self.algo.currentDayInCycle()
+           }
+
+       self.dlgConfig.initValues(dt)
 
        ret=self.dlgConfig.exec_()
 
        if ret==self.dlgConfig.Accepted:
            today=algo.today()
+
+           name=self.dlgConfig.name
            day0=today-self.dlgConfig.current
-           self.algo.setReference(day0, self.dlgConfig.cycle)
-           config.store("default", self.dlgConfig.cycle, day0)
+
+           dt={
+               'cycle':        self.dlgConfig.cycle,
+               'day0':         day0,
+               }
+
+           config.storeGirl(name, dt)
+           config.setCurrentGirl(name)
+
+           # If this is a rename, remove the old one
+           if self.girl!=name:
+               config.removeGirl(self.girl)
+
+           self.setGirl(name)
+
            self.repaint()
 
+    def menuGirls(self):
+       if self.dlgGirls==None:
+           self.dlgGirls=GirlsDialog(self)
+
+       ret=self.dlgGirls.exec_(self.girl)
+
+       what=self.dlgGirls.what
+       which=self.dlgGirls.which
+       if what=='new':
+           # Determine a unique name
+           base="newgirl"
+           idx=0
+           name=base
+           while config.girlExists(name):
+               idx+=1
+               name="%s%d" % (base, idx)
+           # Store this
+           config.newGirl(name)
+           # Set it as current
+           config.setCurrentGirl(name)
+           self.setGirl(name)
+           # Edit it
+           self.menuConfig()
+       elif what=='delete' and which!=None:
+           if self.girl==which:
+               msg=QMessageBox(self)
+               msg.setText("You cannot delete the current girl")
+               msg.exec_()
+           else:
+               config.removeGirl(which)
+       elif what=='select' and which!=None:
+           config.setCurrentGirl(which)
+           self.setGirl(which)
+
     def menuAbout(self):
        if self.dlgAbout==None:
            self.dlgAbout=AboutDialog(self)
@@ -343,13 +430,17 @@ def init(algo):
 
     app=QApplication(sys.argv)
     #app.setAttribute(Qt.WA_Maemo5PortraitOrientation, True);
-    win=MyDays(algo)
+    win=MaeGirls(algo)
     win.show()
 
 def setAlgo(algo):
     global win
     win.setAlgo(algo)
 
+def setGirl(name):
+    global win
+    win.setGirl(name)
+
 def doit():
     global app
     app.exec_()