~launchpad-p-s/sofastatistics/main

« back to all changes in this revision

Viewing changes to start.py

  • Committer: Grant Paton-Simpson
  • Date: 2009-05-19 04:21:43 UTC
  • Revision ID: g@ubuntu-20090519042143-p561mbokz3inefvd
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#! /usr/bin/env python
 
2
# -*- coding: utf-8 -*-
 
3
 
 
4
import os
 
5
import shutil
 
6
from pysqlite2 import dbapi2 as sqlite
 
7
import sys
 
8
import warnings
 
9
import wx
 
10
 
 
11
import dataselect
 
12
import getdata
 
13
import make_table_gui
 
14
import projects
 
15
import projselect
 
16
import util
 
17
 
 
18
MAX_HELP_TEXT_WIDTH = 350 # pixels
 
19
TEXT_BROWN = (90, 74, 61)
 
20
SCRIPT_PATH = util.get_script_path()
 
21
USER_PATH, LOCAL_PATH = util.get_user_paths()
 
22
warnings.filterwarnings("ignore", r".*Data truncated.*")
 
23
warnings.filterwarnings("ignore", r"UN[\w\s:]*.*")
 
24
warnings.filterwarnings("ignore", r".*WebKitSupport.*")
 
25
 
 
26
warnings.filterwarnings("ignore", r".*UserWarning.*[\w\s]*.*")
 
27
 
 
28
 
 
29
def TextOnBitmap(bitmap, text, font, colour):
 
30
    """
 
31
    Add short text to bitmap with standard left margin.
 
32
    Can then use bitmap for a bitmap button.
 
33
    See http://wiki.wxpython.org/index.cgi/WorkingWithImages
 
34
    """
 
35
    mem = wx.MemoryDC()
 
36
    mem.SelectObject(bitmap)
 
37
    mem.SetFont(font)
 
38
    mem.SetTextForeground(colour)
 
39
    mem.DrawText(text, 9, 3)
 
40
    mem.SelectObject(wx.NullBitmap)
 
41
    return bitmap
 
42
 
 
43
def GetTextToDraw(orig_txt, max_width):
 
44
    "Return text broken into new lines so wraps within pixel width"
 
45
    mem = wx.MemoryDC()
 
46
    # add words to it until its width is tooNeed Dun long then put int split
 
47
    lines = []
 
48
    words = orig_txt.split()
 
49
    line_words = []
 
50
    for word in words:
 
51
        line_words.append(word)
 
52
        line_width = mem.GetTextExtent(" ".join(line_words))[0]
 
53
        if line_width > max_width:
 
54
            line_words.pop()
 
55
            lines.append(" ".join(line_words))
 
56
            line_words = [word]
 
57
    lines.append(" ".join(line_words))
 
58
    wrapped_txt = "\n".join(lines)
 
59
    return wrapped_txt
 
60
 
 
61
def GetBlankButtonBitmap():
 
62
    return wx.Image(os.path.join(SCRIPT_PATH, "images", "blankbutton.xpm"), 
 
63
                    wx.BITMAP_TYPE_XPM).ConvertToBitmap()
 
64
 
 
65
def GetNextYPos(start, height):
 
66
    "Facilitate regular y position of buttons"
 
67
    i = 0
 
68
    while True:
 
69
        yield start + (i*height)
 
70
        i += 1
 
71
 
 
72
def InstallLocal():
 
73
    """
 
74
    Install local set of files in user home dir if necessary (not on Windows).
 
75
    Modify default project settings to point to local (user) SOFA  directory.
 
76
    """
 
77
    sofa_prog_path = os.path.join(util.get_prog_path(), "sofa")
 
78
    default_proj = os.path.join(LOCAL_PATH, "projs", 
 
79
                                "SOFA_Default_Project.proj")
 
80
    paths = ["css", projects.INTERNAL_FOLDER, "lbls", "projs", "reports", 
 
81
             "scripts"]
 
82
    if not os.path.exists(LOCAL_PATH):
 
83
            # in Windows these steps are all completed by the installer
 
