Thread: [Workman-svn] SF.net SVN: workman:[2] trunk
An unobtrusive time-tracking program for self-employed people
Status: Pre-Alpha
Brought to you by:
jmsilva
|
From: <jm...@us...> - 2011-10-21 00:21:15
|
Revision: 2
http://workman.svn.sourceforge.net/workman/?rev=2&view=rev
Author: jmsilva
Date: 2011-10-21 00:21:09 +0000 (Fri, 21 Oct 2011)
Log Message:
-----------
Basic database schema.
Added Paths:
-----------
trunk/nha/
trunk/nha/db.sql
Added: trunk/nha/db.sql
===================================================================
--- trunk/nha/db.sql (rev 0)
+++ trunk/nha/db.sql 2011-10-21 00:21:09 UTC (rev 2)
@@ -0,0 +1,37 @@
+create table employers(
+ employer_name varchar(128) not null,
+ employer_hourly_rate float not null,
+ employer_rate_start_date date not null,
+ primary key(employer_name, employer_rate_start_date)
+);
+
+create table projects(
+ project_name varchar(128) not null,
+ project_description varchar not null,
+ employer_name varchar(128) not null,
+ employer_rate_start_date date not null,
+ primary key(project_name),
+ foreign key(employer_name, employer_rate_start_date) references employers
+);
+
+create table sessions(
+ project_name varchar(128) not null,
+ session_start_time date not null,
+ session_end_time date not null,
+ session_description varchar not null,
+ primary key(project_name, session_start_time, session_end_time),
+ foreign key(project_name) references projects
+);
+
+/*
+create table tasks(
+ 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(project_name, task_name),
+ foreign key(project_name) references 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:30:52
|
Revision: 6
http://workman.svn.sourceforge.net/workman/?rev=6&view=rev
Author: jmsilva
Date: 2011-10-21 00:30:46 +0000 (Fri, 21 Oct 2011)
Log Message:
-----------
Basic database schema.
Added Paths:
-----------
trunk/nha/
trunk/nha/db.sql
Added: trunk/nha/db.sql
===================================================================
--- trunk/nha/db.sql (rev 0)
+++ trunk/nha/db.sql 2011-10-21 00:30:46 UTC (rev 6)
@@ -0,0 +1,37 @@
+create table employers(
+ employer_name varchar(128) not null,
+ employer_hourly_rate float not null,
+ employer_rate_start_date date not null,
+ primary key(employer_name, employer_rate_start_date)
+);
+
+create table projects(
+ project_name varchar(128) not null,
+ project_description varchar not null,
+ employer_name varchar(128) not null,
+ employer_rate_start_date date not null,
+ primary key(project_name),
+ foreign key(employer_name, employer_rate_start_date) references employers
+);
+
+create table sessions(
+ project_name varchar(128) not null,
+ session_start_time date not null,
+ session_end_time date not null,
+ session_description varchar not null,
+ primary key(project_name, session_start_time, session_end_time),
+ foreign key(project_name) references projects
+);
+
+/*
+create table tasks(
+ 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(project_name, task_name),
+ foreign key(project_name) references 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:49:53
|
Revision: 22
http://workman.svn.sourceforge.net/workman/?rev=22&view=rev
Author: jmsilva
Date: 2011-10-21 00:49:47 +0000 (Fri, 21 Oct 2011)
Log Message:
-----------
- Tweaks to the database.
- Unfinished database handling. Will probably be changed.
Modified Paths:
--------------
trunk/db.sql
Added Paths:
-----------
trunk/src/
trunk/src/db.py
Modified: trunk/db.sql
===================================================================
--- trunk/db.sql 2011-10-21 00:49:36 UTC (rev 21)
+++ trunk/db.sql 2011-10-21 00:49:47 UTC (rev 22)
@@ -1,37 +1,74 @@
+drop table employers;
+
create table employers(
+ employer_id integer not null autoincrement,
employer_name varchar(128) not null,
employer_hourly_rate float not null,
employer_rate_start_date date not null,
- primary key(employer_name, employer_rate_start_date)
+ primary key(employer_id),
+ unique(employer_name, employer_rate_start_date)
);
+drop table projects;
+
create table projects(
+ project_id integer not null autoincrement,
project_name varchar(128) not null,
project_description varchar not null,
- employer_name varchar(128) not null,
- employer_rate_start_date date not null,
- primary key(project_name),
- foreign key(employer_name, employer_rate_start_date) references employers
+ employer_id integer not null,
+ primary key(project_id),
+ unique(project_name),
+ foreign key(employer_id) references employers
);
+drop table sessions;
+
create table sessions(
- project_name varchar(128) not null,
+ session_id integer not null autoincrement,
session_start_time date not null,
session_end_time date not null,
session_description varchar not null,
- primary key(project_name, session_start_time, session_end_time),
- foreign key(project_name) references projects
+ project_id integer not null,
+ primary key(session_id),
+ unique(session_start_time, project_id),
+ foreign key(project_id) references projects
);
+create table breaks(
+ break_id integer not null 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),
+ unique(break_start_time, session_id),
+ foreign key(session_id) references sessions
+);
+
/*
+drop table tasks;
+
create table tasks(
+ task_id integer not null 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(project_name, task_name),
+ primary key(task_id),
+ unique(project_name, task_name),
foreign key(project_name) references projects
-);
-
+);
*/
+/*
+TODO: triggers
+- no end dates smaller than start dates
+- 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 projects(project_name, project_description, employer_id)
+ (select 'None', 'For unassigned projects', employer_id from employers);
+
Added: trunk/src/db.py
===================================================================
--- trunk/src/db.py (rev 0)
+++ trunk/src/db.py 2011-10-21 00:49:47 UTC (rev 22)
@@ -0,0 +1,152 @@
+'''
+Created on 2009/11/30
+
+@author: jms
+'''
+
+from PyQt4 import QtSql
+
+class DB:
+ '''
+ 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
+
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.
|
|
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: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: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: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: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.
|