1 from PyQt4.QtCore import *
2 from PyQt4.QtGui import *
3 from PyQt4.QtSql import *
5 from chooseaction import ChooseAction
6 from editperson import EditPerson
7 from mergephotos import MergePhotos
8 from odtwriter import ODTWriter
9 from analytics import Analytics
11 class MainApp (QMainWindow):
12 schema = "CREATE TABLE people ( id INTEGER PRIMARY KEY AUTOINCREMENT, forename TEXT NOT NULL, surname TEXT NOT NULL, netid TEXT NOT NULL, email TEXT, birthday TEXT, phone TEXT, major TEXT, dorm TEXT, room INTEGER, photo BLOB, createtime TEXT NOT NULL, mtime TEXT NOT NULL);"
13 def __init__(self, Parent=None):
14 """Set up the main view, load the default database and schema, and set the widgets visible."""
15 QMainWindow.__init__(self, Parent)
16 self.setWindowTitle("Whitepages V3")
18 self.db = QSqlDatabase.addDatabase("QSQLITE")
19 self.db.setDatabaseName("families.db")
21 q = QSqlQuery(self.db)
22 q.exec_(MainApp.schema)
24 self.center = QStackedWidget()
25 self.chooseaction = ChooseAction(self,self.db)
26 self.editperson = EditPerson(self,self.db)
27 self.mergephotos = MergePhotos(self,self.db)
28 self.analytics = Analytics(self,self.db)
29 self.center.addWidget(self.chooseaction)
30 self.center.addWidget(self.editperson)
31 self.center.addWidget(self.mergephotos)
32 self.center.addWidget(self.analytics)
33 self.setCentralWidget(self.center)
38 self.statusBar().showMessage("Ready")
39 self.setUnifiedTitleAndToolBarOnMac(True);
43 def createActions(self):
44 """Create actions and connect signals and slots."""
45 self.fileNewAction = QAction("&New Database",self)
46 QObject.connect( self.fileNewAction, SIGNAL("triggered()"), self.newFile)
47 self.fileOpenAction = QAction("&Open Database",self)
48 QObject.connect( self.fileOpenAction, SIGNAL("triggered()"), self.openFile)
49 self.fileImportAction = QAction("&Import (Merge)", self)
50 QObject.connect( self.fileImportAction, SIGNAL("triggered()"), self.mergeWizard)
51 self.fileQuitAction = QAction("&Quit",self)
52 QObject.connect( self.fileQuitAction, SIGNAL("triggered()"), self.quit)
53 QObject.connect( self.chooseaction, SIGNAL("editPerson()"), self.editPersonSlot)
54 QObject.connect( self.chooseaction, SIGNAL("mergePhotos()"), self.mergePhotosSlot)
55 QObject.connect( self.chooseaction, SIGNAL("exportDocument(QString)"), self.exportDocumentSlot)
56 QObject.connect( self.chooseaction, SIGNAL("runAnalytics()"), self.runAnalyticsSlot)
57 QObject.connect( self.editperson, SIGNAL("done()"), self.returnToMainMenu)
58 QObject.connect( self.mergephotos, SIGNAL("done()"), self.returnToMainMenu)
59 QObject.connect( self.analytics, SIGNAL("done()"), self.returnToMainMenu)
60 QObject.connect( self, SIGNAL("databaseChanged(QString)"), self.editperson.updateDB)
61 QObject.connect( self, SIGNAL("databaseChanged(QString)"), self.analytics.updateDB)
62 QObject.connect( self, SIGNAL("mergeDone()"), self.editperson.reselect )
65 def createMenus(self):
66 """Create the drop-down File menu."""
67 self.fileMenu = self.menuBar().addMenu("&File")
68 self.fileMenu.addAction(self.fileNewAction)
69 self.fileMenu.addAction(self.fileOpenAction)
70 self.fileMenu.addAction(self.fileImportAction)
71 self.fileMenu.addSeparator()
72 self.fileMenu.addAction(self.fileQuitAction)
76 """Allow user to specify a new SQLite database to work with."""
77 fileName = QFileDialog.getSaveFileName(self, "Save new file as:", ".", "Databases (*.db)")
78 if not fileName.isEmpty(): # If they cancelled, do nothing
79 if not fileName.endsWith(".db"): # if they leave off the extension, add it
80 fileName = fileName.append(".db")
82 self.db.setDatabaseName(fileName)
84 q = QSqlQuery(self.db)
85 q.exec_(MainApp.schema)
86 self.statusBar().showMessage("Closed the existing database, created " + fileName)
87 self.emit(SIGNAL("databaseChanged(QString)"),self.db.databaseName())
89 self.statusBar().showMessage("Cancelled creating new database")
91 """Load user-specified SQLite database for editing."""
92 fileName = QFileDialog.getOpenFileName(self, "Open dataset", ".", "Databases (*.db)")
93 if not fileName.isEmpty():
95 self.db.setDatabaseName(fileName)
97 self.statusBar().showMessage("Successfully loaded database " + fileName)
98 self.returnToMainMenu()
99 self.emit(SIGNAL("databaseChanged(QString)"),self.db.databaseName())
101 self.statusBar().showMessage("Canceled loading database")
102 def mergeWizard(self):
103 """Import user-specified SQLite database into this database, with intelligent merge heuristics. NetID conflicts are resolved by ignoring the to-be-imported record and keeping the one in the currently-open database."""
104 fileName = QFileDialog.getOpenFileName(self, "Import which dataset?", ".", "Databases (*.db)" )
105 if not fileName.isEmpty():
106 tempdb = QSqlDatabase.addDatabase("QSQLITE","tempdb")
107 tempdb.setDatabaseName(fileName)
109 q = QSqlQuery(self.db)
110 import_q = QSqlQuery(tempdb)
111 import_q.exec_("SELECT * FROM people;")
112 rec = import_q.record()
113 col_id = rec.indexOf("id")
114 col_forename = rec.indexOf("forename")
115 col_surname = rec.indexOf("surname")
116 col_netid = rec.indexOf("netid")
117 col_email = rec.indexOf("email")
118 col_birthday = rec.indexOf("birthday")
119 col_phone = rec.indexOf("phone")
120 col_major = rec.indexOf("major")
121 col_dorm = rec.indexOf("dorm")
122 col_room = rec.indexOf("room")
123 col_photo = rec.indexOf("photo")
124 col_createtime = rec.indexOf("createtime")
125 col_mtime = rec.indexOf("mtime")
126 #print "Number of columns:",rec.count()
128 while import_q.next():
129 qtestnewnetid = QSqlQuery(self.db)
130 qtestnewnetid.prepare("SELECT * FROM people WHERE netid = :netid")
131 qtestnewnetid.bindValue(":netid", import_q.value(col_netid) )
132 qtestnewnetid.exec_()
133 if qtestnewnetid.next(): # if the person's already in the DB, keep the old data
135 q.prepare("INSERT INTO people (netid, forename, surname, email, birthday, phone, major, dorm, room, createtime, mtime, photo )"
136 "VALUES (:netid, :forename, :surname, :email, :birthday, :phone, :major, :dorm, :room, :createtime, :mtime, :photo )" )
137 q.bindValue(":netid", import_q.value(col_netid) )
138 q.bindValue(":forename", import_q.value(col_forename) )
139 q.bindValue(":surname", import_q.value(col_surname) )
140 q.bindValue(":email", import_q.value(col_email) )
141 q.bindValue(":birthday", import_q.value(col_birthday) )
142 q.bindValue(":phone", import_q.value(col_phone) )
143 q.bindValue(":major", import_q.value(col_major) )
144 q.bindValue(":dorm", import_q.value(col_dorm) )
145 q.bindValue(":room", import_q.value(col_room) )
146 q.bindValue(":createtime", import_q.value(col_createtime) )
147 q.bindValue(":mtime", import_q.value(col_mtime) )
148 q.bindValue(":photo", import_q.value(col_photo) )
150 print "Inserted", import_q.value(col_forename).toString(), import_q.value(col_surname).toString(), "into DB"
151 records_merged = records_merged + 1
152 self.statusBar().showMessage(QString("Successfully merged %1 records from %2").arg(QString(str(records_merged))).arg(fileName))
154 self.emit(SIGNAL("mergeDone()"))
156 self.statusBar().showMessage("Canceled merging databases")
159 # You could do cleanup, like closing/flushing the database, an "Are you sure you want to quit?"
160 # modal dialog, or saving the window layout/state.
162 def returnToMainMenu(self):
163 """Switch to ChooseAction widget."""
164 self.center.setCurrentWidget(self.chooseaction)
165 def editPersonSlot(self):
166 """Switch to EditPerson widget."""
167 self.editperson.model.select() # update the table
168 self.center.setCurrentWidget(self.editperson)
169 def mergePhotosSlot(self):
170 """Switch to MergePhotos widget."""
171 print "beginning photo merge"
172 self.center.setCurrentWidget(self.mergephotos)
173 #self.mergephotos.beginMerge()
174 def exportDocumentSlot(self, filename):
175 """Export current database to ODT file <filename>."""
176 writer = ODTWriter(self.db)
177 success = writer.write(filename)
179 self.statusBar().showMessage(QString("Successfully exported to %1").arg(filename))
181 self.statusBar().showMessage(QString("Document export cancelled or failed"))
182 def runAnalyticsSlot(self):
183 """Switch to Analytics widget."""
184 print "Running analytics"
185 self.analytics.generateReport()
186 self.center.setCurrentWidget(self.analytics)
189 if __name__ == "__main__" :
190 app = QApplication([""])