84
            # create required folders
 
85
            for path in paths:
 
86
                os.makedirs(os.path.join(LOCAL_PATH, path))
 
87
            # copy across default proj, lbls, css
 
88
            shutil.copy(os.path.join(sofa_prog_path, "css", "alt_style.css"), 
 
89
                        os.path.join(LOCAL_PATH, "css", "alt_style.css"))
 
90
            shutil.copy(os.path.join(sofa_prog_path, "css", 
 
91
                                     "SOFA_Default_Style.css"), 
 
92
                        os.path.join(LOCAL_PATH, "css", 
 
93
                                     "SOFA_Default_Style.css"))
 
94
            shutil.copy(os.path.join(sofa_prog_path, projects.INTERNAL_FOLDER, 
 
95
                                     "SOFA_Default_db"), 
 
96
                        os.path.join(LOCAL_PATH, projects.INTERNAL_FOLDER, 
 
97
                                     "SOFA_Default_db"))
 
98
            shutil.copy(os.path.join(sofa_prog_path, "lbls", 
 
99
                                     "SOFA_Default_Labels.lbls"), 
 
100
                        os.path.join(LOCAL_PATH, "lbls", 
 
101
                                     "SOFA_Default_Labels.lbls"))
 
102
            shutil.copy(os.path.join(sofa_prog_path, "projs", 
 
103
                                     "SOFA_Default_Project.proj"), 
 
104
                        default_proj)
 
105
    PROJ_CUSTOMISED_FILE = "proj_file_customised.txt"
 
106
    if not os.path.exists(os.path.join(LOCAL_PATH, PROJ_CUSTOMISED_FILE)):
 
107
        # change home username
 
108
        f = file(default_proj, "r")
 
109
        proj_str = f.read()
 
110
        f.close()
 
111
        for path in paths:
 
112
            proj_str = proj_str.replace("/home/g/sofa/%s/" % path, 
 
113
                                        os.path.join(LOCAL_PATH, path, ""))
 
114
        # add MS Access into mix if Windows
 
115
        if util.in_windows():
 
116
            proj_str = proj_str.replace("default_dbs = {",
 
117
                                        "default_dbs = {'%s': None, " % \
 
118
                                            getdata.DBE_MS_ACCESS)
 
119
            proj_str = proj_str.replace("default_tbls = {",
 
120
                                        "default_tbls = {'%s': None, " % \
 
121
                                            getdata.DBE_MS_ACCESS)
 
122
        f = file(default_proj, "w")
 
123
        f.write(proj_str)
 
124
        f.close()
 
125
        # create file as tag we have done the changes to the proj file
 
126
        f = file(os.path.join(LOCAL_PATH, PROJ_CUSTOMISED_FILE), "w")
 
127
        f.write("Local project file customised successfully :-)")
 
128
        f.close()
 
129
 
 
130
 
 
131
class SofaApp(wx.App):
 
132
 
 
133
    debug = True
 
134
 
 
135
    def __init__(self):        
 
136
        # if wanting to initialise the parent class it must be run in child __init__ and nowhere else
 
137
        if self.debug:
 
138
            redirect = False
 
139
            filename = None
 
140
        else:
 
141
            redirect = True
 
142
            filename = os.path.join(os.getenv('HOME'), "sofa", 
 
143
                                              projects.INTERNAL_FOLDER, 
 
144
                                              'output.txt')
 
145
        wx.App.__init__(self, redirect=redirect, filename=filename) 
 
146
 
 
147
    def OnInit(self):
 
148
        frame = StartFrame()
 
149
        frame.CentreOnScreen()
 
150
        frame.Show()
 
151
        self.SetTopWindow(frame)
 
152
        return True
 
153
 
 
154
 
 
155
class StartFrame(wx.Frame):
 
156
    
 
157
    def __init__(self):
 
158
        wx.Frame.__init__(self, None, title="SOFA Start", size=(800, 542),
 
159
              style=wx.CAPTION|wx.CLOSE_BOX|wx.MINIMIZE_BOX|wx.SYSTEM_MENU,
 
160
              pos=(100, 100))
 
