workman-svn Mailing List for Workman
An unobtrusive time-tracking program for self-employed people
Status: Pre-Alpha
Brought to you by:
jmsilva
You can subscribe to this list here.
2008 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
(1) |
Sep
|
Oct
|
Nov
|
Dec
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
2011 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(46) |
Nov
|
Dec
|
From: <jm...@us...> - 2011-10-21 00:59:35
|
Revision: 47 http://workman.svn.sourceforge.net/workman/?rev=47&view=rev Author: jmsilva Date: 2011-10-21 00:59:28 +0000 (Fri, 21 Oct 2011) Log Message: ----------- - Wizard done. Now to make it do something useful... Modified Paths: -------------- trunk/db.sql trunk/src/db.py trunk/src/gui/wizard.py trunk/src/gui/wizard.ui trunk/src/workman.py Modified: trunk/db.sql =================================================================== --- trunk/db.sql 2011-10-21 00:59:14 UTC (rev 46) +++ trunk/db.sql 2011-10-21 00:59:28 UTC (rev 47) @@ -28,6 +28,7 @@ employer_id integer primary key autoincrement, employer_name varchar(128) not null, employer_description varchar not null, + employer_archived boolean not null, --primary key(employer_id), unique(employer_name) ); @@ -50,6 +51,7 @@ project_id integer primary key autoincrement, project_name varchar(128) not null, project_description varchar not null, + project_archived boolean not null, employer_id integer not null, --primary key(project_id), unique(project_name, employer_id), @@ -105,10 +107,10 @@ */ insert into employers - values(1, 'None', 'For personal projects'); + values(1, 'None', 'For personal projects', FALSE); insert into employer_instances(employer_id, employer_hourly_rate, employer_rate_start_date) values(1, 0.0, datetime()); -insert into projects(project_name, project_description, employer_id) - select 'None', 'For unassigned projects', employer_id from employers; +insert into projects(project_name, project_description, project_archived, employer_id) + select 'None', 'For uncategorized projects', FALSE, employer_id from employers; Modified: trunk/src/db.py =================================================================== --- trunk/src/db.py 2011-10-21 00:59:14 UTC (rev 46) +++ trunk/src/db.py 2011-10-21 00:59:28 UTC (rev 47) @@ -31,29 +31,26 @@ ''' # TODO: What if the database goes down? - # TODO: Generalize SQL insert and select statement handling # TODO: Add remaining needed methods - def __init__(self, dbType = 'QSQLITE', dbName = 'workman', - dbUsername = '', dbPassword = '', dbConnectOptions = ''): - ''' - Connects to the database - ''' + def __init__(self, dbType = 'QSQLITE', dbHost = '', dbPort = 0, + dbName = '', dbUsername = '', dbPassword = '', + dbConnectOptions = ''): + '''Connects to the database''' + self.db = QtSql.QSqlDatabase.addDatabase(dbType) - self.db.setDatabaseName('workman') - self.db.setUsername(dbUsername) - self.db.setPassword(dbPassword) + self.db.setDatabaseName(dbName) + self.db.setHostName(dbHost) + self.db.setPort(dbPort) self.db.setConnectOptions(dbConnectOptions) - if not self.db.open(): - raise RuntimeError('Unable to open database. dbType: %s, ' - 'dbName: %s, dbUsername: %s' % (dbType, dbName, dbUsername)) + if not self.db.open(dbUsername, dbPassword): + raise RuntimeError(str(self.db.lastError().text())) self.pendingQueries = {} self.lastQuery = 0 def insertEmployer(self, employer, rate): - ''' - Inserts a new employer into the Database - ''' + '''Inserts a new employer into the Database''' + if employer is None or rate is None: return False @@ -66,13 +63,11 @@ return query.exec_() def insertSession(self, project, startDate, endDate, desc, breaks): - ''' - Inserts a new session into the Database - ''' + '''Inserts a new session into the Database''' + if project is None or startDate is None or endDate is None or desc is None: return False - QtSql.QSqlDatabase.transaction(); query = QtSql.QSqlQuery(self.db) query.prepare('Insert into sessions(project_name, ' 'project_description, employer_id) values(' @@ -124,9 +119,8 @@ pass""" def getSessions(self, project): - ''' - Gets a list of sessions for a given project - ''' + '''Gets a list of sessions for a given project''' + query = QtSql.QSqlQuery(self.db) query.prepare('select session_id, session_start_time, session_end_time, ' 'session_description from sessions where project_id = :project;') Modified: trunk/src/gui/wizard.py =================================================================== --- trunk/src/gui/wizard.py 2011-10-21 00:59:14 UTC (rev 46) +++ trunk/src/gui/wizard.py 2011-10-21 00:59:28 UTC (rev 47) @@ -18,47 +18,159 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. from PyQt4 import QtGui, QtCore from gui.compiled_ui import Ui_Wizard -''' -Created on 2009/12/21 +from db import DB +import os.path +import re -@author: João Miguel Ferreira da Silva -''' + class WizardStartPage(QtGui.QWizardPage): def __init__(self): QtGui.QWizardPage.__init__(self) - def nextId(self): + def nextId(self): button = self.findChild( - QtGui.QRadioButton, 'projectNoButton') + QtGui.QRadioButton, 'dbNoButton') - if button.isChecked(): - return -1 + if button.isChecked(): + return Wizard.PROJECT_PAGE - return 1 + return Wizard.DB_PAGE - def raiseCompleteChanged(self): - button = self.findChild( - QtGui.QRadioButton, 'projectNoButton') - if button.isChecked(): - self.setFinalPage(True) +class WizardDBPage(QtGui.QWizardPage): + # TODO: Change the port spinner to the default for each DB type + def __init__(self): + QtGui.QWizardPage.__init__(self) + validIpv4AddressRegex = ('^((\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.){3}' + + '(\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])$') + #TODO: IPv6 address + # Hostnames, as defined in RFC 952 and amended in RFC 1123, separated by dots + validHostNameRegex = ('^(([\da-zA-Z]|[\da-zA-Z][\da-zA-Z\-]*[\da-zA-Z])\.)*' + + '([\da-zA-Z]|[\da-zA-Z][\da-zA-Z\-]*[\da-zA-Z])+$') + self.ipRegex = re.compile(validIpv4AddressRegex) + self.hostRegex = re.compile(validHostNameRegex) + + def browse(self): + '''Opens a file selection dialog at the currently selected directory + and changes fileNameBox's text to the selected file.''' + curDir = os.path.dirname(str(self.fileNameBox.text())) + if not os.path.exists(curDir): + curDir = os.path.expanduser('~') + newFileName = QtGui.QFileDialog.getSaveFileName(self.wizard(), + self.tr('Select database file location'), curDir, + options = QtGui.QFileDialog.DontConfirmOverwrite) + if newFileName != '': + self.fileNameBox.setText(newFileName) + + def updateNextButtonText(self): + if(self.fileSaveRadio.isChecked()): + if os.path.exists(self.fileNameBox.text()): + self.setButtonText(QtGui.QWizard.NextButton, self.tr('&Load')) + else: + self.setButtonText(QtGui.QWizard.NextButton, self.tr('&Create')) else: - self.setFinalPage(False) - self.emit(QtCore.SIGNAL('completeChanged()')) - + self.setButtonText(QtGui.QWizard.NextButton, self.tr('&Connect')) + def initializePage(self): + browseButton = self.findChild(QtGui.QPushButton, 'browseButton') + self.connect(browseButton, QtCore.SIGNAL('clicked()'), self.browse) + self.fileSaveRadio = self.findChild(QtGui.QRadioButton, 'fileSaveRadio') + self.fileNameBox = self.findChild(QtGui.QLineEdit, 'fileNameBox') + self.fileNameBox.setText(os.path.join(os.path.expanduser('~'), 'workman.db')) + # TODO: Read the default filename from the config + + self.updateNextButtonText() + + dbTypeChoice = self.findChild(QtGui.QComboBox, 'dbTypeChoice') + dbTypeChoice.addItem('IBM DB2', 'QDB2') + dbTypeChoice.addItem('Borland Interbase', 'QIBASE') + dbTypeChoice.addItem('MySQL', 'QMYSQL') + dbTypeChoice.addItem('ODBC', 'QODBC') + dbTypeChoice.addItem('Oracle Call Interface', 'QOCI') + dbTypeChoice.addItem('PostgreSQL', 'QPSQL') + dbTypeChoice.addItem('Sybase', 'QTDS') + + def emitCompleteChanged(self): + self.updateNextButtonText() + self.emit(QtCore.SIGNAL('completeChanged()')) + + def isComplete(self): + if self.fileSaveRadio.isChecked(): + # Is it a good idea to create the path if it doesn't exist? + if os.path.exists(os.path.dirname(str(self.fileNameBox.text()))): + return True + else: + return False + else: + dbHostText = self.findChild(QtGui.QLineEdit, 'dbHostBox').text() + matchesIp = self.ipRegex.match(dbHostText) is not None + matchesHost = self.hostRegex.match(dbHostText) is not None + # TODO: Check if there's a need to validate the other fields, and react accordingly + return matchesIp or matchesHost + class Wizard(QtGui.QWizard, Ui_Wizard): + START_PAGE = 0 + DB_PAGE = 1 + PROJECT_PAGE = 2 + FINAL_PAGE = 3 def __init__(self): QtGui.QWizard.__init__(self) self.setupUi(self) + self.ignoreIdChange = False + self.db = None + self.connect(self, QtCore.SIGNAL('currentIdChanged(int)'), self.tryDBConnect) - + def tryDBConnect(self, pageId): + '''Check whether the DB page's next button has been pressed, and, in that case, + creates or connects to the database. + pageId: An integer representing the new wizard page's id, as sent by the + currentIdChanged signal.''' + print (pageId, self.PROJECT_PAGE, self.visitedPages()) + if self.ignoreIdChange: + return + if(pageId == self.PROJECT_PAGE and + self.visitedPages()[-2] == self.DB_PAGE): + saveInFile = self.dbPage.findChild( + QtGui.QRadioButton, 'fileSaveRadio').isChecked() + + if saveInFile: + dbType = 'QSQLITE' # Qt SQLite driver + dbHost = dbUserName = dbPassword = '' + dbPort = 0 + dbName = str(self.dbPage.findChild(QtGui.QLineEdit, 'fileNameBox').text()) + else: + choiceBox = self.dbPage.findChild(QtGui.QComboBox, 'dbTypeChoice') + dbType = str(choiceBox.itemData(choiceBox.currentIndex()).toString()) + dbHost = str(self.dbPage.findChild(QtGui.QLineEdit, 'dbHostBox').text()) + dbPort = self.dbPage.findChild(QtGui.QSpinBox, 'dbPortSpinner').value() + dbUserName = str(self.dbPage.findChild( + QtGui.QLineEdit, 'dbUserNameBox').text()) + dbPassword = str(self.dbPage.findChild( + QtGui.QLineEdit, 'dbPasswordBox').text()) + dbName = str(self.dbPage.findChild(QtGui.QLineEdit, 'dbNameBox').text()) + + self.ignoreIdChange = True + + try: + self.db = DB(dbType, dbHost, dbPort, dbName, dbUserName, dbPassword) + except RuntimeError as error: + self.back() + QtGui.QMessageBox.critical(self, + self.tr('Couldn\'t connect to database'), + self.tr('There was an error connecting to the database.\n\n' + + 'Details: ') + error.message) + + self.ignoreIdChange = False + + + + if __name__ == '__main__': import sys QtGui.QApplication(sys.argv) Modified: trunk/src/gui/wizard.ui =================================================================== --- trunk/src/gui/wizard.ui 2011-10-21 00:59:14 UTC (rev 46) +++ trunk/src/gui/wizard.ui 2011-10-21 00:59:28 UTC (rev 47) @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>508</width> - <height>397</height> + <width>500</width> + <height>374</height> </rect> </property> <property name="windowTitle"> @@ -27,186 +27,217 @@ <property name="subTitle"> <string>Welcome to Workman.</string> </property> - <layout class="QVBoxLayout" name="verticalLayout_3"> + <layout class="QVBoxLayout" name="verticalLayout"> <item> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QLabel" name="projectLabel"> - <property name="locale"> - <locale language="English" country="UnitedStates"/> - </property> - <property name="text"> - <string>Hello, and welcome to Workman. + <widget class="QLabel" name="dbLabel"> + <property name="locale"> + <locale language="English" country="UnitedStates"/> + </property> + <property name="text"> + <string>Workman lets you organize your work into projects you do for certain employers, and helps you track the time you spend on each of them. -To bill or organize your work, you are advised to split it into projects. - -Would you like to create a project now?</string> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> +Would you like to set up where your user data is stored?</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="dbYesButton"> + <property name="text"> + <string>Yes</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="dbNoButton"> + <property name="text"> + <string>No, use default settings</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="WizardDBPage" name="dbPage"> + <property name="title"> + <string>Database configuration</string> + </property> + <property name="subTitle"> + <string>To get started, set up how you want to save your information.</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <widget class="QRadioButton" name="fileSaveRadio"> + <property name="text"> + <string>Save the database in a local file (recommended)</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> <item> - <widget class="QRadioButton" name="projectYesButton"> - <property name="locale"> - <locale language="English" country="UnitedStates"/> - </property> - <property name="text"> - <string>&Yes</string> - </property> - <property name="checked"> - <bool>true</bool> - </property> - </widget> + <widget class="QLineEdit" name="fileNameBox"/> </item> <item> - <widget class="QRadioButton" name="projectNoButton"> + <widget class="QPushButton" name="browseButton"> <property name="text"> - <string>&No</string> + <string>Browse...</string> </property> </widget> </item> - <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> </layout> </item> + <item> + <widget class="QRadioButton" name="dbConnectRadio"> + <property name="text"> + <string>Connect to a database to retrieve your information</string> + </property> + </widget> + </item> + <item> + <widget class="QGroupBox" name="dbGroupBox"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="title"> + <string>Database connection info</string> + </property> + <layout class="QFormLayout" name="formLayout_2"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::ExpandingFieldsGrow</enum> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="dbTypeLabel"> + <property name="text"> + <string extracomment="The database's type">Type</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="dbTypeChoice"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="insertPolicy"> + <enum>QComboBox::NoInsert</enum> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="dbHostLabel"> + <property name="text"> + <string extracomment="The database server's host name">Host name</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="dbHostBox"/> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="dbPortLabel"> + <property name="text"> + <string extracomment="Network port the database server is using">Port</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QSpinBox" name="dbPortSpinner"> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>65535</number> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="usernameLabel"> + <property name="text"> + <string>User name</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QLineEdit" name="dbUserNameBox"/> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="passwordLabel"> + <property name="text"> + <string>Password</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QLineEdit" name="dbPasswordBox"> + <property name="echoMode"> + <enum>QLineEdit::Password</enum> + </property> + </widget> + </item> + <item row="5" column="0"> + <widget class="QLabel" name="dbNameLabel"> + <property name="text"> + <string>Database name</string> + </property> + </widget> + </item> + <item row="5" column="1"> + <widget class="QLineEdit" name="dbNameBox"/> + </item> + </layout> + </widget> + </item> </layout> </widget> - <widget class="QWizardPage" name="lastPage"> + <widget class="QWizardPage" name="projectPage"> <property name="title"> - <string>Creating a project</string> + <string>Almost there!</string> </property> <property name="subTitle"> - <string>Please enter some information about the project.</string> + <string>You've almost finished the initial setup.</string> </property> <layout class="QVBoxLayout" name="verticalLayout_4"> <item> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <item> - <layout class="QFormLayout" name="formLayout"> - <item row="0" column="0"> - <widget class="QLabel" name="projectNameLabel"> - <property name="text"> - <string>Project Name</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QLineEdit" name="projectNameBox"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="toolTip"> - <string>The name of the project you want to create</string> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QComboBox" name="employerChoice"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="toolTip"> - <string>The employer for this project</string> - </property> - <item> - <property name="text"> - <string>None (personal project)</string> - </property> - </item> - <item> - <property name="text"> - <string>New...</string> - </property> - </item> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Description</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QTextEdit" name="textEdit"> - <property name="enabled"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="employerLabel"> - <property name="text"> - <string>Employer</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QLabel" name="startSessionLabel"> - <property name="text"> - <string>Would you like to start a work session right now?</string> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QRadioButton" name="sessionYesButton"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="text"> - <string>&Yes</string> - </property> - <property name="checked"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QRadioButton" name="sessionNoButton"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="text"> - <string>&No</string> - </property> - </widget> - </item> - <item> - <spacer name="verticalSpacer_2"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Expanding</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> + <widget class="QLabel" name="projectTutorialLabel"> + <property name="text"> + <string>Workman tracks the time you spent in projects, done for several employers. + +Would you like to create a project now?</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> </item> + <item> + <widget class="QCheckBox" name="projectCheckBox"> + <property name="text"> + <string>Create a project now</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>This concludes the initial setup. If you've selected to create a new project, a window allowing you to enter the project's details will appear. + +Thank you for using Workman!</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> </layout> </widget> </widget> @@ -220,51 +251,130 @@ <slot>raiseCompleteChanged()</slot> </slots> </customwidget> + <customwidget> + <class>WizardDBPage</class> + <extends>QWizardPage</extends> + <header>wizard.h</header> + <container>1</container> + <slots> + <slot>emitCompleteChanged()</slot> + </slots> + </customwidget> </customwidgets> <tabstops> - <tabstop>projectYesButton</tabstop> - <tabstop>projectNoButton</tabstop> - <tabstop>projectNameBox</tabstop> - <tabstop>textEdit</tabstop> - <tabstop>employerChoice</tabstop> - <tabstop>sessionYesButton</tabstop> - <tabstop>sessionNoButton</tabstop> + <tabstop>dbYesButton</tabstop> + <tabstop>dbNoButton</tabstop> + <tabstop>fileSaveRadio</tabstop> + <tabstop>fileNameBox</tabstop> + <tabstop>browseButton</tabstop> + <tabstop>dbConnectRadio</tabstop> + <tabstop>dbTypeChoice</tabstop> + <tabstop>dbHostBox</tabstop> + <tabstop>dbPortSpinner</tabstop> + <tabstop>dbUserNameBox</tabstop> + <tabstop>dbPasswordBox</tabstop> + <tabstop>dbNameBox</tabstop> + <tabstop>projectCheckBox</tabstop> </tabstops> <resources> <include location="res.qrc"/> </resources> <connections> <connection> - <sender>projectNoButton</sender> - <signal>clicked()</signal> - <receiver>startPage</receiver> - <slot>raiseCompleteChanged()</slot> + <sender>fileSaveRadio</sender> + <signal>toggled(bool)</signal> + <receiver>fileNameBox</receiver> + <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>63</x> - <y>211</y> + <x>106</x> + <y>68</y> </hint> <hint type="destinationlabel"> - <x>82</x> - <y>301</y> + <x>119</x> + <y>96</y> </hint> </hints> </connection> <connection> - <sender>projectYesButton</sender> - <signal>clicked()</signal> - <receiver>startPage</receiver> - <slot>raiseCompleteChanged()</slot> + <sender>dbConnectRadio</sender> + <signal>toggled(bool)</signal> + <receiver>dbGroupBox</receiver> + <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>138</x> - <y>179</y> + <x>65</x> + <y>120</y> </hint> <hint type="destinationlabel"> - <x>198</x> - <y>266</y> + <x>65</x> + <y>144</y> </hint> </hints> </connection> + <connection> + <sender>fileSaveRadio</sender> + <signal>toggled(bool)</signal> + <receiver>browseButton</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>458</x> + <y>72</y> + </hint> + <hint type="destinationlabel"> + <x>458</x> + <y>105</y> + </hint> + </hints> + </connection> + <connection> + <sender>fileNameBox</sender> + <signal>textChanged(QString)</signal> + <receiver>dbPage</receiver> + <slot>emitCompleteChanged()</slot> + <hints> + <hint type="sourcelabel"> + <x>139</x> + <y>99</y> + </hint> + <hint type="destinationlabel"> + <x>113</x> + <y>350</y> + </hint> + </hints> + </connection> + <connection> + <sender>dbHostBox</sender> + <signal>textChanged(QString)</signal> + <receiver>dbPage</receiver> + <slot>emitCompleteChanged()</slot> + <hints> + <hint type="sourcelabel"> + <x>306</x> + <y>205</y> + </hint> + <hint type="destinationlabel"> + <x>302</x> + <y>361</y> + </hint> + </hints> + </connection> + <connection> + <sender>fileSaveRadio</sender> + <signal>toggled(bool)</signal> + <receiver>dbPage</receiver> + <slot>emitCompleteChanged()</slot> + <hints> + <hint type="sourcelabel"> + <x>213</x> + <y>72</y> + </hint> + <hint type="destinationlabel"> + <x>230</x> + <y>362</y> + </hint> + </hints> + </connection> </connections> </ui> Modified: trunk/src/workman.py =================================================================== --- trunk/src/workman.py 2011-10-21 00:59:14 UTC (rev 46) +++ trunk/src/workman.py 2011-10-21 00:59:28 UTC (rev 47) @@ -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 PyQt4 import QtGui, QtCore -from PyQt4.Qt import Qt +from PyQt4.QtCore import Qt import sys import workman_types ''' @@ -28,7 +28,7 @@ ''' class DataStore: - '''Where the program data is stored in memory''' + '''Class responsible for Workman's business logic''' NO_EMPLOYER = 'None' # Not to be translated (here) NO_EMPLOYER_TRANSLATED = '' @@ -38,11 +38,11 @@ NO_PROJECT_DESCRIPTION = '' def __init__(self, db): - #: Meaning this project is for no employer + # Meaning this project is for no employer DataStore.NO_EMPLOYER_TRANSLATED = QtGui.qApp.tr("None (personal project)") DataStore.NO_EMPLOYER_DESCRIPTION = QtGui.qApp.tr( "For personal projects") - #: Refers to the fact that this isn't any particular project + # Refers to the fact that this isn't any particular project DataStore.NO_PROJECT_TRANSLATED = QtGui.qApp.tr("Unsorted") DataStore.NO_PROJECT_DESCRIPTION = QtGui.qApp.tr("General work") @@ -56,7 +56,7 @@ self.activeSession = None self.activeBreak = None - return + return #TODO: get stuff from DB @@ -167,7 +167,9 @@ return self.projectItemModel def __getHoursWorked(self, project): - """Returns the total time worked on a project, in seconds""" + """Returns the total time worked on a project, in seconds + + project: a Project object""" result = 0 # Get total number of seconds worked for i in project.sessions: @@ -179,7 +181,9 @@ return result def __getSessionInfo(self, session): - """Returns a triplet of (total_time_worked, number_of_breaks, total_break_time)""" + """Returns a triplet of (total_time_worked, number_of_breaks, total_break_time) + + session: a Session object""" assert session.startTime is not None timeWorked = numBreaks = breakTime = 0 @@ -248,7 +252,7 @@ project = self.employers[employer].projects[project] for i in project.sessions: - if i.startTime < startDate or i.startTime > endDate: + if i.endTime < startDate or i.startTime > endDate: continue timeWorked, numBreaks, breakTime = self.__getSessionInfo(i) @@ -263,12 +267,19 @@ if __name__ == '__main__': from gui.main_window import MainWindow from gui.wizard import Wizard + from config import Config app = QtGui.QApplication(sys.argv) app.setQuitOnLastWindowClosed(False) - data = DataStore(None) - #TODO: Read a config file, create a database and show wizard if not found - y = Wizard() - y.exec_() + + conf = Config() + db = None + if not conf.load(): + conf.create() + y = Wizard() + y.exec_() + db = y.db + + data = DataStore(db) x = MainWindow(data) x.show() sys.exit(app.exec_()) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jm...@us...> - 2011-10-21 00:59:20
|
Revision: 46 http://workman.svn.sourceforge.net/workman/?rev=46&view=rev Author: jmsilva Date: 2011-10-21 00:59:14 +0000 (Fri, 21 Oct 2011) Log Message: ----------- - Initial values on combo boxes from the create project and delete project dialog boxes now reflect the selected project in the main window - Removed option to add employers/projects from informational dialog boxes - Little bug fixes Modified Paths: -------------- trunk/src/gui/dialogs.py trunk/src/gui/main_window.py trunk/src/workman.py Modified: trunk/src/gui/dialogs.py =================================================================== --- trunk/src/gui/dialogs.py 2011-10-21 00:59:02 UTC (rev 45) +++ trunk/src/gui/dialogs.py 2011-10-21 00:59:14 UTC (rev 46) @@ -16,9 +16,8 @@ # # 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.QtGui import QDialog, QDialogButtonBox, QWidget +from PyQt4.QtGui import QDialog, QDialogButtonBox from gui import compiled_ui -from workman import DataStore from gui.compiled_ui import Ui_startSessionDialog, Ui_endSessionDialog, Ui_viewSessionsDialog ''' Created on 2009/12/18 @@ -26,6 +25,9 @@ @author: jms ''' +'''TODO: There's a lot of repeated code on employer/project choice boxes. + Those should be generalized.''' + class NewEmployerDialog(QDialog, compiled_ui.Ui_newEmployerDialog): ''' The dialog used to create employers. @@ -40,12 +42,16 @@ def employerNameChanged(self, text): trimmed = text.trimmed() - if trimmed in self.dataStore.employers.keys(): + if(trimmed == self.dataStore.NO_EMPLOYER or + trimmed == self.dataStore.NO_EMPLOYER_TRANSLATED): self.okButton.setEnabled(False) - #TODO: Show a tooltip explaining what happened + #TODO: Show a tooltip explaining those names are reserved + elif trimmed in self.dataStore.employers.keys(): + self.okButton.setEnabled(False) + #TODO: Show a tooltip explaining that employer already exists elif trimmed == '': self.okButton.setEnabled(False) - #TODO: Show a tooltip explaining what happened + #TODO: Show a tooltip explaining the user needs to write something else: self.okButton.setEnabled(True) @@ -53,11 +59,14 @@ name = self.employerNameBox.text().trimmed() desc = self.descriptionBox.toPlainText().trimmed() rate = self.hourlyRateSpinner.value() - self.dataStore.addEmployer(name, desc, rate) + self.dataStore.addEmployer(name, desc, rate) + """Set the boxes' text to the trimmed version, so calling classes can get + the correct new data""" + self.employerNameBox.setText(name) + self.descriptionBox.setText(desc) + QDialog.accept(self) - - class NewProjectDialog(QDialog, compiled_ui.Ui_newProjectDialog): ''' @@ -100,16 +109,20 @@ def __checkOkButtonState(self): text = self.projectNameBox.text().trimmed() if self.employerIndex == 0: - currentEmployer = DataStore.NO_EMPLOYER + currentEmployer = self.dataStore.NO_EMPLOYER else: currentEmployer = self.employerChoice.currentText() - + + if(text == self.dataStore.NO_PROJECT or + text == self.dataStore.NO_PROJECT_TRANSLATED): + self.okButton.setEnabled(False) + #TODO: Show a tooltip explaining those names are reserved if text in self.dataStore.employers[currentEmployer].projects.keys(): self.okButton.setEnabled(False) - #TODO: Show a tooltip explaining what happened + #TODO: Show a tooltip explaining the project name already exists for this employer elif text == '': self.okButton.setEnabled(False) - #TODO: Show a tooltip explaining what happened + #TODO: Show a tooltip explaining that the user needs to write something else: self.okButton.setEnabled(True) @@ -119,7 +132,7 @@ def accept(self): if self.employerChoice.currentIndex() == 0: - employerName = DataStore.NO_EMPLOYER + employerName = self.dataStore.NO_EMPLOYER else: employerName = self.employerChoice.currentText() @@ -136,10 +149,10 @@ def __populateEmployerBox(self, defaultItem = None): self.ignoreComboBoxChanges = True self.employerChoice.clear() - self.employerChoice.addItem(self.tr("None (personal project)")) + self.employerChoice.addItem(self.dataStore.NO_EMPLOYER_TRANSLATED) items = 1 for i in self.dataStore.employers.values(): - if i.name == DataStore.NO_EMPLOYER: + if i.name == self.dataStore.NO_EMPLOYER: continue self.employerChoice.addItem(i.name) if i.name == defaultItem: @@ -160,25 +173,23 @@ The work session start dialog ''' - def __init__(self, dataStore, project = None, employer = None): + def __init__(self, dataStore, employer = None, project = None): QDialog.__init__(self) self.setupUi(self) self.dataStore = dataStore self.currentEmployer = employer self.employerIndex = 0 self.projectIndex = 0 - self.__populateEmployerBox(employer) - self.__populateProjectBox(project) - + self.__populateEmployerBox(employer, project) def __populateEmployerBox( self, defaultEmployer = None, defaultProject = None): self.ignoreComboBoxChanges = True self.employerChoice.clear() - self.employerChoice.addItem(self.tr("None (personal project)")) + self.employerChoice.addItem(self.dataStore.NO_EMPLOYER_TRANSLATED) items = 1 for i in self.dataStore.employers.values(): - if i.name == DataStore.NO_EMPLOYER: + if i.name == self.dataStore.NO_EMPLOYER: continue self.employerChoice.addItem(i.name) if i.name == defaultEmployer: @@ -191,22 +202,22 @@ self.employerChoice.insertSeparator(items + 1) self.employerChoice.addItem(self.tr("New...")) self.projectIndex = 0 - self.__populateProjectBox(defaultProject) + self.__populateProjectBox(defaultProject) self.ignoreComboBoxChanges = False def __populateProjectBox(self, defaultItem = None): self.ignoreComboBoxChanges = True self.projectChoice.clear() - self.projectChoice.addItem(self.tr("Unsorted")) + self.projectChoice.addItem(self.dataStore.NO_PROJECT_TRANSLATED) items = 1 if self.employerIndex == 0: - employerName = DataStore.NO_EMPLOYER + employerName = self.dataStore.NO_EMPLOYER else: employerName = self.employerChoice.currentText() for i in self.dataStore.employers[employerName].projects.values(): - if i.name == DataStore.NO_PROJECT: + if i.name == self.dataStore.NO_PROJECT: continue self.projectChoice.addItem(i.name) if i.name == defaultItem: @@ -255,12 +266,12 @@ def accept(self): if self.employerIndex == 0: - employer = DataStore.NO_EMPLOYER + employer = self.dataStore.NO_EMPLOYER else: employer = self.employerChoice.currentText() if self.projectIndex == 0: - project = DataStore.NO_PROJECT + project = self.dataStore.NO_PROJECT else: project = self.projectChoice.currentText() @@ -299,38 +310,38 @@ def employerBoxChanged(self, index): if self.ignoreComboBoxChanges: return - if index == self.employerChoice.count() - 1: + """I don't think there's a use for creating new projects/employers + on a merely informational dialog""" + """if index == self.employerChoice.count() - 1: self.ignoreComboBoxChanges = True self.employerChoice.setCurrentIndex(self.employerIndex) employerDialog = NewEmployerDialog(self.dataStore) if employerDialog.exec_() == QDialog.Accepted: self.__populateEmployerBox(employerDialog.employerNameBox.text()) - self.ignoreComboBoxChanges = False - else: - self.employerIndex = index - self.__populateProjectBox() - self.__reloadItemModel() + self.ignoreComboBoxChanges = False""" + self.employerIndex = index + self.__populateProjectBox() + self.__reloadItemModel() def projectBoxChanged(self, index): if self.ignoreComboBoxChanges: return - if index == self.projectChoice.count() - 1: + """I don't think there's a use for creating new projects/employers + on a merely informational dialog""" + """if index == self.projectChoice.count() - 1: self.ignoreComboBoxChanges = True self.projectChoice.setCurrentIndex(self.projectIndex) projectDialog = NewProjectDialog(self.dataStore) result = projectDialog.exec_() - '''TODO: Reflect the other dialog's - selections in the combo boxes''' if projectDialog.createdEmployer: self.__populateEmployerBox() else: self.__populateProjectBox() - self.ignoreComboBoxChanges = False - else: - self.projectIndex = index - self.__reloadItemModel() + self.ignoreComboBoxChanges = False""" + self.projectIndex = index + self.__reloadItemModel() @@ -338,10 +349,10 @@ self, defaultEmployer = None, defaultProject = None): self.ignoreComboBoxChanges = True self.employerChoice.clear() - self.employerChoice.addItem(self.tr("None (personal project)")) + self.employerChoice.addItem(self.dataStore.NO_EMPLOYER_TRANSLATED) items = 1 for i in self.dataStore.employers.values(): - if i.name == DataStore.NO_EMPLOYER: + if i.name == self.dataStore.NO_EMPLOYER: continue self.employerChoice.addItem(i.name) if i.name == defaultEmployer: @@ -349,10 +360,12 @@ self.employerChoice.setCurrentIndex(items) items += 1 - if(items > 1): + """I don't think there's a use for creating new projects/employers + on a merely informational dialog""" + """if(items > 1): self.employerChoice.insertSeparator(1) self.employerChoice.insertSeparator(items + 1) - self.employerChoice.addItem(self.tr("New...")) + self.employerChoice.addItem(self.tr("New..."))""" self.projectIndex = 0 self.__populateProjectBox(defaultProject) self.ignoreComboBoxChanges = False @@ -360,15 +373,15 @@ def __populateProjectBox(self, defaultItem = None): self.ignoreComboBoxChanges = True self.projectChoice.clear() - self.projectChoice.addItem(self.tr("Unsorted")) + self.projectChoice.addItem(self.dataStore.NO_PROJECT_TRANSLATED) items = 1 if self.employerIndex == 0: - employerName = DataStore.NO_EMPLOYER + employerName = self.dataStore.NO_EMPLOYER else: employerName = self.employerChoice.currentText() for i in self.dataStore.employers[employerName].projects.values(): - if i.name == DataStore.NO_PROJECT: + if i.name == self.dataStore.NO_PROJECT: continue self.projectChoice.addItem(i.name) if i.name == defaultItem: @@ -376,21 +389,23 @@ self.projectChoice.setCurrentIndex(items) items += 1 - if(items > 1): + """I don't think there's a use for creating new projects/employers + on a merely informational dialog""" + """if(items > 1): self.projectChoice.insertSeparator(1) self.projectChoice.insertSeparator(items + 1) - self.projectChoice.addItem(self.tr("New...")) + self.projectChoice.addItem(self.tr("New..."))""" self.__reloadItemModel() self.ignoreComboBoxChanges = False def __reloadItemModel(self): if self.employerChoice.currentIndex() == 0: - employer = DataStore.NO_EMPLOYER + employer = self.dataStore.NO_EMPLOYER else: employer = self.employerChoice.currentText() if self.projectChoice.currentIndex() == 0: - project = DataStore.NO_PROJECT + project = self.dataStore.NO_PROJECT else: project = self.projectChoice.currentText() Modified: trunk/src/gui/main_window.py =================================================================== --- trunk/src/gui/main_window.py 2011-10-21 00:59:02 UTC (rev 45) +++ trunk/src/gui/main_window.py 2011-10-21 00:59:14 UTC (rev 46) @@ -24,6 +24,7 @@ ''' from compiled_ui import Ui_mainWindow +from workman import DataStore from PyQt4 import QtGui, QtCore @@ -31,6 +32,9 @@ ''' The application's main window ''' + + PROJECT_COLUMN = 0 # Indices for the project and employer columns + EMPLOYER_COLUMN = 1 def __init__(self, dataStore): @@ -83,8 +87,8 @@ '''Opens the start session dialog''' """TODO: Get the selected project by default on the dialog's combo box""" - - dialog = dialogs.StartSessionDialog(self.dataStore) + employer, project = self.__getSelectedProject() + dialog = dialogs.StartSessionDialog(self.dataStore, employer, project) if dialog.exec_() == QtGui.QDialog.Accepted: self.hide() self.__setStartButton(False) @@ -170,15 +174,44 @@ QtGui.qApp.quit() def iconActivated(self, reason): - if reason != QtGui.QSystemTrayIcon.Context: + if reason != QtGui.QSystemTrayIcon.Context: self.showOrHide() def showWindow(self): - self.show() + self.show() + + def __getSelectedProject(self): + '''Returns an (employer, project) tuple of the currently selected + row on the table''' + + # Note: these indexes refer to cells, not rows. + selected = self.projectList.selectedIndexes() + if(len(selected) == 0): + selectedEmployer = self.dataStore.NO_EMPLOYER + selectedProject = self.dataStore.NO_PROJECT + else: + row = selected[0].row() + employerName = str(selected[0].sibling( + row, self.EMPLOYER_COLUMN).data().toString()) + if(employerName == self.dataStore.NO_EMPLOYER or + employerName == self.dataStore.NO_EMPLOYER_TRANSLATED): + selectedEmployer = self.dataStore.NO_EMPLOYER + else: + selectedEmployer = employerName + projectName = str(selected[0].sibling( + row, self.PROJECT_COLUMN).data().toString()) + if(projectName == self.dataStore.NO_PROJECT or + projectName == self.dataStore.NO_PROJECT_TRANSLATED): + selectedProject = self.dataStore.NO_PROJECT + else: + selectedProject = projectName + + return (selectedEmployer, selectedProject) def createProject(self): '''Opens the new project dialog''' - dialog = dialogs.NewProjectDialog(self.dataStore) + selectedEmployer = self.__getSelectedProject()[0] + dialog = dialogs.NewProjectDialog(self.dataStore, selectedEmployer) if(dialog.exec_() == QtGui.QDialog.Accepted or dialog.createdEmployer): self.__reloadItemModel() Modified: trunk/src/workman.py =================================================================== --- trunk/src/workman.py 2011-10-21 00:59:02 UTC (rev 45) +++ trunk/src/workman.py 2011-10-21 00:59:14 UTC (rev 46) @@ -31,15 +31,22 @@ '''Where the program data is stored in memory''' NO_EMPLOYER = 'None' # Not to be translated (here) + NO_EMPLOYER_TRANSLATED = '' NO_EMPLOYER_DESCRIPTION = '' NO_PROJECT = 'None' # Not to be translated (here) - NO_PROJECT_DESCRIPTION = '' + NO_PROJECT_TRANSLATED = '' + NO_PROJECT_DESCRIPTION = '' def __init__(self, db): + #: Meaning this project is for no employer + DataStore.NO_EMPLOYER_TRANSLATED = QtGui.qApp.tr("None (personal project)") DataStore.NO_EMPLOYER_DESCRIPTION = QtGui.qApp.tr( - "For personal projects") + "For personal projects") + #: Refers to the fact that this isn't any particular project + DataStore.NO_PROJECT_TRANSLATED = QtGui.qApp.tr("Unsorted") DataStore.NO_PROJECT_DESCRIPTION = QtGui.qApp.tr("General work") + self.db = db self.projectItemModel = None if db is None: @@ -79,7 +86,8 @@ def startBreak(self, reason): assert(self.activeSession is not None and - self.activeBreak is None) + self.activeBreak is None) + #TODO: write data to a file for disaster recovery self.activeBreak = workman_types.Break( self.activeSession, reason) @@ -94,7 +102,7 @@ self.activeBreak = None def addEmployer(self, name, description, rate): - assert(name not in self.employers.keys() and + assert(name not in self.employers.keys() and name is not None and name != '' and rate >= 0) employer = workman_types.Employer(name, rate, description) @@ -120,15 +128,12 @@ def __newItemModelRow(self, employerName, projectName, projDesc, hoursWorked): if employerName == DataStore.NO_EMPLOYER: - modelEmployerName = self.projectItemModel.tr( - "None (personal project)") + modelEmployerName = DataStore.NO_EMPLOYER_TRANSLATED else: modelEmployerName = employerName if projectName == DataStore.NO_PROJECT: - modelProjectName = self.projectItemModel.tr( - "Unsorted") - modelDescription = self.projectItemModel.tr( - "General work") + modelProjectName = DataStore.NO_PROJECT_TRANSLATED + modelDescription = DataStore.NO_PROJECT_DESCRIPTION else: modelProjectName = projectName modelDescription = projDesc @@ -154,7 +159,9 @@ self.projectItemModel.appendRow( self.__newItemModelRow( i.name, j.name, j.description, self.__getHoursWorked(j))) - + + # TODO: Make sorting case-insensitive + return self.projectItemModel else: return self.projectItemModel @@ -253,19 +260,15 @@ return result - - - - if __name__ == '__main__': from gui.main_window import MainWindow from gui.wizard import Wizard app = QtGui.QApplication(sys.argv) app.setQuitOnLastWindowClosed(False) data = DataStore(None) + #TODO: Read a config file, create a database and show wizard if not found y = Wizard() y.exec_() x = MainWindow(data) x.show() sys.exit(app.exec_()) - This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jm...@us...> - 2011-10-21 00:59:09
|
Revision: 45 http://workman.svn.sourceforge.net/workman/?rev=45&view=rev Author: jmsilva Date: 2011-10-21 00:59:02 +0000 (Fri, 21 Oct 2011) Log Message: ----------- - Fixed project just created not becoming selected by default on the start session dialog - Fixed time worked display on the main window - Dates are now stored in UTC so there's no issues with daylight savings - Changed date and time displays to use the system's locale settings Stuff not yet relevant, since the DB code isn't called anywhere yet: - Added description to the exception raised when the DB could not be opened. - Made the DB code use the field's name instead of its order on the query. Modified Paths: -------------- trunk/src/db.py trunk/src/gui/dialogs.py trunk/src/gui/main_window.py trunk/src/workman.py trunk/src/workman_types.py Modified: trunk/src/db.py =================================================================== --- trunk/src/db.py 2011-10-21 00:58:48 UTC (rev 44) +++ trunk/src/db.py 2011-10-21 00:59:02 UTC (rev 45) @@ -45,7 +45,8 @@ self.db.setPassword(dbPassword) self.db.setConnectOptions(dbConnectOptions) if not self.db.open(): - raise RuntimeError() + raise RuntimeError('Unable to open database. dbType: %s, ' + 'dbName: %s, dbUsername: %s' % (dbType, dbName, dbUsername)) self.pendingQueries = {} self.lastQuery = 0 @@ -138,10 +139,10 @@ while query.next(): record = query.record() - sid = record.value(0) - startTime = record.value(1) - endTime = record.value(2) - desc = record.value(3) + sid = record.value('session_id') + startTime = record.value('session_start_time') + endTime = record.value('session_end_time') + desc = record.value('session_description') assert (sid.isValid() and startTime.isValid() and endTime.isValid() and desc.isValid()) sessionBreaks = self.__getBreaks(sid) @@ -161,12 +162,11 @@ result = [] while query.next(): record = query.record() - startTime = record.value(0) - endTime = record.value(1) - reason = record.value(2) - assert(startTime.isValid() and + startTime = record.value('break_start_time') + endTime = record.value('break_end_time') + reason = record.value('break_reason') + assert(startTime.isValid() and endTime.isValid() and reason.isValid()) result.append((startTime, endTime, reason)) - return result - + return result \ No newline at end of file Modified: trunk/src/gui/dialogs.py =================================================================== --- trunk/src/gui/dialogs.py 2011-10-21 00:58:48 UTC (rev 44) +++ trunk/src/gui/dialogs.py 2011-10-21 00:59:02 UTC (rev 45) @@ -65,16 +65,16 @@ ''' - def __init__(self, store): + def __init__(self, store, defaultEmployer): ''' Constructor ''' - QDialog.__init__(self) - self.dataStore = store + QDialog.__init__(self) + self.dataStore = store self.setupUi(self) self.employerIndex = 0 self.ignoreComboBoxChanges = False - self.__populateEmployerBox() + self.__populateEmployerBox(defaultEmployer) self.createdEmployer = False @@ -240,16 +240,16 @@ if index == self.projectChoice.count() - 1: self.ignoreComboBoxChanges = True self.projectChoice.setCurrentIndex(self.projectIndex) - projectDialog = NewProjectDialog(self.dataStore) + projectDialog = NewProjectDialog( + self.dataStore, self.employerChoice.currentText()) result = projectDialog.exec_() - - '''TODO: Reflect the other dialog's - selections in the combo boxes''' - if projectDialog.createdEmployer: - self.__populateEmployerBox() - else: - self.__populateProjectBox() - self.ignoreComboBoxChanges = False + if result == QDialog.Accepted: + if projectDialog.createdEmployer: + self.__populateEmployerBox(projectDialog.employerChoice.currentText()) + else: + self.__populateProjectBox( + projectDialog.projectNameBox.text().trimmed()) + self.ignoreComboBoxChanges = False else: self.projectIndex = index Modified: trunk/src/gui/main_window.py =================================================================== --- trunk/src/gui/main_window.py 2011-10-21 00:58:48 UTC (rev 44) +++ trunk/src/gui/main_window.py 2011-10-21 00:59:02 UTC (rev 45) @@ -25,7 +25,6 @@ from compiled_ui import Ui_mainWindow from PyQt4 import QtGui, QtCore -import time class MainWindow(Ui_mainWindow, QtGui.QMainWindow): @@ -93,7 +92,7 @@ self.trayIcon.showMessage(self.tr("Work session started"), self.tr("A work session has started.\n" "To stop working or to take a break, right click " - "this icon, and choose the appropriate option.")) + "this icon, and choose the appropriate option.")) Modified: trunk/src/workman.py =================================================================== --- trunk/src/workman.py 2011-10-21 00:58:48 UTC (rev 44) +++ trunk/src/workman.py 2011-10-21 00:59:02 UTC (rev 45) @@ -17,6 +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 PyQt4 import QtGui, QtCore +from PyQt4.Qt import Qt import sys import workman_types ''' @@ -58,7 +59,7 @@ self.activeSession is None) session = workman_types.Session( self.employers[employerName].projects[projectName], - QtCore.QDateTime.currentDateTime()) + QtCore.QDateTime.currentDateTimeUtc()) self.activeSession = session #TODO: write data to a file for disaster recovery @@ -69,7 +70,7 @@ if self.db is not None: return #TODO: write session and its breaks to database - endTime = QtCore.QDateTime.currentDateTime() + endTime = QtCore.QDateTime.currentDateTimeUtc() if self.activeBreak is not None: self.endBreak(endTime) self.activeSession.endTime = endTime @@ -87,7 +88,7 @@ assert(self.activeBreak is not None and self.activeSession is not None) if endTime is None: - self.activeBreak.endTime = QtCore.QDateTime.currentDateTime() + self.activeBreak.endTime = QtCore.QDateTime.currentDateTimeUtc() else: self.activeBreak.endTime = endTime self.activeBreak = None @@ -95,8 +96,7 @@ def addEmployer(self, name, description, rate): assert(name not in self.employers.keys() and name is not None and name != '' and rate >= 0) - - + employer = workman_types.Employer(name, rate, description) self.employers[employer.name] = employer self.addProject(DataStore.NO_PROJECT, @@ -115,10 +115,10 @@ if self.projectItemModel is not None: self.projectItemModel.appendRow( self.__newItemModelRow( - employerName, projectName, description)) + employerName, projectName, description, 0)) - def __newItemModelRow(self, employerName, projectName, projDesc): + def __newItemModelRow(self, employerName, projectName, projDesc, hoursWorked): if employerName == DataStore.NO_EMPLOYER: modelEmployerName = self.projectItemModel.tr( "None (personal project)") @@ -137,7 +137,7 @@ projectItem = QtGui.QStandardItem(modelProjectName) descriptionItem = QtGui.QStandardItem(modelDescription) timeWorkedItem = QtGui.QStandardItem( - self.projectItemModel.tr("Time worked goes here")) + self.projectItemModel.tr("%1 hours").arg(hoursWorked)) return [projectItem, employerItem, descriptionItem, timeWorkedItem] def getProjectItemModel(self): @@ -147,28 +147,66 @@ [self.projectItemModel.tr("Project"), self.projectItemModel.tr("Employer"), self.projectItemModel.tr("Description"), - self.projectItemModel.tr("Time worked")]) + self.projectItemModel.tr("Hours worked")]) for i in self.employers.values(): for j in i.projects.values(): self.projectItemModel.appendRow( self.__newItemModelRow( - i.name, j.name, j.description)) + i.name, j.name, j.description, self.__getHoursWorked(j))) return self.projectItemModel else: return self.projectItemModel + def __getHoursWorked(self, project): + """Returns the total time worked on a project, in seconds""" + result = 0 + # Get total number of seconds worked + for i in project.sessions: + result += self.__getSessionInfo(i)[0] + + # Calculate the number of hours and round 'em up + result = int(result / 3600.0 + 0.5) + + return result + + def __getSessionInfo(self, session): + """Returns a triplet of (total_time_worked, number_of_breaks, total_break_time)""" + assert session.startTime is not None + + timeWorked = numBreaks = breakTime = 0 + + if session.endTime is None: + timeWorked = session.startTime.secsTo( + QtCore.QDateTime.currentDateTimeUtc()) + else: + timeWorked = session.startTime.secsTo(session.endTime) + + for i in session.breaks: + assert i.startTime is not None + if i.endTime is None: + curBreakTime = i.startTime.secsTo( + QtCore.QDateTime.currentDateTimeUtc()) + else: + curBreakTime = i.startTime.secsTo(i.endTime) + + timeWorked -= curBreakTime + breakTime += curBreakTime + numBreaks += 1 + + return (timeWorked, numBreaks, breakTime) + + def __newSessionItemModelRow(self, startDate, endDate, timeWorked, numBreaks, breakTime, summary): - format = QtGui.qApp.tr("yyyy-MM-dd hh:mm:ss") - timeFormat = QtGui.qApp.tr("hh'h'mm'm'ss's'") - startDateItem = QtGui.QStandardItem(startDate.toString(format)) + dateFormat = timeFormat = Qt.SystemLocaleShortDate + startDateItem = QtGui.QStandardItem(startDate.toString(dateFormat)) if endDate is None: endDateItem = QtGui.QStandardItem(QtGui.qApp.tr("In progress")) else: - endDateItem = QtGui.QStandardItem(endDate.toString(format)) + endDateItem = QtGui.QStandardItem(endDate.toString(dateFormat)) baseTime = QtCore.QTime(0, 0) timeWorkedObject = baseTime.addSecs(timeWorked) @@ -203,30 +241,11 @@ project = self.employers[employer].projects[project] for i in project.sessions: - assert i.startTime is not None if i.startTime < startDate or i.startTime > endDate: continue - if i.endTime is None: - timeWorked = i.startTime.secsTo( - QtCore.QDateTime.currentDateTime()) - else: - timeWorked = i.startTime.secsTo(i.endTime) + timeWorked, numBreaks, breakTime = self.__getSessionInfo(i) - numBreaks = 0 - breakTime = 0 - for j in i.breaks: - assert j.startTime is not None - if j.endTime is None: - curBreakTime = j.startTime.secsTo( - QtCore.QDateTime.currentDateTime()) - else: - curBreakTime = j.startTime.secsTo(j.endTime) - - timeWorked -= curBreakTime - breakTime += curBreakTime - numBreaks += 1 - #TODO: Find out what's up with breaks having too much time row = self.__newSessionItemModelRow(i.startTime, i.endTime, timeWorked, numBreaks, breakTime, i.message) Modified: trunk/src/workman_types.py =================================================================== --- trunk/src/workman_types.py 2011-10-21 00:58:48 UTC (rev 44) +++ trunk/src/workman_types.py 2011-10-21 00:59:02 UTC (rev 45) @@ -58,7 +58,7 @@ employer.projects[self.name] = self class Session: - def __init__(self, project = None, startTime = QDateTime.currentDateTime(), + def __init__(self, project = None, startTime = QDateTime.currentDateTimeUtc(), endTime = None, message = '', breaks = None): #TODO: Handle timezone problems self.startTime = startTime @@ -79,7 +79,7 @@ class Break: def __init__(self, session = None, reason = '', - startTime = QDateTime.currentDateTime(), endTime = None): + startTime = QDateTime.currentDateTimeUtc(), endTime = None): #TODO: Handle timezone problems self.startTime = startTime self.endTime = endTime This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jm...@us...> - 2011-10-21 00:58:55
|
Revision: 44 http://workman.svn.sourceforge.net/workman/?rev=44&view=rev Author: jmsilva Date: 2011-10-21 00:58:48 +0000 (Fri, 21 Oct 2011) Log Message: ----------- - Stripped the employer/project strings of leading and trailing whitespace prior to adding them to the DataStore - Removed random whitespace Modified Paths: -------------- trunk/src/db.py trunk/src/gui/dialogs.py trunk/src/gui/main_window.py trunk/src/workman.py Added Paths: ----------- trunk/src/gui/build_ui.bat Modified: trunk/src/db.py =================================================================== --- trunk/src/db.py 2011-10-21 00:58:33 UTC (rev 43) +++ trunk/src/db.py 2011-10-21 00:58:48 UTC (rev 44) @@ -60,8 +60,8 @@ query.prepare('insert into employers(employer_name, ' 'employer_hourly_rate, employer_rate_start_date) values(' ':employer, :rate, datetime());') - query.addBindValue(employer) - query.addBindValue(rate) + query.bindValue(':employer', employer) + query.addBindValue(':rate', rate) return query.exec_() def insertSession(self, project, startDate, endDate, desc, breaks): @@ -76,10 +76,10 @@ query.prepare('Insert into sessions(project_name, ' 'project_description, employer_id) values(' ':project, :startDate, :endDate, :desc);') - query.addBindValue(project) - query.addBindValue(startDate) - query.addBindValue(endDate) - query.addBindValue(desc) + query.bindValue(':project', project) + query.bindValue(':startDate', startDate) + query.bindValue(':endDate', endDate) + query.bindValue(':desc', desc) return query.exec_() # TODO: Add limits to the queries @@ -129,7 +129,7 @@ query = QtSql.QSqlQuery(self.db) query.prepare('select session_id, session_start_time, session_end_time, ' 'session_description from sessions where project_id = :project;') - query.addBindValue(project) + query.bindValue(':project', project) status = query.exec_() if not status: return False @@ -153,7 +153,7 @@ query = QtSql.QSqlQuery(self.db) query.prepare('select break_start_time, break_end_time, ' 'break_reason from breaks where session_id = :session;') - query.addBindValue(session) + query.bindValue(':session', session) status = query.exec_() if not status: return False Added: trunk/src/gui/build_ui.bat =================================================================== --- trunk/src/gui/build_ui.bat (rev 0) +++ trunk/src/gui/build_ui.bat 2011-10-21 00:58:48 UTC (rev 44) @@ -0,0 +1,7 @@ +pyrcc4 res.qrc -o res_rc.py + +echo #!/usr/bin/python > compiled_ui.py +for %%i in ( *.ui ) do ( + C:\Python27\Lib\site-packages\PyQt4\pyuic4 %%i >> compiled_ui.py +) +done Modified: trunk/src/gui/dialogs.py =================================================================== --- trunk/src/gui/dialogs.py 2011-10-21 00:58:33 UTC (rev 43) +++ trunk/src/gui/dialogs.py 2011-10-21 00:58:48 UTC (rev 44) @@ -39,18 +39,19 @@ self.okButton.setEnabled(False) def employerNameChanged(self, text): - if text in self.dataStore.employers.keys(): + trimmed = text.trimmed() + if trimmed in self.dataStore.employers.keys(): self.okButton.setEnabled(False) #TODO: Show a tooltip explaining what happened - elif text == '': + elif trimmed == '': 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() + name = self.employerNameBox.text().trimmed() + desc = self.descriptionBox.toPlainText().trimmed() rate = self.hourlyRateSpinner.value() self.dataStore.addEmployer(name, desc, rate) @@ -97,7 +98,7 @@ self.__checkOkButtonState() def __checkOkButtonState(self): - text = self.projectNameBox.text() + text = self.projectNameBox.text().trimmed() if self.employerIndex == 0: currentEmployer = DataStore.NO_EMPLOYER else: @@ -120,10 +121,10 @@ if self.employerChoice.currentIndex() == 0: employerName = DataStore.NO_EMPLOYER else: - employerName = self.employerChoice.currentText() + employerName = self.employerChoice.currentText() - projectName = self.projectNameBox.text() - projectDescription = self.descriptionBox.toPlainText() + projectName = self.projectNameBox.text().trimmed() + projectDescription = self.descriptionBox.toPlainText().trimmed() self.dataStore.addProject( projectName, projectDescription, employerName) @@ -227,7 +228,7 @@ self.employerChoice.setCurrentIndex(self.employerIndex) employerDialog = NewEmployerDialog(self.dataStore) if employerDialog.exec_() == QDialog.Accepted: - self.__populateEmployerBox(employerDialog.employerNameBox.text()) + self.__populateEmployerBox(employerDialog.employerNameBox.text().trimmed()) self.ignoreComboBoxChanges = False else: self.employerIndex = index @@ -250,7 +251,7 @@ self.__populateProjectBox() self.ignoreComboBoxChanges = False else: - self.projectIndex = index + self.projectIndex = index def accept(self): if self.employerIndex == 0: Modified: trunk/src/gui/main_window.py =================================================================== --- trunk/src/gui/main_window.py 2011-10-21 00:58:33 UTC (rev 43) +++ trunk/src/gui/main_window.py 2011-10-21 00:58:48 UTC (rev 44) @@ -102,9 +102,9 @@ dialog = dialogs.EndSessionDialog(self.dataStore) if dialog.exec_() == QtGui.QDialog.Accepted: if self.dataStore.activeBreak is not None: - self.endBreak(False) + self.endBreak(False) - self.__setStartButton(True) + self.__setStartButton(True) self.trayIcon.setContextMenu(self.regularMenu) #TODO: Show some info about the session in the message text self.trayIcon.showMessage(self.tr("Work session ended"), @@ -121,10 +121,10 @@ #TODO: Break reasons self.dataStore.startBreak('') self.trayIcon.setContextMenu(self.breakMenu) - if showMessage: + if showMessage: self.trayIcon.showMessage(self.tr("Taking a break"), self.tr("Enjoy your break!\n" - "Right-click the menu and select 'Resume work' to " + "Right-click the menu and select 'Resume work' to " "continue working")) def endBreak(self): @@ -145,7 +145,7 @@ icon = QtGui.QMessageBox.Question activeSession = False if self.dataStore.activeSession is not None: - text = self.tr('A work session is in progress ' + + text = self.tr('A work session is in progress ' 'and will be ended if you choose to quit.\n\n') + text icon = QtGui.QMessageBox.Warning activeSession = True @@ -175,8 +175,7 @@ self.showOrHide() def showWindow(self): - self.show() - + self.show() def createProject(self): '''Opens the new project dialog''' @@ -204,8 +203,7 @@ QtCore.SIGNAL('clicked()'), self.startSession) self.connect(self.startSessionButton, QtCore.SIGNAL('clicked()'), self.endSession) - self.startSessionButton.setText(self.tr("&Stop working...")) - + self.startSessionButton.setText(self.tr("&Stop working...")) def __reloadItemModel(self): itemModel = self.dataStore.getProjectItemModel() Modified: trunk/src/workman.py =================================================================== --- trunk/src/workman.py 2011-10-21 00:58:33 UTC (rev 43) +++ trunk/src/workman.py 2011-10-21 00:58:48 UTC (rev 44) @@ -208,9 +208,8 @@ continue if i.endTime is None: - timeWorked = ( - i.startTime.secsTo( - QtCore.QDateTime.currentDateTime())) + timeWorked = i.startTime.secsTo( + QtCore.QDateTime.currentDateTime()) else: timeWorked = i.startTime.secsTo(i.endTime) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jm...@us...> - 2011-10-21 00:58:39
|
Revision: 43 http://workman.svn.sourceforge.net/workman/?rev=43&view=rev Author: jmsilva Date: 2011-10-21 00:58:33 +0000 (Fri, 21 Oct 2011) Log Message: ----------- Confirmation on quitting. Modified Paths: -------------- trunk/src/gui/main_window.py trunk/src/workman.py Modified: trunk/src/gui/main_window.py =================================================================== --- trunk/src/gui/main_window.py 2011-10-21 00:58:22 UTC (rev 42) +++ trunk/src/gui/main_window.py 2011-10-21 00:58:33 UTC (rev 43) @@ -25,6 +25,7 @@ from compiled_ui import Ui_mainWindow from PyQt4 import QtGui, QtCore +import time class MainWindow(Ui_mainWindow, QtGui.QMainWindow): @@ -109,9 +110,11 @@ self.trayIcon.showMessage(self.tr("Work session ended"), self.tr("The work session has ended.")) self.show() + return True else: self.trayIcon.showMessage(self.tr("End of session canceled"), self.tr("Time is still being tracked")) + return False def startBreak(self, showMessage = True): @@ -134,8 +137,38 @@ self.setVisible(not self.isVisible()) def quit(self): - #TODO confirmation - QtGui.qApp.exit() + """Displays a confirmation dialog and quits the program, + if the user so chooses""" + title = self.tr('Quitting Workman') + text = self.tr('Are you sure you want to quit?') + buttons = QtGui.QMessageBox.Yes | QtGui.QMessageBox.No + icon = QtGui.QMessageBox.Question + activeSession = False + if self.dataStore.activeSession is not None: + text = self.tr('A work session is in progress ' + + 'and will be ended if you choose to quit.\n\n') + text + icon = QtGui.QMessageBox.Warning + activeSession = True + + result = QtGui.QMessageBox(icon, title, text, buttons).exec_() + if result == QtGui.QMessageBox.Yes: + if activeSession: + if self.endSession() == False: + self.trayIcon.showMessage(self.tr("End of session canceled"), + self.tr("Time is still being tracked")) + else: + QtGui.qApp.closeAllWindows() + self.trayIcon.show() + self.trayIcon.showMessage(self.tr("Work session ended"), + self.tr("The work session has ended.\n Quitting...")) + self.trayIcon.setContextMenu(None) + self.trayIcon.disconnect(self.trayIcon, + QtCore.SIGNAL('activated(QSystemTrayIcon::ActivationReason)'), + self.iconActivated) + QUIT_TIMEOUT = 5000 # in ms + QtCore.QTimer.singleShot(QUIT_TIMEOUT, QtGui.qApp, QtCore.SLOT('quit()')) + else: + QtGui.qApp.quit() def iconActivated(self, reason): if reason != QtGui.QSystemTrayIcon.Context: Modified: trunk/src/workman.py =================================================================== --- trunk/src/workman.py 2011-10-21 00:58:22 UTC (rev 42) +++ trunk/src/workman.py 2011-10-21 00:58:33 UTC (rev 43) @@ -243,6 +243,7 @@ from gui.main_window import MainWindow from gui.wizard import Wizard app = QtGui.QApplication(sys.argv) + app.setQuitOnLastWindowClosed(False) data = DataStore(None) y = Wizard() y.exec_() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jm...@us...> - 2011-10-21 00:58:28
|
Revision: 42 http://workman.svn.sourceforge.net/workman/?rev=42&view=rev Author: jmsilva Date: 2011-10-21 00:58:22 +0000 (Fri, 21 Oct 2011) Log Message: ----------- Apparently, the Windows Python interpreter didn't execute QApplication's constructor, unless I saved the result into a variable. Modified Paths: -------------- trunk/src/workman.py Modified: trunk/src/workman.py =================================================================== --- trunk/src/workman.py 2011-10-21 00:58:11 UTC (rev 41) +++ trunk/src/workman.py 2011-10-21 00:58:22 UTC (rev 42) @@ -242,11 +242,11 @@ if __name__ == '__main__': from gui.main_window import MainWindow from gui.wizard import Wizard - QtGui.QApplication(sys.argv) + app = QtGui.QApplication(sys.argv) data = DataStore(None) y = Wizard() y.exec_() x = MainWindow(data) x.show() - sys.exit(QtGui.qApp.exec_()) + sys.exit(app.exec_()) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jm...@us...> - 2011-10-21 00:58:17
|
Revision: 41 http://workman.svn.sourceforge.net/workman/?rev=41&view=rev Author: jmsilva Date: 2011-10-21 00:58:11 +0000 (Fri, 21 Oct 2011) Log Message: ----------- Final version of the prototype Modified Paths: -------------- trunk/src/gui/end_session.ui trunk/src/gui/view_sessions.ui trunk/src/workman.py trunk/src/workman_types.py Modified: trunk/src/gui/end_session.ui =================================================================== --- trunk/src/gui/end_session.ui 2011-10-21 00:57:27 UTC (rev 40) +++ trunk/src/gui/end_session.ui 2011-10-21 00:58:11 UTC (rev 41) @@ -36,6 +36,9 @@ <property name="toolTip"> <string>A small summary of what you worked on</string> </property> + <property name="tabChangesFocus"> + <bool>true</bool> + </property> <property name="acceptRichText"> <bool>false</bool> </property> Modified: trunk/src/gui/view_sessions.ui =================================================================== --- trunk/src/gui/view_sessions.ui 2011-10-21 00:57:27 UTC (rev 40) +++ trunk/src/gui/view_sessions.ui 2011-10-21 00:58:11 UTC (rev 41) @@ -125,6 +125,9 @@ <property name="editTriggers"> <set>QAbstractItemView::NoEditTriggers</set> </property> + <property name="tabKeyNavigation"> + <bool>false</bool> + </property> <property name="alternatingRowColors"> <bool>true</bool> </property> @@ -154,11 +157,12 @@ </layout> </widget> <tabstops> + <tabstop>employerChoice</tabstop> <tabstop>projectChoice</tabstop> <tabstop>startDateWidget</tabstop> <tabstop>endDateWidget</tabstop> + <tabstop>sessionList</tabstop> <tabstop>closeButton</tabstop> - <tabstop>sessionList</tabstop> </tabstops> <resources> <include location="res.qrc"/> Modified: trunk/src/workman.py =================================================================== --- trunk/src/workman.py 2011-10-21 00:57:27 UTC (rev 40) +++ trunk/src/workman.py 2011-10-21 00:58:11 UTC (rev 41) @@ -80,7 +80,7 @@ assert(self.activeSession is not None and self.activeBreak is None) self.activeBreak = workman_types.Break( - self.activeSession, reason = reason) + self.activeSession, reason) def endBreak(self, endTime = None): #TODO: write data to a file for disaster recovery @@ -176,8 +176,8 @@ timeWorkedObject.toString(timeFormat)) numBreaksItem = QtGui.QStandardItem(repr(numBreaks)) - - breakTimeObject = baseTime.addSecs(breakTime) + baseTime2 = QtCore.QTime(0, 0) + breakTimeObject = baseTime2.addSecs(breakTime) breakTimeItem = QtGui.QStandardItem( breakTimeObject.toString(timeFormat)) @@ -191,7 +191,7 @@ project in self.employers[employer].projects.keys() and startDate <= endDate) - result = self.projectItemModel = QtGui.QStandardItemModel() + result = QtGui.QStandardItemModel() result.setHorizontalHeaderLabels( [result.tr("Start Time"), result.tr("End time"), @@ -216,7 +216,6 @@ numBreaks = 0 breakTime = 0 - print (timeWorked, breakTime) for j in i.breaks: assert j.startTime is not None if j.endTime is None: @@ -228,9 +227,8 @@ timeWorked -= curBreakTime breakTime += curBreakTime numBreaks += 1 - print (timeWorked, breakTime, curBreakTime) - + #TODO: Find out what's up with breaks having too much time row = self.__newSessionItemModelRow(i.startTime, i.endTime, timeWorked, numBreaks, breakTime, i.message) result.appendRow(row) @@ -251,4 +249,4 @@ x = MainWindow(data) x.show() sys.exit(QtGui.qApp.exec_()) - \ No newline at end of file + Modified: trunk/src/workman_types.py =================================================================== --- trunk/src/workman_types.py 2011-10-21 00:57:27 UTC (rev 40) +++ trunk/src/workman_types.py 2011-10-21 00:58:11 UTC (rev 41) @@ -63,7 +63,8 @@ #TODO: Handle timezone problems self.startTime = startTime self.endTime = endTime - self.setProject(project) + self.setProject(project) + self.message = message if breaks is None: self.breaks = [] else: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jm...@us...> - 2011-10-21 00:57:33
|
Revision: 40 http://workman.svn.sourceforge.net/workman/?rev=40&view=rev Author: jmsilva Date: 2011-10-21 00:57:27 +0000 (Fri, 21 Oct 2011) Log Message: ----------- Removed some no longer useful files Added Paths: ----------- trunk/icon.png Removed Paths: ------------- trunk/src/gui/workman2.ui trunk/src/types.py Added: trunk/icon.png =================================================================== (Binary files differ) Property changes on: trunk/icon.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Deleted: trunk/src/gui/workman2.ui =================================================================== --- trunk/src/gui/workman2.ui 2011-10-21 00:53:26 UTC (rev 39) +++ trunk/src/gui/workman2.ui 2011-10-21 00:57:27 UTC (rev 40) @@ -1,87 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>MainWindow</class> - <widget class="QMainWindow" name="MainWindow"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>720</width> - <height>246</height> - </rect> - </property> - <property name="windowTitle"> - <string>MainWindow</string> - </property> - <widget class="QWidget" name="centralwidget"> - <widget class="QWidget" name="horizontalLayoutWidget"> - <property name="geometry"> - <rect> - <x>10</x> - <y>10</y> - <width>701</width> - <height>231</height> - </rect> - </property> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <property name="spacing"> - <number>15</number> - </property> - <item> - <widget class="QListView" name="projectList"/> - </item> - <item> - <layout class="QVBoxLayout" name="verticalLayout"> - <property name="spacing"> - <number>10</number> - </property> - <item> - <widget class="QPushButton" name="startSessionButton"> - <property name="text"> - <string>Start working...</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="createProjectButton"> - <property name="text"> - <string>Create project...</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="viewSessionsButton"> - <property name="text"> - <string>View sessions...</string> - </property> - </widget> - </item> - <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="quitButton"> - <property name="text"> - <string>Quit</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - </widget> - </widget> - <resources/> - <connections/> -</ui> Deleted: trunk/src/types.py =================================================================== --- trunk/src/types.py 2011-10-21 00:53:26 UTC (rev 39) +++ trunk/src/types.py 2011-10-21 00:57:27 UTC (rev 40) @@ -1,89 +0,0 @@ -#!/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/>. - -''' - -Created on 2009/12/08 - -@author: João Miguel Ferreira da Silva -''' - -from datetime import datetime - -class Employer: - ''' - Specifies an employer - ''' - def __init__(self, name = '', rate = 0.0, - description = '', projects = None): - self.name = name - self.rate = rate - self.description = description - if projects is None: - self.projects = {} - else: - self.projects = projects - - -class Project: - def __init__(self, name = '', employer = None, description = '', sessions = None): - self.name = name - self.description = description - self.setEmployer(employer) - if sessions is None: - self.sessions = [] - else: - self.sessions = sessions - - - def setEmployer(self, employer): - self.employer = employer - if employer is not None: - employer.projects[self.name] = self - -class Session: - def __init__(self, project = None, startTime = datetime.now(), - endTime = None, message = '', breaks = None): - self.startTime = startTime - self.endTime = endTime - self.setProject(project) - if breaks is not None: - self.breaks = [] - else: - self.breaks = breaks - - def setProject(self, project): - self.project = project - if project is not None: - project.sessions.append(self) - - -class Break: - - def __init__(self, session = None, startTime = datetime.now(), - endTime = None, reason = ''): - self.startTime = startTime - self.endTime = endTime - self.reason = reason - self.setSession(session) - - def setSession(self, session): - self.session = session - if session is not None: - session.breaks.append(self) \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jm...@us...> - 2011-10-21 00:53:33
|
Revision: 39 http://workman.svn.sourceforge.net/workman/?rev=39&view=rev Author: jmsilva Date: 2011-10-21 00:53:26 +0000 (Fri, 21 Oct 2011) Log Message: ----------- - Can now view work sessions. Modified Paths: -------------- trunk/src/gui/dialogs.py trunk/src/gui/main_window.py trunk/src/gui/view_sessions.ui trunk/src/workman.py trunk/src/workman_types.py Modified: trunk/src/gui/dialogs.py =================================================================== --- trunk/src/gui/dialogs.py 2011-10-21 00:53:11 UTC (rev 38) +++ trunk/src/gui/dialogs.py 2011-10-21 00:53:26 UTC (rev 39) @@ -16,10 +16,10 @@ # # 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.QtGui import QDialog, QDialogButtonBox +from PyQt4.QtGui import QDialog, QDialogButtonBox, QWidget from gui import compiled_ui from workman import DataStore -from gui.compiled_ui import Ui_startSessionDialog, Ui_endSessionDialog +from gui.compiled_ui import Ui_startSessionDialog, Ui_endSessionDialog, Ui_viewSessionsDialog ''' Created on 2009/12/18 @@ -277,4 +277,125 @@ def accept(self): self.session = self.dataStore.activeSession self.dataStore.endSession(self.workSummary.toPlainText()) - QDialog.accept(self) \ No newline at end of file + QDialog.accept(self) + + + +class ViewSessionsDialog(QDialog, Ui_viewSessionsDialog): + + def __init__(self, dataStore): + QDialog.__init__(self) + self.setupUi(self) + self.dataStore = dataStore + self.ignoreComboBoxChanges = False + self.employerIndex = 0 + self.projectIndex = 0 + self.__populateEmployerBox() + + def dateBoxesChanged(self, index): + self.__reloadItemModel() + + def employerBoxChanged(self, index): + if self.ignoreComboBoxChanges: + return + if index == self.employerChoice.count() - 1: + self.ignoreComboBoxChanges = True + self.employerChoice.setCurrentIndex(self.employerIndex) + employerDialog = NewEmployerDialog(self.dataStore) + if employerDialog.exec_() == QDialog.Accepted: + self.__populateEmployerBox(employerDialog.employerNameBox.text()) + self.ignoreComboBoxChanges = False + else: + self.employerIndex = index + self.__populateProjectBox() + self.__reloadItemModel() + + + def projectBoxChanged(self, index): + if self.ignoreComboBoxChanges: + return + if index == self.projectChoice.count() - 1: + self.ignoreComboBoxChanges = True + self.projectChoice.setCurrentIndex(self.projectIndex) + projectDialog = NewProjectDialog(self.dataStore) + result = projectDialog.exec_() + + '''TODO: Reflect the other dialog's + selections in the combo boxes''' + if projectDialog.createdEmployer: + self.__populateEmployerBox() + else: + self.__populateProjectBox() + self.ignoreComboBoxChanges = False + else: + self.projectIndex = index + self.__reloadItemModel() + + + + def __populateEmployerBox( + self, defaultEmployer = None, defaultProject = 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: + continue + self.employerChoice.addItem(i.name) + if i.name == defaultEmployer: + self.employerIndex = 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.projectIndex = 0 + self.__populateProjectBox(defaultProject) + self.ignoreComboBoxChanges = False + + def __populateProjectBox(self, defaultItem = None): + self.ignoreComboBoxChanges = True + self.projectChoice.clear() + self.projectChoice.addItem(self.tr("Unsorted")) + items = 1 + if self.employerIndex == 0: + employerName = DataStore.NO_EMPLOYER + else: + employerName = self.employerChoice.currentText() + + for i in self.dataStore.employers[employerName].projects.values(): + if i.name == DataStore.NO_PROJECT: + continue + self.projectChoice.addItem(i.name) + if i.name == defaultItem: + self.projectIndex = items + self.projectChoice.setCurrentIndex(items) + items += 1 + + if(items > 1): + self.projectChoice.insertSeparator(1) + self.projectChoice.insertSeparator(items + 1) + self.projectChoice.addItem(self.tr("New...")) + self.__reloadItemModel() + self.ignoreComboBoxChanges = False + + def __reloadItemModel(self): + if self.employerChoice.currentIndex() == 0: + employer = DataStore.NO_EMPLOYER + else: + employer = self.employerChoice.currentText() + + if self.projectChoice.currentIndex() == 0: + project = DataStore.NO_PROJECT + else: + project = self.projectChoice.currentText() + + startDate = self.startDateWidget.dateTime() + endDate = self.endDateWidget.dateTime() + model = self.dataStore.getSessionItemModel( + employer, project, startDate, endDate) + + self.sessionList.setModel(model) \ No newline at end of file Modified: trunk/src/gui/main_window.py =================================================================== --- trunk/src/gui/main_window.py 2011-10-21 00:53:11 UTC (rev 38) +++ trunk/src/gui/main_window.py 2011-10-21 00:53:26 UTC (rev 39) @@ -59,10 +59,10 @@ self.sessionMenu.addAction(self.tr("&Show/Hide window"), self.showOrHide) self.sessionMenu.addSeparator() - self.sessionMenu.addAction(self.tr("&Stop working..."), - self.endSession) self.sessionMenu.addAction(self.tr("Take a &break"), self.startBreak) + self.sessionMenu.addAction(self.tr("&Stop working..."), + self.endSession) self.sessionMenu.addSeparator() self.sessionMenu.addAction(self.tr("&Quit"), self.quit) @@ -105,7 +105,7 @@ self.__setStartButton(True) self.trayIcon.setContextMenu(self.regularMenu) - #TODO: Show some info about the session in the text + #TODO: Show some info about the session in the message text self.trayIcon.showMessage(self.tr("Work session ended"), self.tr("The work session has ended.")) self.show() @@ -128,6 +128,7 @@ self.dataStore.endBreak() self.trayIcon.showMessage(self.tr("Ending your break"), self.tr("Break time's over. Resuming time tracking...")) + self.trayIcon.setContextMenu(self.sessionMenu) def showOrHide(self): self.setVisible(not self.isVisible()) @@ -153,8 +154,10 @@ def viewSessions(self): '''Opens the view sessions dialog''' - #TODO - pass + dialog = dialogs.ViewSessionsDialog(self.dataStore) + dialog.setModal(False) + dialog.show() + dialog.exec_() def __setStartButton(self, start): if start: Modified: trunk/src/gui/view_sessions.ui =================================================================== --- trunk/src/gui/view_sessions.ui 2011-10-21 00:53:11 UTC (rev 38) +++ trunk/src/gui/view_sessions.ui 2011-10-21 00:53:26 UTC (rev 39) @@ -1,17 +1,17 @@ <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> - <class>sessionsWindow</class> - <widget class="QDialog" name="sessionsWindow"> + <class>viewSessionsDialog</class> + <widget class="QDialog" name="viewSessionsDialog"> <property name="geometry"> <rect> <x>0</x> <y>0</y> - <width>389</width> + <width>647</width> <height>326</height> </rect> </property> <property name="windowTitle"> - <string/> + <string>View sessions</string> </property> <property name="windowIcon"> <iconset resource="res.qrc"> @@ -20,71 +20,85 @@ <property name="locale"> <locale language="English" country="UnitedStates"/> </property> - <layout class="QGridLayout" name="gridLayout" columnstretch="3,1,0"> + <layout class="QGridLayout" name="gridLayout" columnstretch="3,0,0"> <item row="0" column="0"> <layout class="QFormLayout" name="formLayout"> <property name="fieldGrowthPolicy"> <enum>QFormLayout::AllNonFixedFieldsGrow</enum> </property> - <item row="0" column="0"> + <item row="1" column="0"> <widget class="QLabel" name="label"> <property name="text"> <string>Project</string> </property> </widget> </item> - <item row="0" column="1"> - <widget class="QComboBox" name="projectChoice"> - <item> - <property name="text"> - <string>None (personal project)</string> - </property> - </item> - </widget> + <item row="1" column="1"> + <widget class="QComboBox" name="projectChoice"/> </item> - <item row="1" column="0"> + <item row="2" column="0"> <widget class="QLabel" name="label_2"> <property name="text"> <string>Starting date</string> </property> </widget> </item> - <item row="1" column="1"> + <item row="2" column="1"> <widget class="QDateEdit" name="startDateWidget"> + <property name="displayFormat"> + <string>yyyy/MM/dd</string> + </property> <property name="calendarPopup"> <bool>true</bool> </property> + <property name="date"> + <date> + <year>1900</year> + <month>1</month> + <day>1</day> + </date> + </property> </widget> </item> - <item row="2" column="0"> + <item row="3" column="0"> <widget class="QLabel" name="label_3"> <property name="text"> <string>Ending date</string> </property> </widget> </item> - <item row="2" column="1"> + <item row="3" column="1"> <widget class="QDateEdit" name="endDateWidget"> + <property name="displayFormat"> + <string>yyyy/MM/dd</string> + </property> <property name="calendarPopup"> <bool>true</bool> </property> + <property name="date"> + <date> + <year>2050</year> + <month>1</month> + <day>1</day> + </date> + </property> </widget> </item> + <item row="0" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Employer</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="employerChoice"/> + </item> </layout> </item> - <item row="2" column="0" colspan="3"> - <widget class="QListView" name="sessionList"/> - </item> <item row="0" column="1"> <layout class="QVBoxLayout" name="verticalLayout"> <item> - <widget class="QPushButton" name="searchButton"> - <property name="text"> - <string>&Search</string> - </property> - </widget> - </item> - <item> <widget class="QPushButton" name="closeButton"> <property name="text"> <string>&Close</string> @@ -106,13 +120,43 @@ </item> </layout> </item> + <item row="2" column="0" colspan="3"> + <widget class="QTableView" name="sessionList"> + <property name="editTriggers"> + <set>QAbstractItemView::NoEditTriggers</set> + </property> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="selectionMode"> + <enum>QAbstractItemView::SingleSelection</enum> + </property> + <property name="selectionBehavior"> + <enum>QAbstractItemView::SelectRows</enum> + </property> + <property name="showGrid"> + <bool>false</bool> + </property> + <property name="cornerButtonEnabled"> + <bool>false</bool> + </property> + <attribute name="horizontalHeaderHighlightSections"> + <bool>false</bool> + </attribute> + <attribute name="horizontalHeaderStretchLastSection"> + <bool>true</bool> + </attribute> + <attribute name="verticalHeaderVisible"> + <bool>false</bool> + </attribute> + </widget> + </item> </layout> </widget> <tabstops> <tabstop>projectChoice</tabstop> <tabstop>startDateWidget</tabstop> <tabstop>endDateWidget</tabstop> - <tabstop>searchButton</tabstop> <tabstop>closeButton</tabstop> <tabstop>sessionList</tabstop> </tabstops> @@ -123,12 +167,12 @@ <connection> <sender>closeButton</sender> <signal>clicked()</signal> - <receiver>sessionsWindow</receiver> + <receiver>viewSessionsDialog</receiver> <slot>close()</slot> <hints> <hint type="sourcelabel"> - <x>427</x> - <y>53</y> + <x>372</x> + <y>71</y> </hint> <hint type="destinationlabel"> <x>434</x> @@ -136,5 +180,74 @@ </hint> </hints> </connection> + <connection> + <sender>employerChoice</sender> + <signal>currentIndexChanged(int)</signal> + <receiver>viewSessionsDialog</receiver> + <slot>employerBoxChanged()</slot> + <hints> + <hint type="sourcelabel"> + <x>134</x> + <y>19</y> + </hint> + <hint type="destinationlabel"> + <x>0</x> + <y>21</y> + </hint> + </hints> + </connection> + <connection> + <sender>projectChoice</sender> + <signal>currentIndexChanged(int)</signal> + <receiver>viewSessionsDialog</receiver> + <slot>projectBoxChanged()</slot> + <hints> + <hint type="sourcelabel"> + <x>201</x> + <y>52</y> + </hint> + <hint type="destinationlabel"> + <x>84</x> + <y>48</y> + </hint> + </hints> + </connection> + <connection> + <sender>startDateWidget</sender> + <signal>dateChanged(QDate)</signal> + <receiver>viewSessionsDialog</receiver> + <slot>dateBoxesChanged()</slot> + <hints> + <hint type="sourcelabel"> + <x>171</x> + <y>88</y> + </hint> + <hint type="destinationlabel"> + <x>313</x> + <y>99</y> + </hint> + </hints> + </connection> + <connection> + <sender>endDateWidget</sender> + <signal>dateChanged(QDate)</signal> + <receiver>viewSessionsDialog</receiver> + <slot>dateBoxesChanged()</slot> + <hints> + <hint type="sourcelabel"> + <x>215</x> + <y>117</y> + </hint> + <hint type="destinationlabel"> + <x>300</x> + <y>116</y> + </hint> + </hints> + </connection> </connections> + <slots> + <slot>employerBoxChanged()</slot> + <slot>projectBoxChanged()</slot> + <slot>dateBoxesChanged()</slot> + </slots> </ui> Modified: trunk/src/workman.py =================================================================== --- trunk/src/workman.py 2011-10-21 00:53:11 UTC (rev 38) +++ trunk/src/workman.py 2011-10-21 00:53:26 UTC (rev 39) @@ -16,8 +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 datetime import datetime -from PyQt4 import QtGui +from PyQt4 import QtGui, QtCore import sys import workman_types ''' @@ -59,7 +58,7 @@ self.activeSession is None) session = workman_types.Session( self.employers[employerName].projects[projectName], - datetime.now()) + QtCore.QDateTime.currentDateTime()) self.activeSession = session #TODO: write data to a file for disaster recovery @@ -70,9 +69,10 @@ if self.db is not None: return #TODO: write session and its breaks to database + endTime = QtCore.QDateTime.currentDateTime() if self.activeBreak is not None: - self.endBreak() - self.activeSession.endTime = datetime.now() + self.endBreak(endTime) + self.activeSession.endTime = endTime self.activeSession.message = message self.activeSession = None @@ -82,11 +82,14 @@ self.activeBreak = workman_types.Break( self.activeSession, reason = reason) - def endBreak(self): + def endBreak(self, endTime = None): #TODO: write data to a file for disaster recovery assert(self.activeBreak is not None and - self.activeSession is not None) - self.activeBreak.endTime = datetime.now() + self.activeSession is not None) + if endTime is None: + self.activeBreak.endTime = QtCore.QDateTime.currentDateTime() + else: + self.activeBreak.endTime = endTime self.activeBreak = None def addEmployer(self, name, description, rate): @@ -156,7 +159,87 @@ else: return self.projectItemModel + def __newSessionItemModelRow(self, + startDate, endDate, timeWorked, + numBreaks, breakTime, summary): + format = QtGui.qApp.tr("yyyy-MM-dd hh:mm:ss") + timeFormat = QtGui.qApp.tr("hh'h'mm'm'ss's'") + startDateItem = QtGui.QStandardItem(startDate.toString(format)) + if endDate is None: + endDateItem = QtGui.QStandardItem(QtGui.qApp.tr("In progress")) + else: + endDateItem = QtGui.QStandardItem(endDate.toString(format)) + baseTime = QtCore.QTime(0, 0) + timeWorkedObject = baseTime.addSecs(timeWorked) + timeWorkedItem = QtGui.QStandardItem( + timeWorkedObject.toString(timeFormat)) + numBreaksItem = QtGui.QStandardItem(repr(numBreaks)) + + + breakTimeObject = baseTime.addSecs(breakTime) + breakTimeItem = QtGui.QStandardItem( + breakTimeObject.toString(timeFormat)) + + summaryItem = QtGui.QStandardItem(summary) + return( [startDateItem, endDateItem, timeWorkedItem, + numBreaksItem, breakTimeItem, summaryItem] ) + + + def getSessionItemModel(self, employer, project, startDate, endDate): + assert(employer in self.employers.keys() and + project in self.employers[employer].projects.keys() and + startDate <= endDate) + + result = self.projectItemModel = QtGui.QStandardItemModel() + result.setHorizontalHeaderLabels( + [result.tr("Start Time"), + result.tr("End time"), + result.tr("Time worked (excl. breaks)"), + result.tr("Number of breaks"), + result.tr("Break time"), + result.tr("Work summary")]) + + + project = self.employers[employer].projects[project] + for i in project.sessions: + assert i.startTime is not None + if i.startTime < startDate or i.startTime > endDate: + continue + + if i.endTime is None: + timeWorked = ( + i.startTime.secsTo( + QtCore.QDateTime.currentDateTime())) + else: + timeWorked = i.startTime.secsTo(i.endTime) + + numBreaks = 0 + breakTime = 0 + print (timeWorked, breakTime) + for j in i.breaks: + assert j.startTime is not None + if j.endTime is None: + curBreakTime = j.startTime.secsTo( + QtCore.QDateTime.currentDateTime()) + else: + curBreakTime = j.startTime.secsTo(j.endTime) + + timeWorked -= curBreakTime + breakTime += curBreakTime + numBreaks += 1 + print (timeWorked, breakTime, curBreakTime) + + + row = self.__newSessionItemModelRow(i.startTime, i.endTime, + timeWorked, numBreaks, breakTime, i.message) + result.appendRow(row) + + return result + + + + if __name__ == '__main__': from gui.main_window import MainWindow Modified: trunk/src/workman_types.py =================================================================== --- trunk/src/workman_types.py 2011-10-21 00:53:11 UTC (rev 38) +++ trunk/src/workman_types.py 2011-10-21 00:53:26 UTC (rev 39) @@ -24,7 +24,7 @@ @author: João Miguel Ferreira da Silva ''' -from datetime import datetime +from PyQt4.QtCore import QDateTime class Employer: ''' @@ -58,8 +58,9 @@ employer.projects[self.name] = self class Session: - def __init__(self, project = None, startTime = datetime.now(), + def __init__(self, project = None, startTime = QDateTime.currentDateTime(), endTime = None, message = '', breaks = None): + #TODO: Handle timezone problems self.startTime = startTime self.endTime = endTime self.setProject(project) @@ -77,7 +78,8 @@ class Break: def __init__(self, session = None, reason = '', - startTime = datetime.now(), endTime = None): + startTime = QDateTime.currentDateTime(), endTime = None): + #TODO: Handle timezone problems self.startTime = startTime self.endTime = endTime self.reason = reason This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jm...@us...> - 2011-10-21 00:53:18
|
Revision: 38 http://workman.svn.sourceforge.net/workman/?rev=38&view=rev Author: jmsilva Date: 2011-10-21 00:53:11 +0000 (Fri, 21 Oct 2011) Log Message: ----------- - Tab order fixes - Dummy wizard - Dummy time worked in main window Modified Paths: -------------- trunk/src/gui/main_window.py trunk/src/gui/new_project.ui trunk/src/gui/start_session.ui trunk/src/gui/wizard.ui trunk/src/workman.py Added Paths: ----------- trunk/src/gui/wizard.py Modified: trunk/src/gui/main_window.py =================================================================== --- trunk/src/gui/main_window.py 2011-10-21 00:52:55 UTC (rev 37) +++ trunk/src/gui/main_window.py 2011-10-21 00:53:11 UTC (rev 38) @@ -106,9 +106,12 @@ self.__setStartButton(True) self.trayIcon.setContextMenu(self.regularMenu) #TODO: Show some info about the session in the text - self.trayIcon.showMessage(self.tr("Work session ended."), - self.tr("The work session has ended")) + self.trayIcon.showMessage(self.tr("Work session ended"), + self.tr("The work session has ended.")) self.show() + else: + self.trayIcon.showMessage(self.tr("End of session canceled"), + self.tr("Time is still being tracked")) def startBreak(self, showMessage = True): Modified: trunk/src/gui/new_project.ui =================================================================== --- trunk/src/gui/new_project.ui 2011-10-21 00:52:55 UTC (rev 37) +++ trunk/src/gui/new_project.ui 2011-10-21 00:53:11 UTC (rev 38) @@ -23,28 +23,28 @@ <layout class="QVBoxLayout" name="verticalLayout"> <item> <layout class="QFormLayout" name="formLayout"> - <item row="1" column="0"> + <item row="2" column="0"> <widget class="QLabel" name="label"> <property name="text"> <string>Project name</string> </property> </widget> </item> - <item row="1" column="1"> + <item row="2" column="1"> <widget class="QLineEdit" name="projectNameBox"> <property name="toolTip"> <string>Enter the project's name here</string> </property> </widget> </item> - <item row="2" column="0"> + <item row="3" column="0"> <widget class="QLabel" name="label_3"> <property name="text"> <string>Project description</string> </property> </widget> </item> - <item row="2" column="1"> + <item row="3" column="1"> <widget class="QTextEdit" name="descriptionBox"> <property name="toolTip"> <string>Enter an optional description for this project</string> @@ -57,14 +57,14 @@ </property> </widget> </item> - <item row="3" column="0"> + <item row="1" column="0"> <widget class="QLabel" name="label_2"> <property name="text"> <string>Employer</string> </property> </widget> </item> - <item row="3" column="1"> + <item row="1" column="1"> <widget class="QComboBox" name="employerChoice"> <property name="toolTip"> <string>The employer you are working for</string> @@ -86,9 +86,9 @@ </layout> </widget> <tabstops> + <tabstop>employerChoice</tabstop> <tabstop>projectNameBox</tabstop> <tabstop>descriptionBox</tabstop> - <tabstop>employerChoice</tabstop> <tabstop>buttonBox</tabstop> </tabstops> <resources> Modified: trunk/src/gui/start_session.ui =================================================================== --- trunk/src/gui/start_session.ui 2011-10-21 00:52:55 UTC (rev 37) +++ trunk/src/gui/start_session.ui 2011-10-21 00:53:11 UTC (rev 38) @@ -156,6 +156,15 @@ </item> </layout> </widget> + <tabstops> + <tabstop>employerChoice</tabstop> + <tabstop>projectChoice</tabstop> + <tabstop>fixedTimeButton</tabstop> + <tabstop>sessionEndTime</tabstop> + <tabstop>fixedWorkButton</tabstop> + <tabstop>timeEdit</tabstop> + <tabstop>buttonBox</tabstop> + </tabstops> <resources> <include location="res.qrc"/> </resources> Added: trunk/src/gui/wizard.py =================================================================== --- trunk/src/gui/wizard.py (rev 0) +++ trunk/src/gui/wizard.py 2011-10-21 00:53:11 UTC (rev 38) @@ -0,0 +1,65 @@ +#!/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, QtCore +from gui.compiled_ui import Ui_Wizard +''' +Created on 2009/12/21 + +@author: João Miguel Ferreira da Silva +''' +class WizardStartPage(QtGui.QWizardPage): + def __init__(self): + QtGui.QWizardPage.__init__(self) + + + def nextId(self): + button = self.findChild( + QtGui.QRadioButton, 'projectNoButton') + + if button.isChecked(): + return -1 + + return 1 + + def raiseCompleteChanged(self): + button = self.findChild( + QtGui.QRadioButton, 'projectNoButton') + if button.isChecked(): + self.setFinalPage(True) + else: + self.setFinalPage(False) + self.emit(QtCore.SIGNAL('completeChanged()')) + + + + + +class Wizard(QtGui.QWizard, Ui_Wizard): + + def __init__(self): + QtGui.QWizard.__init__(self) + self.setupUi(self) + + + + +if __name__ == '__main__': + import sys + QtGui.QApplication(sys.argv) + Wizard().exec_() \ No newline at end of file Modified: trunk/src/gui/wizard.ui =================================================================== --- trunk/src/gui/wizard.ui 2011-10-21 00:52:55 UTC (rev 37) +++ trunk/src/gui/wizard.ui 2011-10-21 00:53:11 UTC (rev 38) @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>508</width> - <height>314</height> + <height>397</height> </rect> </property> <property name="windowTitle"> @@ -20,7 +20,7 @@ <property name="locale"> <locale language="English" country="UnitedStates"/> </property> - <widget class="QWizardPage" name="startPage"> + <widget class="WizardStartPage" name="startPage"> <property name="title"> <string>Welcome</string> </property> @@ -105,20 +105,19 @@ </item> <item row="0" column="1"> <widget class="QLineEdit" name="projectNameBox"> + <property name="enabled"> + <bool>false</bool> + </property> <property name="toolTip"> <string>The name of the project you want to create</string> </property> </widget> </item> - <item row="1" column="0"> - <widget class="QLabel" name="employerLabel"> - <property name="text"> - <string>Employer</string> + <item row="2" column="1"> + <widget class="QComboBox" name="employerChoice"> + <property name="enabled"> + <bool>false</bool> </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QComboBox" name="employerChoice"> <property name="toolTip"> <string>The employer for this project</string> </property> @@ -134,6 +133,27 @@ </item> </widget> </item> + <item row="1" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Description</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QTextEdit" name="textEdit"> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="employerLabel"> + <property name="text"> + <string>Employer</string> + </property> + </widget> + </item> </layout> </item> <item> @@ -147,7 +167,10 @@ </widget> </item> <item> - <widget class="QRadioButton" name="radioButton"> + <widget class="QRadioButton" name="sessionYesButton"> + <property name="enabled"> + <bool>false</bool> + </property> <property name="text"> <string>&Yes</string> </property> @@ -157,7 +180,10 @@ </widget> </item> <item> - <widget class="QRadioButton" name="radioButton_2"> + <widget class="QRadioButton" name="sessionNoButton"> + <property name="enabled"> + <bool>false</bool> + </property> <property name="text"> <string>&No</string> </property> @@ -184,8 +210,61 @@ </layout> </widget> </widget> + <customwidgets> + <customwidget> + <class>WizardStartPage</class> + <extends>QWizardPage</extends> + <header>wizard.h</header> + <container>1</container> + <slots> + <slot>raiseCompleteChanged()</slot> + </slots> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>projectYesButton</tabstop> + <tabstop>projectNoButton</tabstop> + <tabstop>projectNameBox</tabstop> + <tabstop>textEdit</tabstop> + <tabstop>employerChoice</tabstop> + <tabstop>sessionYesButton</tabstop> + <tabstop>sessionNoButton</tabstop> + </tabstops> <resources> <include location="res.qrc"/> </resources> - <connections/> + <connections> + <connection> + <sender>projectNoButton</sender> + <signal>clicked()</signal> + <receiver>startPage</receiver> + <slot>raiseCompleteChanged()</slot> + <hints> + <hint type="sourcelabel"> + <x>63</x> + <y>211</y> + </hint> + <hint type="destinationlabel"> + <x>82</x> + <y>301</y> + </hint> + </hints> + </connection> + <connection> + <sender>projectYesButton</sender> + <signal>clicked()</signal> + <receiver>startPage</receiver> + <slot>raiseCompleteChanged()</slot> + <hints> + <hint type="sourcelabel"> + <x>138</x> + <y>179</y> + </hint> + <hint type="destinationlabel"> + <x>198</x> + <y>266</y> + </hint> + </hints> + </connection> + </connections> </ui> Modified: trunk/src/workman.py =================================================================== --- trunk/src/workman.py 2011-10-21 00:52:55 UTC (rev 37) +++ trunk/src/workman.py 2011-10-21 00:53:11 UTC (rev 38) @@ -133,23 +133,24 @@ employerItem = QtGui.QStandardItem(modelEmployerName) projectItem = QtGui.QStandardItem(modelProjectName) descriptionItem = QtGui.QStandardItem(modelDescription) - return [projectItem, employerItem, descriptionItem] + timeWorkedItem = QtGui.QStandardItem( + self.projectItemModel.tr("Time worked goes here")) + return [projectItem, employerItem, descriptionItem, timeWorkedItem] def getProjectItemModel(self): if self.projectItemModel is None: self.projectItemModel = QtGui.QStandardItemModel() self.projectItemModel.setHorizontalHeaderLabels( [self.projectItemModel.tr("Project"), - self.projectItemModel.tr("Employer"), - self.projectItemModel.tr("Description")]) + self.projectItemModel.tr("Employer"), + self.projectItemModel.tr("Description"), + self.projectItemModel.tr("Time worked")]) - for i in self.employers.values(): for j in i.projects.values(): self.projectItemModel.appendRow( self.__newItemModelRow( - i.name, j.name, j.description)) - + i.name, j.name, j.description)) return self.projectItemModel else: @@ -159,8 +160,11 @@ if __name__ == '__main__': from gui.main_window import MainWindow + from gui.wizard import Wizard QtGui.QApplication(sys.argv) - data = DataStore(None) + data = DataStore(None) + y = Wizard() + y.exec_() x = MainWindow(data) x.show() sys.exit(QtGui.qApp.exec_()) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jm...@us...> - 2011-10-21 00:53:02
|
Revision: 37 http://workman.svn.sourceforge.net/workman/?rev=37&view=rev Author: jmsilva Date: 2011-10-21 00:52:55 +0000 (Fri, 21 Oct 2011) Log Message: ----------- - Committed gui.__init__ module, which I forgot. - Got some work session management going. Modified Paths: -------------- trunk/src/gui/build_ui.sh trunk/src/gui/dialogs.py trunk/src/gui/end_session.ui trunk/src/gui/main_window.py trunk/src/gui/new_employer.ui trunk/src/gui/new_project.ui trunk/src/gui/start_session.ui trunk/src/gui/view_sessions.ui trunk/src/gui/wizard.ui trunk/src/gui/workman.ui trunk/src/workman.py trunk/src/workman_types.py Added Paths: ----------- trunk/src/gui/__init__.py trunk/src/gui/res.qrc Added: trunk/src/gui/__init__.py =================================================================== --- trunk/src/gui/__init__.py (rev 0) +++ trunk/src/gui/__init__.py 2011-10-21 00:52:55 UTC (rev 37) @@ -0,0 +1,5 @@ +''' +Created on 2009/12/21 + +@author: jms +''' Modified: trunk/src/gui/build_ui.sh =================================================================== --- trunk/src/gui/build_ui.sh 2011-10-21 00:52:27 UTC (rev 36) +++ trunk/src/gui/build_ui.sh 2011-10-21 00:52:55 UTC (rev 37) @@ -1,3 +1,5 @@ +pyrcc4 res.qrc -o res_rc.py + echo \#\!/usr/bin/python > compiled_ui.py for i in *.ui ; do pyuic4 $i >> compiled_ui.py && true Modified: trunk/src/gui/dialogs.py =================================================================== --- trunk/src/gui/dialogs.py 2011-10-21 00:52:27 UTC (rev 36) +++ trunk/src/gui/dialogs.py 2011-10-21 00:52:55 UTC (rev 37) @@ -16,26 +16,26 @@ # # 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 PyQt4.QtGui import QDialog, QDialogButtonBox from gui import compiled_ui from workman import DataStore -import workman_types +from gui.compiled_ui import Ui_startSessionDialog, Ui_endSessionDialog ''' Created on 2009/12/18 @author: jms ''' -class NewEmployerDialog(QtGui.QDialog, compiled_ui.Ui_newEmployerDialog): +class NewEmployerDialog(QDialog, compiled_ui.Ui_newEmployerDialog): ''' The dialog used to create employers. ''' def __init__(self, store): - QtGui.QDialog.__init__(self) + QDialog.__init__(self) self.dataStore = store self.setupUi(self) - self.okButton = self.buttonBox.button(QtGui.QDialogButtonBox.Ok) + self.okButton = self.buttonBox.button(QDialogButtonBox.Ok) self.okButton.setEnabled(False) def employerNameChanged(self, text): @@ -54,11 +54,11 @@ rate = self.hourlyRateSpinner.value() self.dataStore.addEmployer(name, desc, rate) - QtGui.QDialog.accept(self) + QDialog.accept(self) -class NewProjectDialog(QtGui.QDialog, compiled_ui.Ui_newProjectDialog): +class NewProjectDialog(QDialog, compiled_ui.Ui_newProjectDialog): ''' The dialog used to create projects. ''' @@ -68,15 +68,16 @@ ''' Constructor ''' - QtGui.QDialog.__init__(self) + QDialog.__init__(self) self.dataStore = store self.setupUi(self) - self.comboBoxIndex = 0 - self.ignoreComboBoxChanges = False - self.__populateEmployerBox() - + self.employerIndex = 0 + self.ignoreComboBoxChanges = False + self.__populateEmployerBox() - self.okButton = self.buttonBox.button(QtGui.QDialogButtonBox.Ok) + self.createdEmployer = False + + self.okButton = self.buttonBox.button(QDialogButtonBox.Ok) self.okButton.setEnabled(False) def comboIndexChanged(self, index): @@ -84,19 +85,20 @@ return if index == self.employerChoice.count() - 1: self.ignoreComboBoxChanges = True - self.employerChoice.setCurrentIndex(self.comboBoxIndex) + self.employerChoice.setCurrentIndex(self.employerIndex) employerDialog = NewEmployerDialog(self.dataStore) employerDialog.setModal(True) - if employerDialog.exec_() == QtGui.QDialog.Accepted: + if employerDialog.exec_() == QDialog.Accepted: self.__populateEmployerBox(employerDialog.employerNameBox.text()) + self.createdEmployer = True self.ignoreComboBoxChanges = False else: - self.comboBoxIndex = index + self.employerIndex = index self.__checkOkButtonState() def __checkOkButtonState(self): text = self.projectNameBox.text() - if self.comboBoxIndex == 0: + if self.employerIndex == 0: currentEmployer = DataStore.NO_EMPLOYER else: currentEmployer = self.employerChoice.currentText() @@ -126,25 +128,153 @@ self.dataStore.addProject( projectName, projectDescription, employerName) - QtGui.QDialog.accept(self) + QDialog.accept(self) def __populateEmployerBox(self, defaultItem = None): self.ignoreComboBoxChanges = True self.employerChoice.clear() - self.employerChoice.addItem(self.tr('None (personal project)')) + 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 i.name == DataStore.NO_EMPLOYER: + continue + self.employerChoice.addItem(i.name) + if i.name == defaultItem: + self.employerIndex = 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.employerChoice.addItem(self.tr("New...")) self.ignoreComboBoxChanges = False + + + +class StartSessionDialog(QDialog, Ui_startSessionDialog): + ''' + The work session start dialog + ''' + + def __init__(self, dataStore, project = None, employer = None): + QDialog.__init__(self) + self.setupUi(self) + self.dataStore = dataStore + self.currentEmployer = employer + self.employerIndex = 0 + self.projectIndex = 0 + self.__populateEmployerBox(employer) + self.__populateProjectBox(project) + + + def __populateEmployerBox( + self, defaultEmployer = None, defaultProject = 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: + continue + self.employerChoice.addItem(i.name) + if i.name == defaultEmployer: + self.employerIndex = 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.projectIndex = 0 + self.__populateProjectBox(defaultProject) + self.ignoreComboBoxChanges = False + + + def __populateProjectBox(self, defaultItem = None): + self.ignoreComboBoxChanges = True + self.projectChoice.clear() + self.projectChoice.addItem(self.tr("Unsorted")) + items = 1 + if self.employerIndex == 0: + employerName = DataStore.NO_EMPLOYER + else: + employerName = self.employerChoice.currentText() + + for i in self.dataStore.employers[employerName].projects.values(): + if i.name == DataStore.NO_PROJECT: + continue + self.projectChoice.addItem(i.name) + if i.name == defaultItem: + self.projectIndex = items + self.projectChoice.setCurrentIndex(items) + items += 1 + + if(items > 1): + self.projectChoice.insertSeparator(1) + self.projectChoice.insertSeparator(items + 1) + self.projectChoice.addItem(self.tr("New...")) + self.ignoreComboBoxChanges = False + + def employerBoxChanged(self, index): + if self.ignoreComboBoxChanges: + return + if index == self.employerChoice.count() - 1: + self.ignoreComboBoxChanges = True + self.employerChoice.setCurrentIndex(self.employerIndex) + employerDialog = NewEmployerDialog(self.dataStore) + if employerDialog.exec_() == QDialog.Accepted: + self.__populateEmployerBox(employerDialog.employerNameBox.text()) + self.ignoreComboBoxChanges = False + else: + self.employerIndex = index + self.__populateProjectBox() + + def projectBoxChanged(self, index): + if self.ignoreComboBoxChanges: + return + if index == self.projectChoice.count() - 1: + self.ignoreComboBoxChanges = True + self.projectChoice.setCurrentIndex(self.projectIndex) + projectDialog = NewProjectDialog(self.dataStore) + result = projectDialog.exec_() + + '''TODO: Reflect the other dialog's + selections in the combo boxes''' + if projectDialog.createdEmployer: + self.__populateEmployerBox() + else: + self.__populateProjectBox() + self.ignoreComboBoxChanges = False + else: + self.projectIndex = index + + def accept(self): + if self.employerIndex == 0: + employer = DataStore.NO_EMPLOYER + else: + employer = self.employerChoice.currentText() + + if self.projectIndex == 0: + project = DataStore.NO_PROJECT + else: + project = self.projectChoice.currentText() + + self.dataStore.startSession(employer, project) + QDialog.accept(self) + + +class EndSessionDialog(QDialog, Ui_endSessionDialog): + + def __init__(self, dataStore): + QDialog.__init__(self) + self.setupUi(self) + self.dataStore = dataStore + + def accept(self): + self.session = self.dataStore.activeSession + self.dataStore.endSession(self.workSummary.toPlainText()) + QDialog.accept(self) \ No newline at end of file Modified: trunk/src/gui/end_session.ui =================================================================== --- trunk/src/gui/end_session.ui 2011-10-21 00:52:27 UTC (rev 36) +++ trunk/src/gui/end_session.ui 2011-10-21 00:52:55 UTC (rev 37) @@ -13,6 +13,10 @@ <property name="windowTitle"> <string>End session</string> </property> + <property name="windowIcon"> + <iconset resource="res.qrc"> + <normaloff>:/icon/icon.png</normaloff>:/icon/icon.png</iconset> + </property> <property name="locale"> <locale language="English" country="UnitedStates"/> </property> @@ -49,7 +53,9 @@ </item> </layout> </widget> - <resources/> + <resources> + <include location="res.qrc"/> + </resources> <connections> <connection> <sender>confirmationBox</sender> Modified: trunk/src/gui/main_window.py =================================================================== --- trunk/src/gui/main_window.py 2011-10-21 00:52:27 UTC (rev 36) +++ trunk/src/gui/main_window.py 2011-10-21 00:52:55 UTC (rev 37) @@ -16,7 +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 +import dialogs ''' Created on 2009/12/17 @@ -40,27 +40,133 @@ QtGui.QMainWindow.__init__(self) self.setupUi(self) self.dataStore = dataStore + self.projectList.horizontalHeader().setStretchLastSection(True) + self.trayIcon = QtGui.QSystemTrayIcon(self.windowIcon()) + self.trayIcon.connect(self.trayIcon, + QtCore.SIGNAL('activated(QSystemTrayIcon::ActivationReason)'), + self.iconActivated) + self.trayIcon.show() + + self.regularMenu = QtGui.QMenu() + self.regularMenu.addAction(self.tr("&Show/Hide window"), + self.showOrHide) + self.regularMenu.addSeparator() + self.regularMenu.addAction(self.tr("&Quit"), self.quit) + + self.trayIcon.setContextMenu(self.regularMenu) + + self.sessionMenu = QtGui.QMenu() + self.sessionMenu.addAction(self.tr("&Show/Hide window"), + self.showOrHide) + self.sessionMenu.addSeparator() + self.sessionMenu.addAction(self.tr("&Stop working..."), + self.endSession) + self.sessionMenu.addAction(self.tr("Take a &break"), + self.startBreak) + self.sessionMenu.addSeparator() + self.sessionMenu.addAction(self.tr("&Quit"), + self.quit) + self.breakMenu = QtGui.QMenu() + self.breakMenu.addAction(self.tr("&Show/Hide window"), + self.showOrHide) + self.breakMenu.addSeparator() + self.breakMenu.addAction(self.tr("&Resume work"), self.endBreak) + self.breakMenu.addAction(self.tr("Stop &working..."), self.endSession) + self.breakMenu.addSeparator() + self.breakMenu.addAction(self.tr("&Quit"), self.quit) + self.__reloadItemModel() - self.connect(self.quitButton, QtCore.SIGNAL('clicked()'), - QtGui.qApp, QtCore.SLOT('quit()')) + self.connect(self.quitButton, + QtCore.SIGNAL('clicked()'), self.quit) def startSession(self): '''Opens the start session dialog''' - #TODO - pass + """TODO: Get the selected project by default on the + dialog's combo box""" + + dialog = dialogs.StartSessionDialog(self.dataStore) + if dialog.exec_() == QtGui.QDialog.Accepted: + self.hide() + self.__setStartButton(False) + self.trayIcon.setContextMenu(self.sessionMenu) + self.trayIcon.showMessage(self.tr("Work session started"), + self.tr("A work session has started.\n" + "To stop working or to take a break, right click " + "this icon, and choose the appropriate option.")) + + + + def endSession(self): + dialog = dialogs.EndSessionDialog(self.dataStore) + if dialog.exec_() == QtGui.QDialog.Accepted: + if self.dataStore.activeBreak is not None: + self.endBreak(False) + + self.__setStartButton(True) + self.trayIcon.setContextMenu(self.regularMenu) + #TODO: Show some info about the session in the text + self.trayIcon.showMessage(self.tr("Work session ended."), + self.tr("The work session has ended")) + self.show() + + + def startBreak(self, showMessage = True): + #TODO: Break reasons + self.dataStore.startBreak('') + self.trayIcon.setContextMenu(self.breakMenu) + if showMessage: + self.trayIcon.showMessage(self.tr("Taking a break"), + self.tr("Enjoy your break!\n" + "Right-click the menu and select 'Resume work' to " + "continue working")) + + def endBreak(self): + self.dataStore.endBreak() + self.trayIcon.showMessage(self.tr("Ending your break"), + self.tr("Break time's over. Resuming time tracking...")) + + def showOrHide(self): + self.setVisible(not self.isVisible()) + + def quit(self): + #TODO confirmation + QtGui.qApp.exit() + + def iconActivated(self, reason): + if reason != QtGui.QSystemTrayIcon.Context: + self.showOrHide() + + def showWindow(self): + self.show() + + def createProject(self): - '''Opens the new project dialog''' - self.projectList.selectedIndexes() - dialog = dialogs.NewProjectDialog(self.dataStore) - dialog.setModal(True) - if dialog.exec_() == QtGui.QDialog.Accepted: + '''Opens the new project dialog''' + dialog = dialogs.NewProjectDialog(self.dataStore) + if(dialog.exec_() == QtGui.QDialog.Accepted or + dialog.createdEmployer): self.__reloadItemModel() def viewSessions(self): '''Opens the view sessions dialog''' #TODO - pass + pass + + def __setStartButton(self, start): + if start: + self.disconnect(self.startSessionButton, + QtCore.SIGNAL('clicked()'), self.endSession) + self.connect(self.startSessionButton, + QtCore.SIGNAL('clicked()'), self.startSession) + self.startSessionButton.setText(self.tr("&Start working...")) + else: + self.disconnect(self.startSessionButton, + QtCore.SIGNAL('clicked()'), self.startSession) + self.connect(self.startSessionButton, + QtCore.SIGNAL('clicked()'), self.endSession) + self.startSessionButton.setText(self.tr("&Stop working...")) + def __reloadItemModel(self): itemModel = self.dataStore.getProjectItemModel() Modified: trunk/src/gui/new_employer.ui =================================================================== --- trunk/src/gui/new_employer.ui 2011-10-21 00:52:27 UTC (rev 36) +++ trunk/src/gui/new_employer.ui 2011-10-21 00:52:55 UTC (rev 37) @@ -13,6 +13,10 @@ <property name="windowTitle"> <string>New employer</string> </property> + <property name="windowIcon"> + <iconset resource="res.qrc"> + <normaloff>:/icon/icon.png</normaloff>:/icon/icon.png</iconset> + </property> <property name="locale"> <locale language="English" country="UnitedStates"/> </property> @@ -27,9 +31,6 @@ <property name="text"> <string>Employer name</string> </property> - <property name="wordWrap"> - <bool>true</bool> - </property> </widget> </item> <item row="0" column="1"> @@ -40,9 +41,6 @@ <property name="text"> <string>Employer description</string> </property> - <property name="wordWrap"> - <bool>true</bool> - </property> </widget> </item> <item row="2" column="0"> @@ -50,9 +48,6 @@ <property name="text"> <string>Hourly Rate</string> </property> - <property name="wordWrap"> - <bool>true</bool> - </property> </widget> </item> <item row="2" column="1"> @@ -99,7 +94,9 @@ <tabstop>hourlyRateSpinner</tabstop> <tabstop>buttonBox</tabstop> </tabstops> - <resources/> + <resources> + <include location="res.qrc"/> + </resources> <connections> <connection> <sender>buttonBox</sender> Modified: trunk/src/gui/new_project.ui =================================================================== --- trunk/src/gui/new_project.ui 2011-10-21 00:52:27 UTC (rev 36) +++ trunk/src/gui/new_project.ui 2011-10-21 00:52:55 UTC (rev 37) @@ -13,6 +13,10 @@ <property name="windowTitle"> <string>New project</string> </property> + <property name="windowIcon"> + <iconset resource="res.qrc"> + <normaloff>:/icon/icon.png</normaloff>:/icon/icon.png</iconset> + </property> <property name="locale"> <locale language="English" country="UnitedStates"/> </property> @@ -24,9 +28,6 @@ <property name="text"> <string>Project name</string> </property> - <property name="wordWrap"> - <bool>true</bool> - </property> </widget> </item> <item row="1" column="1"> @@ -41,9 +42,6 @@ <property name="text"> <string>Project description</string> </property> - <property name="wordWrap"> - <bool>true</bool> - </property> </widget> </item> <item row="2" column="1"> @@ -64,9 +62,6 @@ <property name="text"> <string>Employer</string> </property> - <property name="wordWrap"> - <bool>true</bool> - </property> </widget> </item> <item row="3" column="1"> @@ -96,7 +91,9 @@ <tabstop>employerChoice</tabstop> <tabstop>buttonBox</tabstop> </tabstops> - <resources/> + <resources> + <include location="res.qrc"/> + </resources> <connections> <connection> <sender>buttonBox</sender> Added: trunk/src/gui/res.qrc =================================================================== --- trunk/src/gui/res.qrc (rev 0) +++ trunk/src/gui/res.qrc 2011-10-21 00:52:55 UTC (rev 37) @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="icon" > + <file>../../icon.png</file> + </qresource> +</RCC> Modified: trunk/src/gui/start_session.ui =================================================================== --- trunk/src/gui/start_session.ui 2011-10-21 00:52:27 UTC (rev 36) +++ trunk/src/gui/start_session.ui 2011-10-21 00:52:55 UTC (rev 37) @@ -6,13 +6,17 @@ <rect> <x>0</x> <y>0</y> - <width>365</width> - <height>216</height> + <width>351</width> + <height>234</height> </rect> </property> <property name="windowTitle"> <string>Start work session</string> </property> + <property name="windowIcon"> + <iconset resource="res.qrc"> + <normaloff>:/icon/icon.png</normaloff>:/icon/icon.png</iconset> + </property> <property name="locale"> <locale language="English" country="UnitedStates"/> </property> @@ -23,45 +27,53 @@ <enum>QFormLayout::AllNonFixedFieldsGrow</enum> </property> <item row="0" column="0"> - <widget class="QLabel" name="label"> + <widget class="QLabel" name="label_4"> <property name="text"> - <string>Project</string> + <string>Employer</string> </property> </widget> </item> <item row="0" column="1"> - <widget class="QComboBox" name="projectChoice"> - <item> - <property name="text"> - <string>None (personal project)</string> - </property> - </item> - </widget> + <widget class="QComboBox" name="employerChoice"/> </item> - <item row="1" column="0" colspan="2"> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Preferred</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="2" column="0" colspan="2"> - <widget class="QLabel" name="label_2"> + <item row="1" column="0"> + <widget class="QLabel" name="label"> <property name="text"> - <string>Remind me to end the work session:</string> + <string>Project</string> </property> </widget> </item> - <item row="3" column="0"> + <item row="1" column="1"> + <widget class="QComboBox" name="projectChoice"/> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Remind me to end the work session:</string> + </property> + </widget> + </item> + <item> + <layout class="QFormLayout" name="formLayout"> + <item row="0" column="0"> <widget class="QRadioButton" name="fixedTimeButton"> <property name="text"> <string>At a &fixed time:</string> @@ -71,7 +83,7 @@ </property> </widget> </item> - <item row="3" column="1"> + <item row="0" column="1"> <widget class="QTimeEdit" name="sessionEndTime"> <property name="time"> <time> @@ -82,15 +94,15 @@ </property> </widget> </item> - <item row="4" column="0"> + <item row="1" column="0"> <widget class="QRadioButton" name="fixedWorkButton"> <property name="text"> <string>Work for:</string> </property> </widget> </item> - <item row="4" column="1"> - <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0"> + <item row="1" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0"> <item> <widget class="QTimeEdit" name="timeEdit"> <property name="enabled"> @@ -117,6 +129,22 @@ </layout> </item> <item> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Maximum</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> <widget class="QDialogButtonBox" name="buttonBox"> <property name="orientation"> <enum>Qt::Horizontal</enum> @@ -128,7 +156,9 @@ </item> </layout> </widget> - <resources/> + <resources> + <include location="res.qrc"/> + </resources> <connections> <connection> <sender>fixedTimeButton</sender> @@ -137,12 +167,12 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>41</x> - <y>105</y> + <x>51</x> + <y>134</y> </hint> <hint type="destinationlabel"> - <x>218</x> - <y>105</y> + <x>354</x> + <y>137</y> </hint> </hints> </connection> @@ -153,12 +183,12 @@ <slot>setDisabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>59</x> - <y>130</y> + <x>69</x> + <y>166</y> </hint> <hint type="destinationlabel"> - <x>208</x> - <y>105</y> + <x>352</x> + <y>137</y> </hint> </hints> </connection> @@ -170,7 +200,7 @@ <hints> <hint type="sourcelabel"> <x>257</x> - <y>185</y> + <y>199</y> </hint> <hint type="destinationlabel"> <x>157</x> @@ -186,7 +216,7 @@ <hints> <hint type="sourcelabel"> <x>322</x> - <y>185</y> + <y>199</y> </hint> <hint type="destinationlabel"> <x>286</x> @@ -201,12 +231,12 @@ <slot>setDisabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>40</x> - <y>101</y> + <x>50</x> + <y>134</y> </hint> <hint type="destinationlabel"> - <x>208</x> - <y>141</y> + <x>311</x> + <y>170</y> </hint> </hints> </connection> @@ -217,14 +247,50 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>43</x> - <y>141</y> + <x>53</x> + <y>166</y> </hint> <hint type="destinationlabel"> - <x>185</x> - <y>140</y> + <x>311</x> + <y>170</y> </hint> </hints> </connection> + <connection> + <sender>projectChoice</sender> + <signal>currentIndexChanged(int)</signal> + <receiver>startSessionDialog</receiver> + <slot>projectBoxChanged(int)</slot> + <hints> + <hint type="sourcelabel"> + <x>238</x> + <y>49</y> + </hint> + <hint type="destinationlabel"> + <x>118</x> + <y>41</y> + </hint> + </hints> + </connection> + <connection> + <sender>employerChoice</sender> + <signal>currentIndexChanged(int)</signal> + <receiver>startSessionDialog</receiver> + <slot>employerBoxChanged(int)</slot> + <hints> + <hint type="sourcelabel"> + <x>183</x> + <y>27</y> + </hint> + <hint type="destinationlabel"> + <x>124</x> + <y>23</y> + </hint> + </hints> + </connection> </connections> + <slots> + <slot>employerBoxChanged(int)</slot> + <slot>projectBoxChanged(int)</slot> + </slots> </ui> Modified: trunk/src/gui/view_sessions.ui =================================================================== --- trunk/src/gui/view_sessions.ui 2011-10-21 00:52:27 UTC (rev 36) +++ trunk/src/gui/view_sessions.ui 2011-10-21 00:52:55 UTC (rev 37) @@ -13,6 +13,10 @@ <property name="windowTitle"> <string/> </property> + <property name="windowIcon"> + <iconset resource="res.qrc"> + <normaloff>:/icon/icon.png</normaloff>:/icon/icon.png</iconset> + </property> <property name="locale"> <locale language="English" country="UnitedStates"/> </property> @@ -112,7 +116,9 @@ <tabstop>closeButton</tabstop> <tabstop>sessionList</tabstop> </tabstops> - <resources/> + <resources> + <include location="res.qrc"/> + </resources> <connections> <connection> <sender>closeButton</sender> Modified: trunk/src/gui/wizard.ui =================================================================== --- trunk/src/gui/wizard.ui 2011-10-21 00:52:27 UTC (rev 36) +++ trunk/src/gui/wizard.ui 2011-10-21 00:52:55 UTC (rev 37) @@ -13,6 +13,10 @@ <property name="windowTitle"> <string>Workman - Initial Setup</string> </property> + <property name="windowIcon"> + <iconset resource="res.qrc"> + <normaloff>:/icon/icon.png</normaloff>:/icon/icon.png</iconset> + </property> <property name="locale"> <locale language="English" country="UnitedStates"/> </property> @@ -180,6 +184,8 @@ </layout> </widget> </widget> - <resources/> + <resources> + <include location="res.qrc"/> + </resources> <connections/> </ui> Modified: trunk/src/gui/workman.ui =================================================================== --- trunk/src/gui/workman.ui 2011-10-21 00:52:27 UTC (rev 36) +++ trunk/src/gui/workman.ui 2011-10-21 00:52:55 UTC (rev 37) @@ -7,12 +7,16 @@ <x>0</x> <y>0</y> <width>673</width> - <height>279</height> + <height>270</height> </rect> </property> <property name="windowTitle"> <string>Workman</string> </property> + <property name="windowIcon"> + <iconset resource="res.qrc"> + <normaloff>:/icon/icon.png</normaloff>:/icon/icon.png</iconset> + </property> <property name="locale"> <locale language="English" country="UnitedStates"/> </property> @@ -29,6 +33,9 @@ <property name="alternatingRowColors"> <bool>true</bool> </property> + <property name="selectionMode"> + <enum>QAbstractItemView::SingleSelection</enum> + </property> <property name="selectionBehavior"> <enum>QAbstractItemView::SelectRows</enum> </property> @@ -116,7 +123,9 @@ </layout> </widget> </widget> - <resources/> + <resources> + <include location="res.qrc"/> + </resources> <connections> <connection> <sender>startSessionButton</sender> Modified: trunk/src/workman.py =================================================================== --- trunk/src/workman.py 2011-10-21 00:52:27 UTC (rev 36) +++ trunk/src/workman.py 2011-10-21 00:52:55 UTC (rev 37) @@ -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, QtCore +from PyQt4 import QtGui import sys import workman_types ''' @@ -30,58 +30,74 @@ class DataStore: '''Where the program data is stored in memory''' - NO_EMPLOYER = 'None' + NO_EMPLOYER = 'None' # Not to be translated (here) + NO_EMPLOYER_DESCRIPTION = '' + NO_PROJECT = 'None' # Not to be translated (here) + NO_PROJECT_DESCRIPTION = '' def __init__(self, db): + DataStore.NO_EMPLOYER_DESCRIPTION = QtGui.qApp.tr( + "For personal projects") + DataStore.NO_PROJECT_DESCRIPTION = QtGui.qApp.tr("General work") + self.db = db self.projectItemModel = None if db is None: - noEmployer = workman_types.Employer( - 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.employers = {} + self.addEmployer(DataStore.NO_EMPLOYER, + DataStore.NO_EMPLOYER_DESCRIPTION, 0.0) + self.activeSession = None self.activeBreak = None return #TODO: get stuff from DB - def startSession(self, project): - result = workman_types.Session(datetime.now(), project) - self.activeSession = result + def startSession(self, employerName, projectName): + assert(employerName in self.employers.keys() and + projectName in self.employers[employerName].projects.keys() and + self.activeSession is None) + session = workman_types.Session( + self.employers[employerName].projects[projectName], + datetime.now()) + self.activeSession = session #TODO: write data to a file for disaster recovery - return result - def endSession(self, session, message): - assert session is not None + def endSession(self, message): + assert self.activeSession is not None #TODO: write data to a file for disaster recovery if self.db is not None: return #TODO: write session and its breaks to database - session.endTime = datetime.now() - session.message = message + if self.activeBreak is not None: + self.endBreak() + self.activeSession.endTime = datetime.now() + self.activeSession.message = message self.activeSession = None - def startBreak(self, session, reason): - assert self.activeSession is not None and session is not None - result = workman_types.Break(datetime.now(), session, reason = reason) - self.activeBreak = result - return result + def startBreak(self, reason): + assert(self.activeSession is not None and + self.activeBreak is None) + self.activeBreak = workman_types.Break( + self.activeSession, reason = reason) - def endBreak(self, curBreak): + def endBreak(self): #TODO: write data to a file for disaster recovery assert(self.activeBreak is not None and - self.activeSession is not None and curBreak is not None) - curBreak.endTime = datetime.now() + self.activeSession is not None) + self.activeBreak.endTime = datetime.now() self.activeBreak = None def addEmployer(self, name, description, rate): assert(name not in self.employers.keys() and - name is not None and name != '') + name is not None and name != '' and rate >= 0) - employer = workman_types.Employer(name, rate, description) + + employer = workman_types.Employer(name, rate, description) self.employers[employer.name] = employer + self.addProject(DataStore.NO_PROJECT, + DataStore.NO_PROJECT_DESCRIPTION, name) #TODO: Write data to database def addProject(self, projectName, description, employerName): @@ -93,44 +109,46 @@ workman_types.Project( projectName, self.employers[employerName], description) - if self.projectItemModel is not None: - self.projectItemModel.appendRow(self.__newItemModelRow( - employerName, projectName, description)) + if self.projectItemModel is not None: + 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] + if employerName == DataStore.NO_EMPLOYER: + modelEmployerName = self.projectItemModel.tr( + "None (personal project)") + else: + modelEmployerName = employerName + if projectName == DataStore.NO_PROJECT: + modelProjectName = self.projectItemModel.tr( + "Unsorted") + modelDescription = self.projectItemModel.tr( + "General work") + else: + modelProjectName = projectName + modelDescription = projDesc + + employerItem = QtGui.QStandardItem(modelEmployerName) + projectItem = QtGui.QStandardItem(modelProjectName) + descriptionItem = QtGui.QStandardItem(modelDescription) + return [projectItem, employerItem, descriptionItem] def getProjectItemModel(self): if self.projectItemModel is None: self.projectItemModel = QtGui.QStandardItemModel() self.projectItemModel.setHorizontalHeaderLabels( - [QtGui.qApp.tr("Project"), - QtGui.qApp.tr("Employer"), - QtGui.qApp.tr("Description")]) + [self.projectItemModel.tr("Project"), + self.projectItemModel.tr("Employer"), + self.projectItemModel.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( self.__newItemModelRow( - employerName, projectName, j.description)) + i.name, j.name, j.description)) return self.projectItemModel Modified: trunk/src/workman_types.py =================================================================== --- trunk/src/workman_types.py 2011-10-21 00:52:27 UTC (rev 36) +++ trunk/src/workman_types.py 2011-10-21 00:52:55 UTC (rev 37) @@ -62,12 +62,12 @@ endTime = None, message = '', breaks = None): self.startTime = startTime self.endTime = endTime - self.setProject(project) - if breaks is not None: + self.setProject(project) + if breaks is None: self.breaks = [] else: self.breaks = breaks - + def setProject(self, project): self.project = project if project is not None: @@ -76,8 +76,8 @@ class Break: - def __init__(self, session = None, startTime = datetime.now(), - endTime = None, reason = ''): + def __init__(self, session = None, reason = '', + startTime = datetime.now(), endTime = None): self.startTime = startTime self.endTime = endTime self.reason = reason This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
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. |
From: <jm...@us...> - 2011-10-21 00:52:16
|
Revision: 35 http://workman.svn.sourceforge.net/workman/?rev=35&view=rev Author: jmsilva Date: 2011-10-21 00:52:10 +0000 (Fri, 21 Oct 2011) Log Message: ----------- UI tweaks, some business logic and a main window class stub. Modified Paths: -------------- trunk/src/gui/new_employer.ui trunk/src/gui/workman.ui Added Paths: ----------- trunk/src/gui/main_window.py trunk/src/workman.py Added: trunk/src/gui/main_window.py =================================================================== --- trunk/src/gui/main_window.py (rev 0) +++ trunk/src/gui/main_window.py 2011-10-21 00:52:10 UTC (rev 35) @@ -0,0 +1,60 @@ +#!/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/>. +''' +Created on 2009/12/17 + +@author: João Miguel Ferreira da Silva +''' + +from compiled_ui import Ui_mainWindow +from PyQt4 import QtGui, QtCore + + +class MainWindow(Ui_mainWindow, QtGui.QMainWindow): + ''' + The application's main window + ''' + + + def __init__(self, dataStore): + ''' + Initiates the main window, populating the project list + ''' + QtGui.QMainWindow.__init__(self) + self.setupUi(self) + itemModel = dataStore.getProjectItemModel() + self.projectList.setModel(itemModel) + self.connect(self.quitButton, QtCore.SIGNAL('clicked()'), + QtGui.qApp, QtCore.SLOT('quit()')) + + def startSession(self): + '''Opens the start session dialog''' + #TODO + pass + + def createProject(self): + '''Opens the new project dialog''' + + pass + + def viewSessions(self): + '''Opens the view sessions dialog''' + #TODO + pass + \ No newline at end of file Modified: trunk/src/gui/new_employer.ui =================================================================== --- trunk/src/gui/new_employer.ui 2011-10-21 00:51:54 UTC (rev 34) +++ trunk/src/gui/new_employer.ui 2011-10-21 00:52:10 UTC (rev 35) @@ -62,13 +62,6 @@ </item> <item row="1" column="1"> <widget class="QTextEdit" name="descriptionBox"> - <property name="html"> - <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Sans'; font-size:10pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p></body></html></string> - </property> <property name="acceptRichText"> <bool>false</bool> </property> Modified: trunk/src/gui/workman.ui =================================================================== --- trunk/src/gui/workman.ui 2011-10-21 00:51:54 UTC (rev 34) +++ trunk/src/gui/workman.ui 2011-10-21 00:52:10 UTC (rev 35) @@ -63,6 +63,16 @@ </widget> </item> <item> + <widget class="QPushButton" name="generateInvoiceButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>&New report/invoice...</string> + </property> + </widget> + </item> + <item> <widget class="QPushButton" name="viewSessionsButton"> <property name="text"> <string>&View sessions...</string> Added: trunk/src/workman.py =================================================================== --- trunk/src/workman.py (rev 0) +++ trunk/src/workman.py 2011-10-21 00:52:10 UTC (rev 35) @@ -0,0 +1,113 @@ +#!/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 datetime import datetime +from PyQt4 import QtGui +import sys +import workman_types +''' +The main module for the program +Created on 2009/12/18 + +@author: João Miguel Ferreira da Silva +''' + +class DataStore: + '''Where the program data is stored in memory''' + + 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] + self.activeSession = None + self.activeBreak = None + return + + #TODO: get stuff from DB + + def startSession(self, project): + result = workman_types.Session(datetime.now(), project) + self.activeSession = result + #TODO: write data to a file for disaster recovery + return result + + + def endSession(self, session, message): + assert session is not None + #TODO: write data to a file for disaster recovery + if self.db is not None: + return #TODO: write session and its breaks to database + + session.endTime = datetime.now() + session.message = message + self.activeSession = None + + def startBreak(self, session, reason): + assert self.activeSession is not None and session is not None + result = workman_types.Break(datetime.now(), session, reason = reason) + self.activeBreak = result + return result + + def endBreak(self, curBreak): + #TODO: write data to a file for disaster recovery + assert(self.activeBreak is not None and + self.activeSession is not None and curBreak is not None) + curBreak.endTime = datetime.now() + self.activeBreak = None + + def addEmployer(self, employer): + assert employer is not None + 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]) + if self.projectItemModel is not None: + self.projectItemModel.appendRow([project.name, employerName]) + + 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: + self.projectItemModel.appendRow( + [j.name, i.name]) + + + return self.projectItemModel + else: + return self.projectItemModel + + + +if __name__ == '__main__': + from gui.main_window import MainWindow + QtGui.QApplication(sys.argv) + data = DataStore(None) + x = MainWindow(data) + x.show() + sys.exit(QtGui.qApp.exec_()) + \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jm...@us...> - 2011-10-21 00:52:00
|
Revision: 34 http://workman.svn.sourceforge.net/workman/?rev=34&view=rev Author: jmsilva Date: 2011-10-21 00:51:54 +0000 (Fri, 21 Oct 2011) Log Message: ----------- Python apparently already had a types module Added Paths: ----------- trunk/src/workman_types.py Added: trunk/src/workman_types.py =================================================================== --- trunk/src/workman_types.py (rev 0) +++ trunk/src/workman_types.py 2011-10-21 00:51:54 UTC (rev 34) @@ -0,0 +1,89 @@ +#!/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/>. + +''' + +Created on 2009/12/08 + +@author: João Miguel Ferreira da Silva +''' + +from datetime import datetime + +class Employer: + ''' + Specifies an employer + ''' + def __init__(self, name = '', rate = 0.0, + description = '', projects = None): + self.name = name + self.rate = rate + self.description = description + if projects is None: + self.projects = {} + else: + self.projects = projects + + +class Project: + def __init__(self, name = '', employer = None, description = '', sessions = None): + self.name = name + self.description = description + self.setEmployer(employer) + if sessions is None: + self.sessions = [] + else: + self.sessions = sessions + + + def setEmployer(self, employer): + self.employer = employer + if employer is not None: + employer.projects[self.name] = self + +class Session: + def __init__(self, project = None, startTime = datetime.now(), + endTime = None, message = '', breaks = None): + self.startTime = startTime + self.endTime = endTime + self.setProject(project) + if breaks is not None: + self.breaks = [] + else: + self.breaks = breaks + + def setProject(self, project): + self.project = project + if project is not None: + project.sessions.append(self) + + +class Break: + + def __init__(self, session = None, startTime = datetime.now(), + endTime = None, reason = ''): + self.startTime = startTime + self.endTime = endTime + self.reason = reason + self.setSession(session) + + def setSession(self, session): + self.session = session + if session is not None: + session.breaks.append(self) \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jm...@us...> - 2011-10-21 00:51:49
|
Revision: 33 http://workman.svn.sourceforge.net/workman/?rev=33&view=rev Author: jmsilva Date: 2011-10-21 00:51:43 +0000 (Fri, 21 Oct 2011) Log Message: ----------- Changed not * is to is not Modified Paths: -------------- trunk/src/types.py Modified: trunk/src/types.py =================================================================== --- trunk/src/types.py 2011-10-21 00:51:34 UTC (rev 32) +++ trunk/src/types.py 2011-10-21 00:51:43 UTC (rev 33) @@ -54,7 +54,7 @@ def setEmployer(self, employer): self.employer = employer - if not employer is None: + if employer is not None: employer.projects[self.name] = self class Session: @@ -63,14 +63,14 @@ self.startTime = startTime self.endTime = endTime self.setProject(project) - if not breaks is None: + if breaks is not None: self.breaks = [] else: self.breaks = breaks def setProject(self, project): self.project = project - if not project is None: + if project is not None: project.sessions.append(self) @@ -85,5 +85,5 @@ def setSession(self, session): self.session = session - if not session is None: + if session is not None: session.breaks.append(self) \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jm...@us...> - 2011-10-21 00:51:40
|
Revision: 32 http://workman.svn.sourceforge.net/workman/?rev=32&view=rev Author: jmsilva Date: 2011-10-21 00:51:34 +0000 (Fri, 21 Oct 2011) Log Message: ----------- - Changes to the database. - Changes to the type classes. - Corrected the main window's UI to use a QTableView instead of a QListView Modified Paths: -------------- trunk/db.sql trunk/src/db.py trunk/src/gui/build_ui.sh trunk/src/gui/workman.ui trunk/src/types.py Modified: trunk/db.sql =================================================================== --- trunk/db.sql 2011-10-21 00:51:20 UTC (rev 31) +++ trunk/db.sql 2011-10-21 00:51:34 UTC (rev 32) @@ -16,24 +16,30 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* +This should work with SQLite 3 +It doesn't enforce the foreign keys, but they are provided for +ease of migration to another database. +*/ + drop table employers; create table employers( - employer_id integer not null autoincrement, + employer_id integer primary key autoincrement, employer_name varchar(128) not null, employer_description varchar not null, - primary key(employer_id), + --primary key(employer_id), unique(employer_name) ); drop table employer_instances; create table employer_instances( - employer_instance_id integer not null autoincrement, + employer_instance_id integer primary key autoincrement, employer_id integer not null, - employer_hourly_rate float not null + employer_hourly_rate float not null, employer_rate_start_date date not null, - primary key(employer_instance_id), + --primary key(employer_instance_id), unique(employer_id, employer_rate_start_date), foreign key(employer_id) references employers ); @@ -41,11 +47,11 @@ drop table projects; create table projects( - project_id integer not null autoincrement, + project_id integer primary key autoincrement, project_name varchar(128) not null, project_description varchar not null, employer_id integer not null, - primary key(project_id), + --primary key(project_id), unique(project_name), foreign key(employer_id) references employers ); @@ -53,23 +59,25 @@ drop table sessions; create table sessions( - session_id integer not null autoincrement, + session_id integer primary key autoincrement, session_start_time date not null, session_end_time date not null, session_description varchar not null, project_id integer not null, - primary key(session_id), + --primary key(session_id), unique(session_start_time, project_id), foreign key(project_id) references projects ); +drop table breaks; + create table breaks( - break_id integer not null autoincrement, + break_id integer primary key autoincrement, break_start_time date not null, break_end_time date not null, break_reason varchar(128) not null, session_id integer not null, - primary key(break_id), + --primary key(break_id), unique(break_start_time, session_id), foreign key(session_id) references sessions ); @@ -78,15 +86,16 @@ drop table tasks; create table tasks( - task_id integer not null autoincrement, + task_id integer primary key autoincrement, project_name varchar(128) not null, task_name varchar(256) not null, task_description varchar not null, task_due_date date not null, - primary key(task_id), + --primary key(task_id), unique(project_name, task_name), foreign key(project_name) references projects ); + */ /* @@ -95,9 +104,11 @@ - no start dates smaller than the biggest end date */ -insert into employers( - employer_name, employer_hourly_rate, employer_rate_start_date) - values('None', 0, datetime()); +insert into employers + values(1, 'None', 'For personal projects'); +insert into employer_instances(employer_id, + employer_hourly_rate, employer_rate_start_date) + values(1, 0.0, datetime()); insert into projects(project_name, project_description, employer_id) - (select 'None', 'For unassigned projects', employer_id from employers); + select 'None', 'For unassigned projects', employer_id from employers; Modified: trunk/src/db.py =================================================================== --- trunk/src/db.py 2011-10-21 00:51:20 UTC (rev 31) +++ trunk/src/db.py 2011-10-21 00:51:34 UTC (rev 32) @@ -19,7 +19,7 @@ ''' Created on 2009/11/30 -@author: jms +@author: João Miguel Ferreira da Silva ''' Modified: trunk/src/gui/build_ui.sh =================================================================== --- trunk/src/gui/build_ui.sh 2011-10-21 00:51:20 UTC (rev 31) +++ trunk/src/gui/build_ui.sh 2011-10-21 00:51:34 UTC (rev 32) @@ -1,4 +1,4 @@ +echo \#\!/usr/bin/python > compiled_ui.py for i in *.ui ; do - basename=`basename $i .ui` - pyuic4 -o $basename.py $i && true + pyuic4 $i >> compiled_ui.py && true done Modified: trunk/src/gui/workman.ui =================================================================== --- trunk/src/gui/workman.ui 2011-10-21 00:51:20 UTC (rev 31) +++ trunk/src/gui/workman.ui 2011-10-21 00:51:34 UTC (rev 32) @@ -22,16 +22,19 @@ <number>10</number> </property> <item> - <widget class="QListView" name="projectList"> - <property name="toolTip"> - <string>A list with all your projects.</string> - </property> + <widget class="QTableView" name="projectList"> <property name="editTriggers"> <set>QAbstractItemView::NoEditTriggers</set> </property> - <property name="tabKeyNavigation"> + <property name="alternatingRowColors"> <bool>true</bool> </property> + <property name="selectionBehavior"> + <enum>QAbstractItemView::SelectRows</enum> + </property> + <property name="gridStyle"> + <enum>Qt::NoPen</enum> + </property> </widget> </item> <item> @@ -92,5 +95,59 @@ </widget> </widget> <resources/> - <connections/> + <connections> + <connection> + <sender>startSessionButton</sender> + <signal>clicked()</signal> + <receiver>mainWindow</receiver> + <slot>startSession()</slot> + <hints> + <hint type="sourcelabel"> + <x>569</x> + <y>30</y> + </hint> + <hint type="destinationlabel"> + <x>431</x> + <y>-7</y> + </hint> + </hints> + </connection> + <connection> + <sender>createProjectButton</sender> + <signal>clicked()</signal> + <receiver>mainWindow</receiver> + <slot>createProject()</slot> + <hints> + <hint type="sourcelabel"> + <x>547</x> + <y>60</y> + </hint> + <hint type="destinationlabel"> + <x>572</x> + <y>140</y> + </hint> + </hints> + </connection> + <connection> + <sender>viewSessionsButton</sender> + <signal>clicked()</signal> + <receiver>mainWindow</receiver> + <slot>viewSessions()</slot> + <hints> + <hint type="sourcelabel"> + <x>558</x> + <y>103</y> + </hint> + <hint type="destinationlabel"> + <x>549</x> + <y>174</y> + </hint> + </hints> + </connection> + </connections> + <slots> + <slot>startSession()</slot> + <slot>createProject()</slot> + <slot>viewSessions()</slot> + </slots> </ui> Modified: trunk/src/types.py =================================================================== --- trunk/src/types.py 2011-10-21 00:51:20 UTC (rev 31) +++ trunk/src/types.py 2011-10-21 00:51:34 UTC (rev 32) @@ -21,7 +21,7 @@ Created on 2009/12/08 -@author: jms +@author: João Miguel Ferreira da Silva ''' from datetime import datetime @@ -31,32 +31,59 @@ Specifies an employer ''' def __init__(self, name = '', rate = 0.0, - description = '', startDate = ''): + description = '', projects = None): self.name = name self.rate = rate self.description = description - self.startDate = startDate + if projects is None: + self.projects = {} + else: + self.projects = projects class Project: - def __init__(self, name = '', employer = None, description = ''): - self.name = name - self.employer = employer + def __init__(self, name = '', employer = None, description = '', sessions = None): + self.name = name self.description = description + self.setEmployer(employer) + if sessions is None: + self.sessions = [] + else: + self.sessions = sessions + + def setEmployer(self, employer): + self.employer = employer + if not employer is None: + employer.projects[self.name] = self + class Session: - def __init__(self, project = None, - startTime = datetime.now(), endTime = None, message = ''): - self.project = project + def __init__(self, project = None, startTime = datetime.now(), + endTime = None, message = '', breaks = None): self.startTime = startTime self.endTime = endTime + self.setProject(project) + if not breaks is None: + self.breaks = [] + else: + self.breaks = breaks + + def setProject(self, project): + self.project = project + if not project is None: + project.sessions.append(self) class Break: - def __init__(self, session = None, - startTime = datetime.now(), endTime = None, reason = ''): - self.session = session + def __init__(self, session = None, startTime = datetime.now(), + endTime = None, reason = ''): self.startTime = startTime self.endTime = endTime - self.reason = reason \ No newline at end of file + self.reason = reason + self.setSession(session) + + def setSession(self, session): + self.session = session + if not session is None: + session.breaks.append(self) \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jm...@us...> - 2011-10-21 00:51:26
|
Revision: 31 http://workman.svn.sourceforge.net/workman/?rev=31&view=rev Author: jmsilva Date: 2011-10-21 00:51:20 +0000 (Fri, 21 Oct 2011) Log Message: ----------- REALY fixed the bug in the UI creation script. Modified Paths: -------------- trunk/src/gui/build_ui.sh Modified: trunk/src/gui/build_ui.sh =================================================================== --- trunk/src/gui/build_ui.sh 2011-10-21 00:51:11 UTC (rev 30) +++ trunk/src/gui/build_ui.sh 2011-10-21 00:51:20 UTC (rev 31) @@ -1,4 +1,4 @@ for i in *.ui ; do basename=`basename $i .ui` - pyuic4 -o $basename $i.py && true + pyuic4 -o $basename.py $i && true done This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jm...@us...> - 2011-10-21 00:51:17
|
Revision: 30 http://workman.svn.sourceforge.net/workman/?rev=30&view=rev Author: jmsilva Date: 2011-10-21 00:51:11 +0000 (Fri, 21 Oct 2011) Log Message: ----------- Fixed a bug in the UI compilation script. Modified Paths: -------------- trunk/src/gui/build_ui.sh Modified: trunk/src/gui/build_ui.sh =================================================================== --- trunk/src/gui/build_ui.sh 2011-10-21 00:51:01 UTC (rev 29) +++ trunk/src/gui/build_ui.sh 2011-10-21 00:51:11 UTC (rev 30) @@ -1,4 +1,4 @@ for i in *.ui ; do basename=`basename $i .ui` - pyuic4 -o $basename $i && true + pyuic4 -o $basename $i.py && true done This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jm...@us...> - 2011-10-21 00:51:08
|
Revision: 29 http://workman.svn.sourceforge.net/workman/?rev=29&view=rev Author: jmsilva Date: 2011-10-21 00:51:01 +0000 (Fri, 21 Oct 2011) Log Message: ----------- UI files. I know this is starting from the end, but this is a prototype for a Human-Computer Interaction subject at university. Added Paths: ----------- trunk/src/gui/ trunk/src/gui/build_ui.sh trunk/src/gui/end_session.ui trunk/src/gui/new_employer.ui trunk/src/gui/new_project.ui trunk/src/gui/start_session.ui trunk/src/gui/view_sessions.ui trunk/src/gui/wizard.ui trunk/src/gui/workman.ui trunk/src/gui/workman2.ui Added: trunk/src/gui/build_ui.sh =================================================================== --- trunk/src/gui/build_ui.sh (rev 0) +++ trunk/src/gui/build_ui.sh 2011-10-21 00:51:01 UTC (rev 29) @@ -0,0 +1,4 @@ +for i in *.ui ; do + basename=`basename $i .ui` + pyuic4 -o $basename $i && true +done Property changes on: trunk/src/gui/build_ui.sh ___________________________________________________________________ Added: svn:executable + * Added: trunk/src/gui/end_session.ui =================================================================== --- trunk/src/gui/end_session.ui (rev 0) +++ trunk/src/gui/end_session.ui 2011-10-21 00:51:01 UTC (rev 29) @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>endSessionDialog</class> + <widget class="QDialog" name="endSessionDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>End session</string> + </property> + <property name="locale"> + <locale language="English" country="UnitedStates"/> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="endSessionLabel"> + <property name="text"> + <string>Ending the work session. You may write a small summary of what you did.</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QTextEdit" name="workSummary"> + <property name="toolTip"> + <string>A small summary of what you worked on</string> + </property> + <property name="acceptRichText"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="confirmationBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>confirmationBox</sender> + <signal>accepted()</signal> + <receiver>endSessionDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>257</x> + <y>290</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>confirmationBox</sender> + <signal>rejected()</signal> + <receiver>endSessionDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>325</x> + <y>290</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> Added: trunk/src/gui/new_employer.ui =================================================================== --- trunk/src/gui/new_employer.ui (rev 0) +++ trunk/src/gui/new_employer.ui 2011-10-21 00:51:01 UTC (rev 29) @@ -0,0 +1,132 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>newEmployerDialog</class> + <widget class="QDialog" name="newEmployerDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>343</width> + <height>212</height> + </rect> + </property> + <property name="windowTitle"> + <string>New employer</string> + </property> + <property name="locale"> + <locale language="English" country="UnitedStates"/> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QFormLayout" name="formLayout"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::AllNonFixedFieldsGrow</enum> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Employer name</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="employerNameBox"/> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Employer description</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Hourly Rate</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0"> + <item> + <widget class="QDoubleSpinBox" name="hourlyRateSpinner"/> + </item> + <item> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>$</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="1" column="1"> + <widget class="QTextEdit" name="descriptionBox"> + <property name="html"> + <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p></body></html></string> + </property> + <property name="acceptRichText"> + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <tabstops> + <tabstop>employerNameBox</tabstop> + <tabstop>descriptionBox</tabstop> + <tabstop>hourlyRateSpinner</tabstop> + <tabstop>buttonBox</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>newEmployerDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>newEmployerDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> Added: trunk/src/gui/new_project.ui =================================================================== --- trunk/src/gui/new_project.ui (rev 0) +++ trunk/src/gui/new_project.ui 2011-10-21 00:51:01 UTC (rev 29) @@ -0,0 +1,132 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>newProjectDialog</class> + <widget class="QDialog" name="newProjectDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>327</width> + <height>215</height> + </rect> + </property> + <property name="windowTitle"> + <string>New project</string> + </property> + <property name="locale"> + <locale language="English" country="UnitedStates"/> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QFormLayout" name="formLayout"> + <item row="1" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Project name</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="projectNameBox"> + <property name="toolTip"> + <string>Enter the project's name here</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Project description</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QTextEdit" name="descriptionBox"> + <property name="toolTip"> + <string>Enter an optional description for this project</string> + </property> + <property name="acceptRichText"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Employer</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QComboBox" name="employerChoice"> + <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> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <tabstops> + <tabstop>projectNameBox</tabstop> + <tabstop>descriptionBox</tabstop> + <tabstop>employerChoice</tabstop> + <tabstop>buttonBox</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>newProjectDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>257</x> + <y>205</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>newProjectDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>317</x> + <y>205</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> Added: trunk/src/gui/start_session.ui =================================================================== --- trunk/src/gui/start_session.ui (rev 0) +++ trunk/src/gui/start_session.ui 2011-10-21 00:51:01 UTC (rev 29) @@ -0,0 +1,230 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>startSessionDialog</class> + <widget class="QDialog" name="startSessionDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>365</width> + <height>216</height> + </rect> + </property> + <property name="windowTitle"> + <string>Start work session</string> + </property> + <property name="locale"> + <locale language="English" country="UnitedStates"/> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QFormLayout" name="formLayout_2"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::AllNonFixedFieldsGrow</enum> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Project</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="projectChoice"> + <item> + <property name="text"> + <string>None (personal project)</string> + </property> + </item> + </widget> + </item> + <item row="1" column="0" colspan="2"> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Preferred</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="0" colspan="2"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Remind me to end the work session:</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QRadioButton" name="fixedTimeButton"> + <property name="text"> + <string>At a &fixed time:</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QTimeEdit" name="sessionEndTime"> + <property name="time"> + <time> + <hour>18</hour> + <minute>0</minute> + <second>0</second> + </time> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QRadioButton" name="fixedWorkButton"> + <property name="text"> + <string>Work for:</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0"> + <item> + <widget class="QTimeEdit" name="timeEdit"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="time"> + <time> + <hour>8</hour> + <minute>0</minute> + <second>0</second> + </time> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>hours</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>fixedTimeButton</sender> + <signal>toggled(bool)</signal> + <receiver>sessionEndTime</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>41</x> + <y>105</y> + </hint> + <hint type="destinationlabel"> + <x>218</x> + <y>105</y> + </hint> + </hints> + </connection> + <connection> + <sender>fixedWorkButton</sender> + <signal>toggled(bool)</signal> + <receiver>sessionEndTime</receiver> + <slot>setDisabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>59</x> + <y>130</y> + </hint> + <hint type="destinationlabel"> + <x>208</x> + <y>105</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>startSessionDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>257</x> + <y>185</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>201</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>startSessionDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>322</x> + <y>185</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>201</y> + </hint> + </hints> + </connection> + <connection> + <sender>fixedTimeButton</sender> + <signal>toggled(bool)</signal> + <receiver>timeEdit</receiver> + <slot>setDisabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>40</x> + <y>101</y> + </hint> + <hint type="destinationlabel"> + <x>208</x> + <y>141</y> + </hint> + </hints> + </connection> + <connection> + <sender>fixedWorkButton</sender> + <signal>toggled(bool)</signal> + <receiver>timeEdit</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>43</x> + <y>141</y> + </hint> + <hint type="destinationlabel"> + <x>185</x> + <y>140</y> + </hint> + </hints> + </connection> + </connections> +</ui> Added: trunk/src/gui/view_sessions.ui =================================================================== --- trunk/src/gui/view_sessions.ui (rev 0) +++ trunk/src/gui/view_sessions.ui 2011-10-21 00:51:01 UTC (rev 29) @@ -0,0 +1,134 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>sessionsWindow</class> + <widget class="QDialog" name="sessionsWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>389</width> + <height>326</height> + </rect> + </property> + <property name="windowTitle"> + <string/> + </property> + <property name="locale"> + <locale language="English" country="UnitedStates"/> + </property> + <layout class="QGridLayout" name="gridLayout" columnstretch="3,1,0"> + <item row="0" column="0"> + <layout class="QFormLayout" name="formLayout"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::AllNonFixedFieldsGrow</enum> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Project</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="projectChoice"> + <item> + <property name="text"> + <string>None (personal project)</string> + </property> + </item> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Starting date</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QDateEdit" name="startDateWidget"> + <property name="calendarPopup"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Ending date</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QDateEdit" name="endDateWidget"> + <property name="calendarPopup"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + <item row="2" column="0" colspan="3"> + <widget class="QListView" name="sessionList"/> + </item> + <item row="0" column="1"> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QPushButton" name="searchButton"> + <property name="text"> + <string>&Search</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="closeButton"> + <property name="text"> + <string>&Close</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + <tabstops> + <tabstop>projectChoice</tabstop> + <tabstop>startDateWidget</tabstop> + <tabstop>endDateWidget</tabstop> + <tabstop>searchButton</tabstop> + <tabstop>closeButton</tabstop> + <tabstop>sessionList</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>closeButton</sender> + <signal>clicked()</signal> + <receiver>sessionsWindow</receiver> + <slot>close()</slot> + <hints> + <hint type="sourcelabel"> + <x>427</x> + <y>53</y> + </hint> + <hint type="destinationlabel"> + <x>434</x> + <y>81</y> + </hint> + </hints> + </connection> + </connections> +</ui> Added: trunk/src/gui/wizard.ui =================================================================== --- trunk/src/gui/wizard.ui (rev 0) +++ trunk/src/gui/wizard.ui 2011-10-21 00:51:01 UTC (rev 29) @@ -0,0 +1,185 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Wizard</class> + <widget class="QWizard" name="Wizard"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>508</width> + <height>314</height> + </rect> + </property> + <property name="windowTitle"> + <string>Workman - Initial Setup</string> + </property> + <property name="locale"> + <locale language="English" country="UnitedStates"/> + </property> + <widget class="QWizardPage" name="startPage"> + <property name="title"> + <string>Welcome</string> + </property> + <property name="subTitle"> + <string>Welcome to Workman.</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="projectLabel"> + <property name="locale"> + <locale language="English" country="UnitedStates"/> + </property> + <property name="text"> + <string>Hello, and welcome to Workman. + +To bill or organize your work, you are advised to split it into projects. + +Would you like to create a project now?</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="projectYesButton"> + <property name="locale"> + <locale language="English" country="UnitedStates"/> + </property> + <property name="text"> + <string>&Yes</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="projectNoButton"> + <property name="text"> + <string>&No</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + <widget class="QWizardPage" name="lastPage"> + <property name="title"> + <string>Creating a project</string> + </property> + <property name="subTitle"> + <string>Please enter some information about the project.</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QFormLayout" name="formLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="projectNameLabel"> + <property name="text"> + <string>Project Name</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="projectNameBox"> + <property name="toolTip"> + <string>The name of the project you want to create</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="employerLabel"> + <property name="text"> + <string>Employer</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="employerChoice"> + <property name="toolTip"> + <string>The employer for this project</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> + </item> + <item> + <widget class="QLabel" name="startSessionLabel"> + <property name="text"> + <string>Would you like to start a work session right now?</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="radioButton"> + <property name="text"> + <string>&Yes</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="radioButton_2"> + <property name="text"> + <string>&No</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + </widget> + <resources/> + <connections/> +</ui> Added: trunk/src/gui/workman.ui =================================================================== --- trunk/src/gui/workman.ui (rev 0) +++ trunk/src/gui/workman.ui 2011-10-21 00:51:01 UTC (rev 29) @@ -0,0 +1,96 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>mainWindow</class> + <widget class="QMainWindow" name="mainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>673</width> + <height>279</height> + </rect> + </property> + <property name="windowTitle"> + <string>Workman</string> + </property> + <property name="locale"> + <locale language="English" country="UnitedStates"/> + </property> + <widget class="QWidget" name="centralwidget"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="spacing"> + <number>10</number> + </property> + <item> + <widget class="QListView" name="projectList"> + <property name="toolTip"> + <string>A list with all your projects.</string> + </property> + <property name="editTriggers"> + <set>QAbstractItemView::NoEditTriggers</set> + </property> + <property name="tabKeyNavigation"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="spacing"> + <number>10</number> + </property> + <item> + <widget class="QPushButton" name="startSessionButton"> + <property name="text"> + <string>&Start working...</string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="createProjectButton"> + <property name="text"> + <string>&Create project...</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="viewSessionsButton"> + <property name="text"> + <string>&View sessions...</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="quitButton"> + <property name="text"> + <string>&Quit</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </widget> + <resources/> + <connections/> +</ui> Added: trunk/src/gui/workman2.ui =================================================================== --- trunk/src/gui/workman2.ui (rev 0) +++ trunk/src/gui/workman2.ui 2011-10-21 00:51:01 UTC (rev 29) @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>720</width> + <height>246</height> + </rect> + </property> + <property name="windowTitle"> + <string>MainWindow</string> + </property> + <widget class="QWidget" name="centralwidget"> + <widget class="QWidget" name="horizontalLayoutWidget"> + <property name="geometry"> + <rect> + <x>10</x> + <y>10</y> + <width>701</width> + <height>231</height> + </rect> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="spacing"> + <number>15</number> + </property> + <item> + <widget class="QListView" name="projectList"/> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="spacing"> + <number>10</number> + </property> + <item> + <widget class="QPushButton" name="startSessionButton"> + <property name="text"> + <string>Start working...</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="createProjectButton"> + <property name="text"> + <string>Create project...</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="viewSessionsButton"> + <property name="text"> + <string>View sessions...</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="quitButton"> + <property name="text"> + <string>Quit</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </widget> + </widget> + <resources/> + <connections/> +</ui> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jm...@us...> - 2011-10-21 00:50:51
|
Revision: 28 http://workman.svn.sourceforge.net/workman/?rev=28&view=rev Author: jmsilva Date: 2011-10-21 00:50:45 +0000 (Fri, 21 Oct 2011) Log Message: ----------- Some basic data types. Added Paths: ----------- trunk/src/types.py Added: trunk/src/types.py =================================================================== --- trunk/src/types.py (rev 0) +++ trunk/src/types.py 2011-10-21 00:50:45 UTC (rev 28) @@ -0,0 +1,62 @@ +#!/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/>. + +''' + +Created on 2009/12/08 + +@author: jms +''' + +from datetime import datetime + +class Employer: + ''' + Specifies an employer + ''' + def __init__(self, name = '', rate = 0.0, + description = '', startDate = ''): + self.name = name + self.rate = rate + self.description = description + self.startDate = startDate + + +class Project: + def __init__(self, name = '', employer = None, description = ''): + self.name = name + self.employer = employer + self.description = description + +class Session: + def __init__(self, project = None, + startTime = datetime.now(), endTime = None, message = ''): + self.project = project + self.startTime = startTime + self.endTime = endTime + + +class Break: + + def __init__(self, session = None, + startTime = datetime.now(), endTime = None, reason = ''): + self.session = session + self.startTime = startTime + self.endTime = endTime + self.reason = reason \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jm...@us...> - 2011-10-21 00:50:41
|
Revision: 27 http://workman.svn.sourceforge.net/workman/?rev=27&view=rev Author: jmsilva Date: 2011-10-21 00:50:35 +0000 (Fri, 21 Oct 2011) Log Message: ----------- Changed the DB schema Modified Paths: -------------- trunk/db.sql Modified: trunk/db.sql =================================================================== --- trunk/db.sql 2011-10-21 00:50:27 UTC (rev 26) +++ trunk/db.sql 2011-10-21 00:50:35 UTC (rev 27) @@ -20,14 +20,24 @@ create table employers( employer_id integer not null autoincrement, - employer_name varchar(128) not null, - employer_hourly_rate float not null, + employer_name varchar(128) not null, employer_description varchar not null, - employer_rate_start_date date not null, primary key(employer_id), - unique(employer_name, employer_rate_start_date) + unique(employer_name) ); +drop table employer_instances; + +create table employer_instances( + employer_instance_id integer not null autoincrement, + employer_id integer not null, + employer_hourly_rate float not null + employer_rate_start_date date not null, + primary key(employer_instance_id), + unique(employer_id, employer_rate_start_date), + foreign key(employer_id) references employers +); + drop table projects; create table projects( This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jm...@us...> - 2011-10-21 00:50:33
|
Revision: 26 http://workman.svn.sourceforge.net/workman/?rev=26&view=rev Author: jmsilva Date: 2011-10-21 00:50:27 +0000 (Fri, 21 Oct 2011) Log Message: ----------- Tiny changes in the DB. Modified Paths: -------------- trunk/db.sql trunk/src/db.py Modified: trunk/db.sql =================================================================== --- trunk/db.sql 2011-10-21 00:50:16 UTC (rev 25) +++ trunk/db.sql 2011-10-21 00:50:27 UTC (rev 26) @@ -22,6 +22,7 @@ employer_id integer not null autoincrement, employer_name varchar(128) not null, employer_hourly_rate float not null, + employer_description varchar not null, employer_rate_start_date date not null, primary key(employer_id), unique(employer_name, employer_rate_start_date) Modified: trunk/src/db.py =================================================================== --- trunk/src/db.py 2011-10-21 00:50:16 UTC (rev 25) +++ trunk/src/db.py 2011-10-21 00:50:27 UTC (rev 26) @@ -1,4 +1,5 @@ #!/usr/bin/python +# -*- coding: utf-8 -*- # # Workman - A time tracking program for self-employed people # Copyright (C) 2009 João Miguel Ferreira da Silva @@ -30,7 +31,8 @@ ''' # TODO: What if the database goes down? - # TODO: Generalise SQL insert and select statement handling + # TODO: Generalize SQL insert and select statement handling + # TODO: Add remaining needed methods def __init__(self, dbType = 'QSQLITE', dbName = 'workman', dbUsername = '', dbPassword = '', dbConnectOptions = ''): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jm...@us...> - 2011-10-21 00:50:22
|
Revision: 25 http://workman.svn.sourceforge.net/workman/?rev=25&view=rev Author: jmsilva Date: 2011-10-21 00:50:16 +0000 (Fri, 21 Oct 2011) Log Message: ----------- Added shebangs. Modified Paths: -------------- trunk/src/db.py Modified: trunk/src/db.py =================================================================== --- trunk/src/db.py 2011-10-21 00:50:06 UTC (rev 24) +++ trunk/src/db.py 2011-10-21 00:50:16 UTC (rev 25) @@ -1,8 +1,5 @@ -''' -Created on 2009/11/30 - -@author: jms -''' +#!/usr/bin/python +# # Workman - A time tracking program for self-employed people # Copyright (C) 2009 João Miguel Ferreira da Silva # @@ -18,7 +15,13 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. +''' +Created on 2009/11/30 +@author: jms +''' + + from PyQt4 import QtSql class DB: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jm...@us...> - 2011-10-21 00:50:12
|
Revision: 24 http://workman.svn.sourceforge.net/workman/?rev=24&view=rev Author: jmsilva Date: 2011-10-21 00:50:06 +0000 (Fri, 21 Oct 2011) Log Message: ----------- Annoyingly, my python IDE was configured to replace tabs with spaces by default. Replaced the tabs. Modified Paths: -------------- trunk/src/db.py Modified: trunk/src/db.py =================================================================== --- trunk/src/db.py 2011-10-21 00:49:57 UTC (rev 23) +++ trunk/src/db.py 2011-10-21 00:50:06 UTC (rev 24) @@ -22,146 +22,146 @@ from PyQt4 import QtSql class DB: - ''' - Handles data access - ''' - - # TODO: What if the database goes down? - # TODO: Generalise SQL insert and select statement handling + ''' + Handles data access + ''' + + # TODO: What if the database goes down? + # TODO: Generalise SQL insert and select statement handling + + def __init__(self, dbType = 'QSQLITE', dbName = 'workman', + dbUsername = '', dbPassword = '', dbConnectOptions = ''): + ''' + Connects to the database + ''' + self.db = QtSql.QSqlDatabase.addDatabase(dbType) + self.db.setDatabaseName('workman') + self.db.setUsername(dbUsername) + self.db.setPassword(dbPassword) + self.db.setConnectOptions(dbConnectOptions) + if not self.db.open(): + raise RuntimeError() + self.pendingQueries = {} + self.lastQuery = 0 + + def insertEmployer(self, employer, rate): + ''' + Inserts a new employer into the Database + ''' + if employer is None or rate is None: + return False + + query = QtSql.QSqlQuery(self.db) + query.prepare('insert into employers(employer_name, ' + 'employer_hourly_rate, employer_rate_start_date) values(' + ':employer, :rate, datetime());') + query.addBindValue(employer) + query.addBindValue(rate) + return query.exec_() + + def insertSession(self, project, startDate, endDate, desc, breaks): + ''' + Inserts a new session into the Database + ''' + if project is None or startDate is None or endDate is None or desc is None: + return False + + QtSql.QSqlDatabase.transaction(); + query = QtSql.QSqlQuery(self.db) + query.prepare('Insert into sessions(project_name, ' + 'project_description, employer_id) values(' + ':project, :startDate, :endDate, :desc);') + query.addBindValue(project) + query.addBindValue(startDate) + query.addBindValue(endDate) + query.addBindValue(desc) + return query.exec_() + + # TODO: Add limits to the queries + """def newQuery(self, query, numElems = 20): + ''' + Creates a new query id, which should be passed to + subsequent requests + ''' + try: + result = self.lastQuery + self.pendingQueries[self.lastQuery] = (query, 0, numElems) + self.lastQuery += 1 + + return result + except KeyError: + return None + + + + def startQuery(self, id, args): + ''' + Sets the arguments for the query with ID. Args is a tuple + ''' + try: + queryInfo = self.pendingQueries[id] + query = QtSql.QSqlQuery(self.db) + status = query.exec_(queryInfo[0] + 'limit ' + str(queryInfo[1])) + if not status: + return False + + result = [] + + while query.next(): + record = query.record() + startTime = record.value(0) + endTime = record.value(1) + desc = record.value(2) + assert startTime.isValid() and endTime.isValid() and desc.isValid() + result.append((startTime, endTime, desc)) + except KeyError: + pass""" + + def getSessions(self, project): + ''' + Gets a list of sessions for a given project + ''' + query = QtSql.QSqlQuery(self.db) + query.prepare('select session_id, session_start_time, session_end_time, ' + 'session_description from sessions where project_id = :project;') + query.addBindValue(project) + status = query.exec_() + if not status: + return False + + result = [] + + while query.next(): + record = query.record() + sid = record.value(0) + startTime = record.value(1) + endTime = record.value(2) + desc = record.value(3) + assert (sid.isValid() and startTime.isValid() and + endTime.isValid() and desc.isValid()) + sessionBreaks = self.__getBreaks(sid) + result.append((startTime, endTime, desc, sessionBreaks)) + + return result + + def __getBreaks(self, session): + query = QtSql.QSqlQuery(self.db) + query.prepare('select break_start_time, break_end_time, ' + 'break_reason from breaks where session_id = :session;') + query.addBindValue(session) + status = query.exec_() + if not status: + return False + + result = [] + while query.next(): + record = query.record() + startTime = record.value(0) + endTime = record.value(1) + reason = record.value(2) + assert(startTime.isValid() and + endTime.isValid() and reason.isValid()) + result.append((startTime, endTime, reason)) + + return result - def __init__(self, dbType = 'QSQLITE', dbName = 'workman', - dbUsername = '', dbPassword = '', dbConnectOptions = ''): - ''' - Connects to the database - ''' - self.db = QtSql.QSqlDatabase.addDatabase(dbType) - self.db.setDatabaseName('workman') - self.db.setUsername(dbUsername) - self.db.setPassword(dbPassword) - self.db.setConnectOptions(dbConnectOptions) - if not self.db.open(): - raise RuntimeError() - self.pendingQueries = {} - self.lastQuery = 0 - - def insertEmployer(self, employer, rate): - ''' - Inserts a new employer into the Database - ''' - if employer is None or rate is None: - return False - - query = QtSql.QSqlQuery(self.db) - query.prepare('insert into employers(employer_name, ' - 'employer_hourly_rate, employer_rate_start_date) values(' - ':employer, :rate, datetime());') - query.addBindValue(employer) - query.addBindValue(rate) - return query.exec_() - - def insertSession(self, project, startDate, endDate, desc, breaks): - ''' - Inserts a new session into the Database - ''' - if project is None or startDate is None or endDate is None or desc is None: - return False - - QtSql.QSqlDatabase.transaction(); - query = QtSql.QSqlQuery(self.db) - query.prepare('Insert into sessions(project_name, ' - 'project_description, employer_id) values(' - ':project, :startDate, :endDate, :desc);') - query.addBindValue(project) - query.addBindValue(startDate) - query.addBindValue(endDate) - query.addBindValue(desc) - return query.exec_() - - # TODO: Add limits to the queries - """def newQuery(self, query, numElems = 20): - ''' - Creates a new query id, which should be passed to - subsequent requests - ''' - try: - result = self.lastQuery - self.pendingQueries[self.lastQuery] = (query, 0, numElems) - self.lastQuery += 1 - - return result - except KeyError: - return None - - - - def startQuery(self, id, args): - ''' - Sets the arguments for the query with ID. Args is a tuple - ''' - try: - queryInfo = self.pendingQueries[id] - query = QtSql.QSqlQuery(self.db) - status = query.exec_(queryInfo[0] + 'limit ' + str(queryInfo[1])) - if not status: - return False - - result = [] - - while query.next(): - record = query.record() - startTime = record.value(0) - endTime = record.value(1) - desc = record.value(2) - assert startTime.isValid() and endTime.isValid() and desc.isValid() - result.append((startTime, endTime, desc)) - except KeyError: - pass""" - - def getSessions(self, project): - ''' - Gets a list of sessions for a given project - ''' - query = QtSql.QSqlQuery(self.db) - query.prepare('select session_id, session_start_time, session_end_time, ' - 'session_description from sessions where project_id = :project;') - query.addBindValue(project) - status = query.exec_() - if not status: - return False - - result = [] - - while query.next(): - record = query.record() - sid = record.value(0) - startTime = record.value(1) - endTime = record.value(2) - desc = record.value(3) - assert (sid.isValid() and startTime.isValid() and - endTime.isValid() and desc.isValid()) - sessionBreaks = self.__getBreaks(sid) - result.append((startTime, endTime, desc, sessionBreaks)) - - return result - - def __getBreaks(self, session): - query = QtSql.QSqlQuery(self.db) - query.prepare('select break_start_time, break_end_time, ' - 'break_reason from breaks where session_id = :session;') - query.addBindValue(session) - status = query.exec_() - if not status: - return False - - result = [] - while query.next(): - record = query.record() - startTime = record.value(0) - endTime = record.value(1) - reason = record.value(2) - assert(startTime.isValid() and - endTime.isValid() and reason.isValid()) - result.append((startTime, endTime, reason)) - - return result - This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jm...@us...> - 2011-10-21 00:50:03
|
Revision: 23 http://workman.svn.sourceforge.net/workman/?rev=23&view=rev Author: jmsilva Date: 2011-10-21 00:49:57 +0000 (Fri, 21 Oct 2011) Log Message: ----------- Forgot to add license headers... oops! Modified Paths: -------------- trunk/db.sql trunk/src/db.py Modified: trunk/db.sql =================================================================== --- trunk/db.sql 2011-10-21 00:49:47 UTC (rev 22) +++ trunk/db.sql 2011-10-21 00:49:57 UTC (rev 23) @@ -1,3 +1,21 @@ +/* +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/>. +*/ + drop table employers; create table employers( Modified: trunk/src/db.py =================================================================== --- trunk/src/db.py 2011-10-21 00:49:47 UTC (rev 22) +++ trunk/src/db.py 2011-10-21 00:49:57 UTC (rev 23) @@ -3,6 +3,21 @@ @author: jms ''' +# 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 QtSql This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |