[Workman-svn] SF.net SVN: workman:[36] trunk
An unobtrusive time-tracking program for self-employed people
Status: Pre-Alpha
Brought to you by:
jmsilva
|
From: <jm...@us...> - 2011-10-21 00:52:34
|
Revision: 36
http://workman.svn.sourceforge.net/workman/?rev=36&view=rev
Author: jmsilva
Date: 2011-10-21 00:52:27 +0000 (Fri, 21 Oct 2011)
Log Message:
-----------
- A couple of dialogs done.
- Some UI changes.
Modified Paths:
--------------
trunk/db.sql
trunk/src/gui/main_window.py
trunk/src/gui/new_employer.ui
trunk/src/gui/new_project.ui
trunk/src/gui/workman.ui
trunk/src/workman.py
Added Paths:
-----------
trunk/src/gui/dialogs.py
Modified: trunk/db.sql
===================================================================
--- trunk/db.sql 2011-10-21 00:52:10 UTC (rev 35)
+++ trunk/db.sql 2011-10-21 00:52:27 UTC (rev 36)
@@ -52,7 +52,7 @@
project_description varchar not null,
employer_id integer not null,
--primary key(project_id),
- unique(project_name),
+ unique(project_name, employer_id),
foreign key(employer_id) references employers
);
Added: trunk/src/gui/dialogs.py
===================================================================
--- trunk/src/gui/dialogs.py (rev 0)
+++ trunk/src/gui/dialogs.py 2011-10-21 00:52:27 UTC (rev 36)
@@ -0,0 +1,150 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Workman - A time tracking program for self-employed people
+# Copyright (C) 2009 João Miguel Ferreira da Silva
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+from PyQt4 import QtGui
+from gui import compiled_ui
+from workman import DataStore
+import workman_types
+'''
+Created on 2009/12/18
+
+@author: jms
+'''
+
+class NewEmployerDialog(QtGui.QDialog, compiled_ui.Ui_newEmployerDialog):
+ '''
+ The dialog used to create employers.
+ '''
+
+ def __init__(self, store):
+ QtGui.QDialog.__init__(self)
+ self.dataStore = store
+ self.setupUi(self)
+ self.okButton = self.buttonBox.button(QtGui.QDialogButtonBox.Ok)
+ self.okButton.setEnabled(False)
+
+ def employerNameChanged(self, text):
+ if text in self.dataStore.employers.keys():
+ self.okButton.setEnabled(False)
+ #TODO: Show a tooltip explaining what happened
+ elif text == '':
+ self.okButton.setEnabled(False)
+ #TODO: Show a tooltip explaining what happened
+ else:
+ self.okButton.setEnabled(True)
+
+ def accept(self):
+ name = self.employerNameBox.text()
+ desc = self.descriptionBox.toPlainText()
+ rate = self.hourlyRateSpinner.value()
+ self.dataStore.addEmployer(name, desc, rate)
+
+ QtGui.QDialog.accept(self)
+
+
+
+class NewProjectDialog(QtGui.QDialog, compiled_ui.Ui_newProjectDialog):
+ '''
+ The dialog used to create projects.
+ '''
+
+
+ def __init__(self, store):
+ '''
+ Constructor
+ '''
+ QtGui.QDialog.__init__(self)
+ self.dataStore = store
+ self.setupUi(self)
+ self.comboBoxIndex = 0
+ self.ignoreComboBoxChanges = False
+ self.__populateEmployerBox()
+
+
+ self.okButton = self.buttonBox.button(QtGui.QDialogButtonBox.Ok)
+ self.okButton.setEnabled(False)
+
+ def comboIndexChanged(self, index):
+ if self.ignoreComboBoxChanges:
+ return
+ if index == self.employerChoice.count() - 1:
+ self.ignoreComboBoxChanges = True
+ self.employerChoice.setCurrentIndex(self.comboBoxIndex)
+ employerDialog = NewEmployerDialog(self.dataStore)
+ employerDialog.setModal(True)
+ if employerDialog.exec_() == QtGui.QDialog.Accepted:
+ self.__populateEmployerBox(employerDialog.employerNameBox.text())
+ self.ignoreComboBoxChanges = False
+ else:
+ self.comboBoxIndex = index
+ self.__checkOkButtonState()
+
+ def __checkOkButtonState(self):
+ text = self.projectNameBox.text()
+ if self.comboBoxIndex == 0:
+ currentEmployer = DataStore.NO_EMPLOYER
+ else:
+ currentEmployer = self.employerChoice.currentText()
+
+ if text in self.dataStore.employers[currentEmployer].projects.keys():
+ self.okButton.setEnabled(False)
+ #TODO: Show a tooltip explaining what happened
+ elif text == '':
+ self.okButton.setEnabled(False)
+ #TODO: Show a tooltip explaining what happened
+ else:
+ self.okButton.setEnabled(True)
+
+
+ def projectNameChanged(self, text):
+ self.__checkOkButtonState()
+
+ def accept(self):
+ if self.employerChoice.currentIndex() == 0:
+ employerName = DataStore.NO_EMPLOYER
+ else:
+ employerName = self.employerChoice.currentText()
+
+ projectName = self.projectNameBox.text()
+ projectDescription = self.descriptionBox.toPlainText()
+
+ self.dataStore.addProject(
+ projectName, projectDescription, employerName)
+
+ QtGui.QDialog.accept(self)
+
+
+
+ def __populateEmployerBox(self, defaultItem = None):
+ self.ignoreComboBoxChanges = True
+ self.employerChoice.clear()
+ self.employerChoice.addItem(self.tr('None (personal project)'))
+ items = 1
+ for i in self.dataStore.employers.values():
+ if i.name != DataStore.NO_EMPLOYER:
+ self.employerChoice.addItem(i.name)
+ if i.name == defaultItem:
+ self.comboBoxIndex = items
+ self.employerChoice.setCurrentIndex(items)
+ items += 1
+
+ if(items > 1):
+ self.employerChoice.insertSeparator(1)
+ self.employerChoice.insertSeparator(items + 1)
+ self.employerChoice.addItem(self.tr('New...'))
+ self.ignoreComboBoxChanges = False
Modified: trunk/src/gui/main_window.py
===================================================================
--- trunk/src/gui/main_window.py 2011-10-21 00:52:10 UTC (rev 35)
+++ trunk/src/gui/main_window.py 2011-10-21 00:52:27 UTC (rev 36)
@@ -16,6 +16,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+from gui import dialogs
'''
Created on 2009/12/17
@@ -38,8 +39,8 @@
'''
QtGui.QMainWindow.__init__(self)
self.setupUi(self)
- itemModel = dataStore.getProjectItemModel()
- self.projectList.setModel(itemModel)
+ self.dataStore = dataStore
+ self.__reloadItemModel()
self.connect(self.quitButton, QtCore.SIGNAL('clicked()'),
QtGui.qApp, QtCore.SLOT('quit()'))
@@ -50,11 +51,17 @@
def createProject(self):
'''Opens the new project dialog'''
-
- pass
+ self.projectList.selectedIndexes()
+ dialog = dialogs.NewProjectDialog(self.dataStore)
+ dialog.setModal(True)
+ if dialog.exec_() == QtGui.QDialog.Accepted:
+ self.__reloadItemModel()
def viewSessions(self):
'''Opens the view sessions dialog'''
#TODO
pass
-
\ No newline at end of file
+
+ def __reloadItemModel(self):
+ itemModel = self.dataStore.getProjectItemModel()
+ self.projectList.setModel(itemModel)
\ No newline at end of file
Modified: trunk/src/gui/new_employer.ui
===================================================================
--- trunk/src/gui/new_employer.ui 2011-10-21 00:52:10 UTC (rev 35)
+++ trunk/src/gui/new_employer.ui 2011-10-21 00:52:27 UTC (rev 36)
@@ -27,6 +27,9 @@
<property name="text">
<string>Employer name</string>
</property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
</widget>
</item>
<item row="0" column="1">
@@ -37,6 +40,9 @@
<property name="text">
<string>Employer description</string>
</property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
</widget>
</item>
<item row="2" column="0">
@@ -44,6 +50,9 @@
<property name="text">
<string>Hourly Rate</string>
</property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
</widget>
</item>
<item row="2" column="1">
@@ -62,6 +71,9 @@
</item>
<item row="1" column="1">
<widget class="QTextEdit" name="descriptionBox">
+ <property name="tabChangesFocus">
+ <bool>true</bool>
+ </property>
<property name="acceptRichText">
<bool>false</bool>
</property>
@@ -96,8 +108,8 @@
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
- <x>248</x>
- <y>254</y>
+ <x>257</x>
+ <y>202</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
@@ -112,8 +124,8 @@
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
- <x>316</x>
- <y>260</y>
+ <x>325</x>
+ <y>202</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
@@ -121,5 +133,24 @@
</hint>
</hints>
</connection>
+ <connection>
+ <sender>employerNameBox</sender>
+ <signal>textChanged(QString)</signal>
+ <receiver>newEmployerDialog</receiver>
+ <slot>employerNameChanged(QString)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>172</x>
+ <y>30</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>135</x>
+ <y>27</y>
+ </hint>
+ </hints>
+ </connection>
</connections>
+ <slots>
+ <slot>employerNameChanged(QString)</slot>
+ </slots>
</ui>
Modified: trunk/src/gui/new_project.ui
===================================================================
--- trunk/src/gui/new_project.ui 2011-10-21 00:52:10 UTC (rev 35)
+++ trunk/src/gui/new_project.ui 2011-10-21 00:52:27 UTC (rev 36)
@@ -24,6 +24,9 @@
<property name="text">
<string>Project name</string>
</property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
</widget>
</item>
<item row="1" column="1">
@@ -38,6 +41,9 @@
<property name="text">
<string>Project description</string>
</property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
</widget>
</item>
<item row="2" column="1">
@@ -45,6 +51,9 @@
<property name="toolTip">
<string>Enter an optional description for this project</string>
</property>
+ <property name="tabChangesFocus">
+ <bool>true</bool>
+ </property>
<property name="acceptRichText">
<bool>false</bool>
</property>
@@ -55,6 +64,9 @@
<property name="text">
<string>Employer</string>
</property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
</widget>
</item>
<item row="3" column="1">
@@ -62,16 +74,6 @@
<property name="toolTip">
<string>The employer you are working for</string>
</property>
- <item>
- <property name="text">
- <string>None (personal project)</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>New...</string>
- </property>
- </item>
</widget>
</item>
</layout>
@@ -128,5 +130,41 @@
</hint>
</hints>
</connection>
+ <connection>
+ <sender>employerChoice</sender>
+ <signal>currentIndexChanged(int)</signal>
+ <receiver>newProjectDialog</receiver>
+ <slot>comboIndexChanged(int)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>197</x>
+ <y>159</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>85</x>
+ <y>99</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>projectNameBox</sender>
+ <signal>textChanged(QString)</signal>
+ <receiver>newProjectDialog</receiver>
+ <slot>projectNameChanged(QString)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>177</x>
+ <y>33</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>99</x>
+ <y>86</y>
+ </hint>
+ </hints>
+ </connection>
</connections>
+ <slots>
+ <slot>comboIndexChanged(int)</slot>
+ <slot>projectNameChanged(QString)</slot>
+ </slots>
</ui>
Modified: trunk/src/gui/workman.ui
===================================================================
--- trunk/src/gui/workman.ui 2011-10-21 00:52:10 UTC (rev 35)
+++ trunk/src/gui/workman.ui 2011-10-21 00:52:27 UTC (rev 36)
@@ -35,6 +35,18 @@
<property name="gridStyle">
<enum>Qt::NoPen</enum>
</property>
+ <property name="sortingEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="cornerButtonEnabled">
+ <bool>false</bool>
+ </property>
+ <attribute name="horizontalHeaderHighlightSections">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="verticalHeaderVisible">
+ <bool>false</bool>
+ </attribute>
</widget>
</item>
<item>
@@ -145,8 +157,8 @@
<slot>viewSessions()</slot>
<hints>
<hint type="sourcelabel">
- <x>558</x>
- <y>103</y>
+ <x>662</x>
+ <y>151</y>
</hint>
<hint type="destinationlabel">
<x>549</x>
Modified: trunk/src/workman.py
===================================================================
--- trunk/src/workman.py 2011-10-21 00:52:10 UTC (rev 35)
+++ trunk/src/workman.py 2011-10-21 00:52:27 UTC (rev 36)
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from datetime import datetime
-from PyQt4 import QtGui
+from PyQt4 import QtGui, QtCore
import sys
import workman_types
'''
@@ -30,14 +30,16 @@
class DataStore:
'''Where the program data is stored in memory'''
+ NO_EMPLOYER = 'None'
+
def __init__(self, db):
self.db = db
self.projectItemModel = None
if db is None:
noEmployer = workman_types.Employer(
- 'None', 0.0, 'For projects done at no charge')
- workman_types.Project('None', noEmployer, 'For personal projects')
- self.employers = [noEmployer]
+ DataStore.NO_EMPLOYER, 0.0, 'For projects done at no charge')
+ workman_types.Project(DataStore.NO_EMPLOYER, noEmployer, 'For personal projects')
+ self.employers = {DataStore.NO_EMPLOYER : noEmployer}
self.activeSession = None
self.activeBreak = None
return
@@ -74,27 +76,61 @@
curBreak.endTime = datetime.now()
self.activeBreak = None
- def addEmployer(self, employer):
- assert employer is not None
+ def addEmployer(self, name, description, rate):
+ assert(name not in self.employers.keys() and
+ name is not None and name != '')
+
+ employer = workman_types.Employer(name, rate, description)
self.employers[employer.name] = employer
#TODO: Write data to database
- def addProject(self, project, employerName):
- assert(project is not None and
- employerName is not None and employerName != '')
- project.setEmployer(self.employers[employerName])
+ def addProject(self, projectName, description, employerName):
+ assert(projectName is not None and projectName != '' and
+ employerName is not None and employerName != '' and
+ employerName in self.employers.keys() and
+ projectName not in self.employers[employerName].projects.keys())
+
+ workman_types.Project(
+ projectName,
+ self.employers[employerName], description)
if self.projectItemModel is not None:
- self.projectItemModel.appendRow([project.name, employerName])
-
+ self.projectItemModel.appendRow(self.__newItemModelRow(
+ employerName, projectName, description))
+
+
+ def __newItemModelRow(self, employerName, projectName, projDesc):
+ employerItem = QtGui.QStandardItem(employerName)
+ projectItem = QtGui.QStandardItem(projectName)
+ descriptionItem = QtGui.QStandardItem(projDesc)
+ return [employerItem, projectItem, descriptionItem]
+
def getProjectItemModel(self):
if self.projectItemModel is None:
self.projectItemModel = QtGui.QStandardItemModel()
self.projectItemModel.setHorizontalHeaderLabels(
- ['Project', 'Employer'])
- for i in self.employers:
- for j in i.projects:
+ [QtGui.qApp.tr("Project"),
+ QtGui.qApp.tr("Employer"),
+ QtGui.qApp.tr("Description")])
+
+
+ for i in self.employers.values():
+ if i.name != DataStore.NO_EMPLOYER:
+ employerName = i.name
+ else:
+ employerName = QtGui.qApp.tr("None (personal project)")
+
+
+ for j in i.projects.values():
+ if(i.name == DataStore.NO_EMPLOYER and
+ j.name != DataStore.NO_EMPLOYER):
+ projectName = j.name
+ else:
+ projectName = QtGui.qApp.tr("Unsorted")
+
+
self.projectItemModel.appendRow(
- [j.name, i.name])
+ self.__newItemModelRow(
+ employerName, projectName, j.description))
return self.projectItemModel
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|