161
        y_start = self.GetClientSize()[1] - self.GetSize()[1]
 
162
        self.SetClientSize(self.GetSize()) # Windows doesn't include window decorations
 
163
        self.panel = wx.Panel(self)
 
164
        self.panel.Bind(wx.EVT_PAINT, self.OnPaint)        
 
165
        # icon
 
166
        ib = wx.IconBundle()
 
167
        ib.AddIconFromFile(os.path.join(SCRIPT_PATH, 
 
168
                                        "images", 
 
169
                                        "tinysofa.xpm"), 
 
170
                           wx.BITMAP_TYPE_XPM)
 
171
        self.SetIcons(ib)        
 
172
        # background image
 
173
        img_sofa = wx.Image(os.path.join(SCRIPT_PATH, "images", "sofa2.xpm"), 
 
174
                            wx.BITMAP_TYPE_XPM)
 
175
        self.bmp_sofa = wx.BitmapFromImage(img_sofa)
 
176
        # slice of image to be refreshed (where text and image will be)
 
177
        self.blank_wallpaper = self.bmp_sofa.GetSubBitmap(wx.Rect(160, 248, 
 
178
                                                                  640, 250))
 
179
        self.blank_proj_strip = self.bmp_sofa.GetSubBitmap(wx.Rect(160, 218, 
 
180
                                                                   500, 30))
 
181
        # buttons
 
182
        font_buttons = wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD)
 
183
        g = GetNextYPos(245, 34)
 
184
        btn_x_pos = 5
 
185
        bmp_btn_proj = TextOnBitmap(GetBlankButtonBitmap(), "Select project", 
 
186
                                    font_buttons, "white")
 
187
        self.btnProj = wx.BitmapButton(self.panel, -1, bmp_btn_proj, 
 
188
                                       pos=(btn_x_pos, g.next()))
 
189
        self.btnProj.Bind(wx.EVT_BUTTON, self.OnProjClick)
 
190
        self.btnProj.Bind(wx.EVT_ENTER_WINDOW, self.OnProjEnter)
 
191
        self.btnProj.SetDefault()
 
192
        bmp_btn_enter = TextOnBitmap(GetBlankButtonBitmap(), "Enter Data", 
 
193
                                     font_buttons, "white")
 
194
        self.btnEnter = wx.BitmapButton(self.panel, -1, bmp_btn_enter, 
 
195
                                        pos=(btn_x_pos, g.next()))
 
196
        self.btnEnter.Bind(wx.EVT_BUTTON, self.OnEnterClick)
 
197
        self.btnEnter.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterEnter)
 
198
        bmp_btn_tables = TextOnBitmap(GetBlankButtonBitmap(), "Make Tables", 
 
199
                                      font_buttons, "white")
 
200
        self.btnTables = wx.BitmapButton(self.panel, -1, bmp_btn_tables, 
 
201
                                         pos=(btn_x_pos, g.next()))
 
202
        self.btnTables.Bind(wx.EVT_BUTTON, self.OnTablesClick)
 
203
        self.btnTables.Bind(wx.EVT_ENTER_WINDOW, self.OnTablesEnter)
 
204
        bmp_btn_charts = TextOnBitmap(GetBlankButtonBitmap(), "View Charts", 
 
205
                                      font_buttons, "white")
 
206
        self.btnCharts = wx.BitmapButton(self.panel, -1, bmp_btn_charts, 
 
207
                                         pos=(btn_x_pos, g.next()))
 
208
        self.btnCharts.Bind(wx.EVT_BUTTON, self.OnChartsClick)
 
209
        self.btnCharts.Bind(wx.EVT_ENTER_WINDOW, self.OnChartsEnter)
 
210
        bmp_btn_stats = TextOnBitmap(GetBlankButtonBitmap(), "Statistics", 
 
211
                                     font_buttons, "white")
 
212
        self.btnStatistics = wx.BitmapButton(self.panel, -1, bmp_btn_stats, 
 
213
                                             pos=(btn_x_pos, g.next()))
 
214
        self.btnStatistics.Bind(wx.EVT_BUTTON, self.OnStatsClick)
 
215
        self.btnStatistics.Bind(wx.EVT_ENTER_WINDOW, self.OnStatsEnter)
 
216
        bmp_btn_exit = TextOnBitmap(GetBlankButtonBitmap(), "Exit", 
 
217
                                    font_buttons, "white")
 
218
        self.btnExit = wx.BitmapButton(self.panel, -1, bmp_btn_exit, 
 
219
                                       pos=(btn_x_pos, g.next()))
 
220
        self.btnExit.Bind(wx.EVT_BUTTON, self.OnExitClick)
 
221
        self.btnExit.Bind(wx.EVT_ENTER_WINDOW, self.OnExitEnter)
 
222
        # text
 
223
        # NB cannot have transparent background properly in Windows if using
 
224
        # a static ctrl http://aspn.activestate.com/ASPN/Mail/Message/wxpython-users/3045245
 
225
        self.txtWelcome = "Welcome to SOFA.  Hover the mouse over the " + \
 
226
            "buttons on the left to see what you can do."
 
227
        # help images
 
228
        img_chart = wx.Image(os.path.join(SCRIPT_PATH, "images", "demo_chart.xpm"), 
 
229
                              wx.BITMAP_TYPE_XPM)
 
230
        self.bmp_chart = wx.BitmapFromImage(img_chart)
 
231
        img_proj = wx.Image(os.path.join(SCRIPT_PATH, "images", "mysql_dolphins.xpm"), 
 
232
                            wx.BITMAP_TYPE_XPM)
 
233
        self.bmp_proj = wx.BitmapFromImage(img_proj)
 
234
        img_tabs = wx.Image(os.path.join(SCRIPT_PATH, "images", "table.xpm"), 
 
235
                            wx.BITMAP_TYPE_XPM)
 
236
        self.bmp_tabs = wx.BitmapFromImage(img_tabs)
 
237
        img_stats = wx.Image(os.path.join(SCRIPT_PATH, "images", "stats.xpm"), 
 
238
                            wx.BITMAP_TYPE_XPM)
 
239
        self.bmp_stats = wx.BitmapFromImage(img_stats)
 
240
        img_python = wx.Image(os.path.join(SCRIPT_PATH, "images", "python_small.xpm"), 
 
241
                         wx.BITMAP_TYPE_XPM)
 
242
        self.bmp_python = wx.BitmapFromImage(img_python)
 
243
        self.HELP_TEXT_FONT = wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL)
 
244
        self.active_proj = projects.SOFA_DEFAULT_PROJ
 
245
    
 
246
    def OnPaint(self, event):
 
247
        """
 
248
        Cannot use static bitmaps and static text to replace.  In windows
 
249
            doesn't show background wallpaper.
 
250
        NB painting like this sets things behind the controls.
 
251
        """
 
252
        panel_dc = wx.PaintDC(self.panel)
 
253
        panel_dc.DrawBitmap(self.bmp_sofa, 0, 0, True)
 
254
        panel_dc.DrawBitmap(self.bmp_chart, 540, 260, True)
 
255
        panel_dc.SetTextForeground(wx.WHITE)
 
256
        panel_dc.SetFont(wx.Font(16, wx.SWISS, wx.NORMAL, wx.NORMAL))
 
257
        panel_dc.DrawLabel("Statistics Open For All", 
 
258
                           wx.Rect(160, 70, 100, 100))
 
259
        panel_dc.SetFont(wx.Font(9, wx.SWISS, wx.NORMAL, wx.NORMAL))
 
260
        panel_dc.SetTextForeground(TEXT_BROWN)
 
261
        panel_dc.DrawLabel("SOFA - Statistics Open For All" + \
 
262
           "\nthe user-friendly, open-source\nstatistics & analysis package", 
 
263
           wx.Rect(160, 105, 100, 100))
 
264
        panel_dc.DrawLabel(GetTextToDraw(self.txtWelcome, MAX_HELP_TEXT_WIDTH), 
 
265
                           wx.Rect(160, 248, 540, 260))
 
266
        panel_dc.SetTextForeground(wx.WHITE)
 
267
        panel_dc.SetFont(wx.Font(7, wx.SWISS, wx.NORMAL, wx.NORMAL))
 
268
        panel_dc.DrawLabel("SOFA\nThe Open Statistics Company\nAuckland, New Zealand", 
 
269
                           wx.Rect(160, 497, 100, 50))
 
270
        panel_dc.DrawLabel("¬© 2009 The Open Statistics Company", 
 
271
                           wx.Rect(610, 522, 100, 50))
 
272
        panel_dc.DrawBitmap(self.bmp_python, 7, 495, True)
 
273
        # make default db if not already there
 
274
        connSqlite = sqlite.connect(os.path.join(LOCAL_PATH, 
 
275
                                                 projects.INTERNAL_FOLDER, 
 
276
                                                 projects.SOFA_DEFAULT_DB))
 
277
        connSqlite.close()
 
278
        panel_dc.DrawBitmap(self.blank_proj_strip, 160, 218, False)
 
279
        panel_dc.SetTextForeground(wx.WHITE)
 
280
        panel_dc.SetFont(wx.Font(11, wx.SWISS, wx.NORMAL, wx.NORMAL))
 
281
        panel_dc.DrawLabel("Currently using \"%s\" Project settings" % 
 
282
                               self.active_proj[:-5],
 
283
                           wx.Rect(160, 218, 400, 30))
 
284
        event.Skip()
 
285
    
 
286
    def SetProj(self, proj_text=""):
 
287
        "proj_text must NOT have .proj on the end"
 
288
        self.active_proj = "%s.proj" % proj_text
 
289
        self.Refresh()
 
290
        
 
291
    def OnProjClick(self, event):
 
292
        proj_fils = projects.GetProjs() # should always be the default present
 
293
        # open proj selection form
 
294
        dlgProj = projselect.ProjSelectDlg(self, proj_fils)
 
295
        dlgProj.ShowModal()
 
296
        dlgProj.Destroy()
 
297
        event.Skip()
 
298
 
 
299
    def DrawBlankWallpaper(self, panel_dc):
 
300
        panel_dc.DrawBitmap(self.blank_wallpaper, 160, 248, False)
 
301
 
 
302
    def OnProjEnter(self, event):
 
303
        panel_dc = wx.ClientDC(self.panel)
 
304
        self.DrawBlankWallpaper(panel_dc)
 
305
        panel_dc.DrawBitmap(self.bmp_proj, 570, 280, True)
 
306
        panel_dc.SetTextForeground(TEXT_BROWN)
 
307
        txt_projs = "Projects are a way of storing all related reports, " + \
 
308
            "data files, and configuration info in one place.  The " + \
 
309
            "default project will be OK to get you started."
 
310
        panel_dc.DrawLabel(GetTextToDraw(txt_projs, MAX_HELP_TEXT_WIDTH), 
 
311
                           wx.Rect(160, 248, 540, 260))
 
312
        event.Skip()
 
313
    
 
314
    def OnEnterClick(self, event):
 
315
        # open proj selection form
 
316
        proj_name = self.active_proj
 
317
        dlgData = dataselect.DataSelectDlg(self, proj_name)
 
318
        dlgData.ShowModal()
 
319
        dlgData.Destroy()
 
320
        event.Skip()
 
321
        
 
322
    def OnEnterEnter(self, event):
 
323
        panel_dc = wx.ClientDC(self.panel)
 
324
        self.DrawBlankWallpaper(panel_dc)
 
325
        panel_dc.DrawBitmap(self.bmp_chart, 540, 260, True)
 
326
        panel_dc.SetTextForeground(TEXT_BROWN)
 
327
        txt_entry = "Enter data into a fresh dataset or select an existing " + \
 
328
            "one to edit or add to."
 
329
        panel_dc.DrawLabel(GetTextToDraw(txt_entry, MAX_HELP_TEXT_WIDTH), 
 
330
                           wx.Rect(160, 248, 540, 260))
 
331
        event.Skip()
 
332
    
 
333
    def OnTablesClick(self, event):
 
334
        "Open make table gui with settings as per active_proj"
 
335
        proj_dic = projects.GetProjSettingsDic(proj_name=self.active_proj)
 
336
        dlg = make_table_gui.DlgMakeTable("Make Table", 
 
337
            proj_dic["default_dbe"], proj_dic["conn_dets"], 
 
338
            proj_dic["default_dbs"], proj_dic["default_tbls"], 
 
339
            proj_dic["fil_labels"], proj_dic["fil_css"], 
 
340
            proj_dic["fil_report"], proj_dic["fil_script"])
 
341
        dlg.ShowModal()
 
342
        event.Skip()
 
343
        
 
344
    def OnTablesEnter(self, event):
 
345
        panel_dc = wx.ClientDC(self.panel)
 
346
        self.DrawBlankWallpaper(panel_dc)
 
347
        panel_dc.DrawBitmap(self.bmp_tabs, 530, 255, True)
 
348
        panel_dc.SetTextForeground(TEXT_BROWN)
 
349
        txt_tabs = "Make tables e.g. Age vs Gender"
 
350
        panel_dc.DrawLabel(GetTextToDraw(txt_tabs, MAX_HELP_TEXT_WIDTH), 
 
351
                           wx.Rect(160, 248, 540, 260))
 
352
        event.Skip()
 
353
    
 
354
    def OnChartsClick(self, event):
 
355
        event.Skip()
 
356
        
 
357
    def OnChartsEnter(self, event):
 
358
        panel_dc = wx.ClientDC(self.panel)
 
359
        self.DrawBlankWallpaper(panel_dc)
 
360
        panel_dc.DrawBitmap(self.bmp_chart, 540, 260, True)
 
361
        panel_dc.SetTextForeground(TEXT_BROWN)
 
362
        txt_charts = "Make attractive charts e.g. a pie chart of regions"
 
363
        panel_dc.DrawLabel(GetTextToDraw(txt_charts, MAX_HELP_TEXT_WIDTH), 
 
364
                           wx.Rect(160, 248, 540, 260))
 
365
        event.Skip()
 
366
    
 
367
    def OnStatsClick(self, event):
 
368
        event.Skip()
 
369
        
 
370
    def OnStatsEnter(self, event):
 
371
        panel_dc = wx.ClientDC(self.panel)
 
372
        self.DrawBlankWallpaper(panel_dc)
 
373
        panel_dc.DrawBitmap(self.bmp_stats, 500, 260, True)
 
374
        panel_dc.SetTextForeground(TEXT_BROWN)
 
375
        txt_stats = "Run statistical tests on your data e.g. a Chi Square." + \
 
376
            "to see if there is a relationship between age and gender."
 
377
        panel_dc.DrawLabel(GetTextToDraw(txt_stats, MAX_HELP_TEXT_WIDTH), 
 
378
                           wx.Rect(160, 248, 540, 260))
 
379
        event.Skip()
 
380
    
 
381
    def OnExitClick(self, event):
 
382
        self.Destroy()
 
383
        sys.exit()
 
384
        
 
385
    def OnExitEnter(self, event):
 
386
        panel_dc = wx.ClientDC(self.panel)
 
387
        self.DrawBlankWallpaper(panel_dc)
 
388
        panel_dc.SetTextForeground(TEXT_BROWN)
 
389
        txt_exit = "Exit SOFA"
 
390
        panel_dc.DrawLabel(GetTextToDraw(txt_exit, MAX_HELP_TEXT_WIDTH), 
 
391
                           wx.Rect(160, 248, 540, 260))
 
392
        event.Skip()
 
393
 
 
394
  
 
395
InstallLocal()
 
396
app = SofaApp()
 
397
try:
 
398
    app.MainLoop()
 
399
finally:
 
400
    del app