4
# This file contains all the custom dialogs (each based on CustomDialog) used
7
# This program is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 2 of the License, or
10
# (at your option) any later version.
12
# This program is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
17
# You should have received a copy of the GNU General Public License
18
# along with this program; if not, write to the Free Software
19
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
# Copyright (C)2003 Phil Edwards, phil@linux2000.com
22
# vim: ts=4 sw=4 ai et
24
# standard Python imports
32
# PythonCard & wxPython imports
33
from PythonCard import dialog, resource, graphic, model
34
from PythonCard.model import CustomDialog
36
from wx.lib import dialogs
39
def dirSize(start, follow_links, my_depth, max_depth):
40
# work out how much space a directory is taking up, another handy one from the
41
# ASPN website, http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/86554
45
dir_list = os.listdir(start)
47
if os.path.isdir(start): print 'Cannot list directory %s' % start
51
path = '%s/%s' % (start, item)
55
print 'Cannot stat %s' % path
58
if os.path.isdir(path) and (follow_links or (not follow_links and not os.path.islink(path))):
59
bytes = dirSize(path, follow_links, my_depth + 1, max_depth)
64
def wrap_string(str, max, para = "\n\n"):
65
paras = string.split(str, para)
68
for paragraph in paras:
69
paragraph = paragraph.replace("\n", " ")
70
words = string.split(paragraph)
72
lineCount = wordCount = 0
74
for i in range(len(words)):
75
if (len(outLine) + len(words[i])) > max:
95
# supplemental function used when doing a recursive import
96
def walkTree(arg, dirname, names):
98
file, ext = os.path.splitext(item)
99
if ext.lower() == '.jpg' or ext.lower() == '.jpeg' and file[:1] != '.':
100
arg.append(os.path.join(dirname,item))
102
class versionDialog(CustomDialog):
103
"""Displays a dialog for the next release version number"""
105
def __init__(self, aBg, currentVersion):
106
path = os.path.join(aBg.application.applicationDirectory, 'versionDialog')
107
aDialogRsrc = resource.ResourceFile(model.internationalResourceName(path)).getResource()
108
CustomDialog.__init__(self, aBg, aDialogRsrc)
111
vstring = string.split(currentVersion, '.')
112
self.components.majorVersion.value = int(vstring[0])
113
self.components.minorVersion.value = int(vstring[1])
114
self.components.fixLevel.value = int(vstring[2]) + 1
116
def getVersion(self):
118
vstring.append(str(self.components.majorVersion.value))
119
vstring.append(str(self.components.minorVersion.value))
120
vstring.append(str(self.components.fixLevel.value))
123
def on_btnOK_mouseClick(self, event):
126
def on_btnCancel_mouseClick(self, event):
129
class HTMLHelp(CustomDialog):
130
"""Displays an HTML based about box"""
132
def __init__(self, aBg, links=None):
133
path = os.path.join(aBg.application.applicationDirectory, 'helpAbout')
134
aDialogRsrc = resource.ResourceFile(model.internationalResourceName(path)).getResource()
135
CustomDialog.__init__(self, aBg, aDialogRsrc)
137
#self.components.versionText.text = 'Version %s' % self.parent.pimpversion
139
# links is a 3-element list giving the HTML files to use for the About, Author
140
# and License buttons
141
if links is None: links = ['doc/about.html', 'doc/author.html', 'doc/license.html']
144
self.components.HtmlWindow.text = self.links[0]
146
def on_btnOK_mouseClick(self, event):
149
def on_AboutBtn_mouseClick(self, event):
150
self.components.HtmlWindow.text = self.links[0]
152
def on_AuthorBtn_mouseClick(self, event):
153
self.components.HtmlWindow.text = self.links[1]
155
def on_LicenseBtn_mouseClick(self, event):
156
self.components.HtmlWindow.text = self.links[2]
158
class newProjectWizard(CustomDialog):
159
"""Displays a wizard for creating a new project"""
161
def __init__(self, aBg):
162
baseResourceName = 'newProjectWizard'
163
path = os.path.join(aBg.application.applicationDirectory, baseResourceName)
164
aDialogRsrc = resource.ResourceFile(model.internationalResourceName(path)).getResource()
165
CustomDialog.__init__(self, aBg, aDialogRsrc)
169
self.addWizardPage(baseResourceName, 'Page1')
170
self.addWizardPage(baseResourceName, 'Page2')
171
self.addWizardPage(baseResourceName, 'Page3')
172
self.addWizardPage(baseResourceName, 'Page4')
176
self.accepted = False
177
self.setPage(self.pgCnt)
179
def addWizardPage(self, basename, pageref):
180
r = basename + pageref
181
resName = model.internationalResourceName(r)
182
fd = open(resName, 'r')
183
res = eval(fd.read())
184
for comp in res['components']:
185
if comp.has_key('userdata') and comp['userdata'] == pageref.lower():
186
compname = comp['name']
187
self.components[compname] = comp
189
def setPage(self, cnt, flag=True):
190
# set the currently displayed page
191
groupname = 'page' + str(cnt)
193
for compname in self.components.keys():
194
if groupname in self.components[compname].userdata:
195
self.components[compname].enabled = flag
196
self.components[compname].visible = flag
197
elif self.components[compname].userdata != '':
198
self.components[compname].enabled = not(flag)
199
self.components[compname].visible = not(flag)
203
def setButtons(self):
204
# enable the 'next' button if we have enough information to move
205
# on to the next page
207
# back button is (almost) always enabled
208
self.components.backBtn.enabled = True
211
# initial page - the back button is always disabled, the next
212
# button is always enabled
213
self.components.nextBtn.enabled = True
214
self.components.backBtn.enabled = False
217
# first page - next button is enabled if we have something in the
218
# project name field, back button is always enabled
219
self.components.backBtn.enabled = True
220
if self.components.projectName.text == '':
221
self.components.nextBtn.enabled = False
223
self.components.nextBtn.enabled = True
224
self.components.projectName.SetFocus()
227
# second page - next button is enabled if we have something in
228
# the project descrption
229
if self.components.projectDesc.text == '':
230
self.components.nextBtn.enabled = False
232
self.components.nextBtn.enabled = True
233
self.components.projectDesc.SetFocus()
236
# third page - next button is enabled if we have something in
238
if self.components.baseDir.text == '':
239
self.components.nextBtn.enabled = False
241
self.components.nextBtn.enabled = True
242
self.components.baseDir.SetFocus()
244
if self.pgCnt == self.maxPages:
245
self.components.nextBtn.label = 'Create'
247
self.components.nextBtn.label = 'Next >'
248
self.components.nextBtn.SetFocus()
250
def on_backBtn_mouseClick(self, event):
251
# got to previous page
253
self.setPage(self.pgCnt)
255
def on_nextBtn_mouseClick(self, event):
257
if self.pgCnt < self.maxPages:
259
self.setPage(self.pgCnt)
264
def on_projectName_keyUp(self, event):
265
# can't move on to the next page until something is typed into the
267
if self.components.projectName.text != '':
268
self.components.nextBtn.enabled = True
270
self.components.nextBtn.enabled = False
273
def on_projectDesc_keyUp(self, event):
274
if self.components.projectDesc.text != '':
275
self.components.nextBtn.enabled = True
277
self.components.nextBtn.enabled = False
280
def on_baseDir_keyUp(self, event):
281
if self.components.baseDir.text != '':
282
self.components.nextBtn.enabled = True
284
self.components.nextBtn.enabled = False
287
def on_baseDirBtn_mouseClick(self, event):
288
title = 'Select project base directory'
289
basepath = str(self.parent.cfg.get('ConfigData', 'projects'))
290
result = dialog.directoryDialog(self, title, basepath, wx.DD_NEW_DIR_BUTTON)
292
# need an error here if the directory selected is not a subdirectory
295
plist.append(basepath)
296
plist.append(str(result.path))
297
if os.path.commonprefix(plist) != basepath:
298
title = 'Invalid project base directory'
299
txt = 'This version of standaloneBuilder does not allow creation '
300
txt += 'of projects which reside outside of the projects directory '
301
txt += 'specified in your preferences. This issue will be addressed '
302
txt += 'in the next version. Yes, it\'s lame - sorry! :-('
303
bull = dialog.alertDialog(self, wrap_string(txt, 60), title)
304
self.components.baseDir.SetFocus()
306
self.components.baseDir.text = result.path
307
self.components.nextBtn.enabled = True
310
d = dialogs.DialogResults
311
d.accepted = self.accepted
312
d.projectName = self.components.projectName.text
313
d.projectDesc = self.components.projectDesc.text
314
d.baseDir = self.components.baseDir.text
317
def on_cancelBtn_mouseClick(self, event):
320
class prefsDialog(CustomDialog):
321
"""Displays a preferences dialog"""
323
def __init__(self, aBg, cfgfile):
324
path = os.path.join(aBg.application.applicationDirectory, 'prefsDialog')
325
aDialogRsrc = resource.ResourceFile(model.internationalResourceName(path)).getResource()
326
CustomDialog.__init__(self, aBg, aDialogRsrc)
328
self.CONFIG_FILE = cfgfile
329
#if sys.platform.startswith('win'): self.fitToComponents(10,10)
330
self.components.resEditPath.text = self.parent.cfg.get('ConfigData', 'reseditor')
331
self.components.srcEditPath.text = self.parent.cfg.get('ConfigData', 'codeeditor')
332
self.components.txtEditPath.text = self.parent.cfg.get('ConfigData', 'texteditor')
333
self.components.pixmapEditPath.text = self.parent.cfg.get('ConfigData', 'pixmapeditor')
334
self.components.installerPath.text = self.parent.cfg.get('ConfigData', 'installerpath')
335
self.components.buildTool.stringSelection = self.parent.cfg.get('ConfigData', 'buildtool')
337
if self.components.buildTool.stringSelection == 'py2exe':
338
self.components.installerPath.enabled = False
339
self.components.installerPathBtn.enabled = False
340
self.components.installerPathHelpBtn.enabled = False
342
self.components.installerPath.enabled = True
343
self.components.installerPathBtn.enabled = True
344
self.components.installerPathHelpBtn.enabled = True
346
self.components.compilerPath.text = self.parent.cfg.get('ConfigData', 'compilerpath')
347
self.components.appPublisher.text = self.parent.cfg.get('ConfigData', 'publisher')
348
self.components.projectsPath.text = self.parent.cfg.get('ConfigData', 'projects')
350
def on_buildTool_select(self, event):
351
if self.components.buildTool.stringSelection == 'py2exe':
353
from distutils.core import setup as wibble
355
title = '*** ERROR ***'
356
txt = 'You do not appear to have a copy of the distutils '
357
txt += 'package installed. This is required in order to allow '
358
txt += 'building with py2exe.'
359
bull = dialog.alertDialog(self, wrap_string(txt, 60), title)
360
self.components.buildTool.stringSelection = 'pyInstaller'
363
import py2exe as wibble
365
title = '*** ERROR ***'
366
txt = 'You do not appear to have a '
367
txt += 'copy of the py2exe package installed. Please install '
368
txt += 'the package and then re-configure your preferences.'
369
bull = dialog.alertDialog(self, wrap_string(txt, 60), title)
370
self.components.buildTool.stringSelection = 'pyInstaller'
372
self.components.installerPath.text = ''
373
self.components.installerPath.enabled = False
374
self.components.installerPathBtn.enabled = False
375
self.components.installerPathHelpBtn.enabled = False
377
self.components.installerPath.enabled = True
378
self.components.installerPathBtn.enabled = True
379
self.components.installerPathHelpBtn.enabled = True
380
# see if we can find pyInstaller
381
# C:\Python23\pyInstaller\Build.py
382
want = os.path.join('pyInstaller', 'Build.py')
383
installer = self.parent.lookFor(want)
384
#self.parent.cfg.set('ConfigData', 'installerpath', installer)
385
self.components.installerPath.text = installer
387
def on_btnOK_mouseClick(self, event):
388
if self.components.buildTool.stringSelection == 'pyInstaller':
389
if self.components.installerPath.text == '':
390
title = 'Preferences not saved!'
391
txt = 'You must specify the directory where the pyInstaller components can be found'
392
bull = dialog.alertDialog(self, wrap_string(txt, 60), title)
394
if self.components.compilerPath.text == '' and sys.platform.startswith('win'):
395
title = 'Preferences not saved!'
396
txt = 'You must specify the directory where the Inno Setup compiler can be found'
397
bull = dialog.alertDialog(self, wrap_string(txt, 60), title)
399
if self.components.projectsPath.text == '':
400
title = 'Preferences not saved!'
401
txt = 'You must specify your base projects directory'
402
bull = dialog.alertDialog(self, wrap_string(txt, 60), title)
404
self.parent.cfg.set('ConfigData', 'reseditor', self.components.resEditPath.text)
405
self.parent.cfg.set('ConfigData', 'codeeditor', self.components.srcEditPath.text)
406
self.parent.cfg.set('ConfigData', 'texteditor', self.components.txtEditPath.text)
407
self.parent.cfg.set('ConfigData', 'pixmapeditor', self.components.pixmapEditPath.text)
408
self.parent.cfg.set('ConfigData', 'installerpath', self.components.installerPath.text)
409
self.parent.cfg.set('ConfigData', 'buildtool', self.components.buildTool.stringSelection)
410
self.parent.cfg.set('ConfigData', 'compilerpath', self.components.compilerPath.text)
411
self.parent.cfg.set('ConfigData', 'publisher', self.components.appPublisher.text)
412
self.parent.cfg.set('ConfigData', 'projects', self.components.projectsPath.text)
413
fd = open(self.CONFIG_FILE, 'w')
414
self.parent.cfg.write(fd)
418
def on_btnCancel_mouseClick(self, event):
421
def on_resEditPathBtn_mouseClick(self, event):
422
result = dialog.fileDialog(self, self.components.StaticText3.text, self.components.resEditPath.text)
424
self.components.resEditPath.text = result.paths[0]
426
def on_resEditPathHelpBtn_mouseClick(self, event):
427
self.showHelp(self.components.resEditPath.userdata, self.components.StaticText3.text)
429
def on_srcEditPathBtn_mouseClick(self, event):
430
result = dialog.fileDialog(self, self.components.StaticText4.text, self.components.srcEditPath.text)
432
self.components.srcEditPath.text = result.paths[0]
434
def on_srcEditPathHelpBtn_mouseClick(self, event):
435
self.showHelp(self.components.srcEditPath.userdata, self.components.StaticText4.text)
437
def on_pixmapEditPathBtn_mouseClick(self, event):
438
result = dialog.fileDialog(self, self.components.StaticText5.text, self.components.pixmapEditPath.text)
440
self.components.pixmapEditPath.text = result.paths[0]
442
def on_pixmapEditPathHelpBtn_mouseClick(self, event):
443
self.showHelp(self.components.pixmapEditPath.userdata, self.components.StaticText5.text)
445
def on_installerPathBtn_mouseClick(self, event):
446
result = dialog.fileDialog(self, self.components.StaticText1.text, self.components.installerPath.text)
448
self.components.installerPath.text = result.paths[0]
450
def on_installerPathHelpBtn_mouseClick(self, event):
451
self.showHelp(self.components.installerPath.userdata, self.components.StaticText1.text)
453
def on_buildToolHelpBtn_mouseClick(self, event):
454
self.showHelp(self.components.buildTool.userdata, self.components.StaticText1.text)
456
def on_compilerPathBtn_mouseClick(self, event):
457
result = dialog.fileDialog(self, self.components.StaticText7.text, self.components.compilerPath.text)
459
self.components.compilerPath.text = result.paths[0]
461
def on_compilerPathHelpBtn_mouseClick(self, event):
462
self.showHelp(self.components.compilerPath.userdata, self.components.StaticText7.text)
464
def on_appPublisherHelpBtn_mouseClick(self, event):
465
self.showHelp(self.components.appPublisher.userdata, self.components.StaticText6.text)
467
def on_projectsPathBtn_mouseClick(self, event):
468
result = dialog.directoryDialog(self, self.components.StaticText2.text, self.components.projectsPath.text)
470
self.components.projectsPath.text = result.path
472
def on_projectsPathHelpBtn_mouseClick(self, event):
473
self.showHelp(self.components.projectsPath.userdata, self.components.StaticText2.text)
475
def showHelp(self, text, label):
476
text = string.replace(text, '\\n', '\n')
477
#dlg = wx.MessageDialog(self, wrap_string(text, 50), label, wx.OK|wx.ICON_INFORMATION)
478
dlg = wx.MessageDialog(self, wrap_string(text, 60), label, wx.OK)
482
class propertiesDialog(CustomDialog):
483
"""Displays the project properties dialog"""
485
def __init__(self, aBg):
486
path = os.path.join(aBg.application.applicationDirectory, 'propertiesDialog')
487
aDialogRsrc = resource.ResourceFile(model.internationalResourceName(path)).getResource()
488
CustomDialog.__init__(self, aBg, aDialogRsrc)
492
self.components.buildPath.text = self.parent.pathJoin(self.parent.project.get('Project', 'buildfilespath'))
493
self.components.distPath.text = self.parent.pathJoin(self.parent.project.get('Project', 'distfilespath'))
494
self.components.pixmapsPath.text = self.parent.pathJoin(self.parent.project.get('Project', 'pixmapspath'))
495
self.components.tarballPath.text = self.parent.pathJoin(self.parent.project.get('Project', 'tarballspath'))
496
self.components.appPublisher.text = self.parent.project.get('Project', 'publisher')
497
self.components.appURL.text = self.parent.project.get('Project', 'appurl')
498
self.components.appLicence.text = self.parent.pathJoin(self.parent.project.get('Project', 'applicence'))
499
self.components.asciiChk.checked = self.parent.project.getboolean('Project', 'ascii')
500
self.components.striplibsChk.checked = self.parent.project.getboolean('Project', 'striplib')
501
self.components.consoleChk.checked = self.parent.project.getboolean('Project', 'console') # best to have a coonsole for new projects!
502
self.components.optimizeChk.checked = self.parent.project.getboolean('Project', 'optimize')
503
self.components.compressChk.checked = self.parent.project.getboolean('Project', 'compress')
504
self.components.debugChk.checked = self.parent.project.getboolean('Project', 'debug')
505
if self.parent.project.getboolean('Project', 'onedir'):
506
self.components.buildType.stringSelection = 'Single directory'
508
self.components.buildType.stringSelection = 'Single file'
512
def on_buildPathBtn_mouseClick(self, event):
513
basepath = os.path.join(self.parent.cfg.get('ConfigData', 'projects'), self.parent.components.baseDir.text)
514
basepath = os.path.join(basepath, self.components.buildPath.text)
515
refpath = os.path.join(self.parent.cfg.get('ConfigData', 'projects'), self.parent.components.baseDir.text)
517
title = 'Select path to project build directory'
518
result = dialog.directoryDialog(self, title, basepath)
521
path = self.parent.getRelativePath(refpath, result.path)
522
self.components.buildPath.text = path
524
def on_distPathBtn_mouseClick(self, event):
525
basepath = os.path.join(self.parent.cfg.get('ConfigData', 'projects'), self.parent.components.baseDir.text)
526
basepath = os.path.join(basepath, self.components.distPath.text)
527
refpath = os.path.join(self.parent.cfg.get('ConfigData', 'projects'), self.parent.components.baseDir.text)
529
title = 'Select path to project distribution directory'
530
result = dialog.directoryDialog(self, title, basepath)
533
path = self.parent.getRelativePath(refpath, result.path)
534
self.components.distPath.text = path
536
def on_pixmapsPathBtn_mouseClick(self, event):
537
basepath = os.path.join(self.parent.cfg.get('ConfigData', 'projects'), self.parent.components.baseDir.text)
538
basepath = os.path.join(basepath, self.components.pixmapsPath.text)
539
refpath = os.path.join(self.parent.cfg.get('ConfigData', 'projects'), self.parent.components.baseDir.text)
541
title = 'Select path to project pixmaps directory'
542
result = dialog.directoryDialog(self, title, basepath)
545
path = self.parent.getRelativePath(refpath, result.path)
546
self.components.pixmapsPath.text = path
548
def on_tarballsPathBtn_mouseClick(self, event):
549
basepath = os.path.join(self.parent.cfg.get('ConfigData', 'projects'), self.parent.components.baseDir.text)
550
basepath = os.path.join(basepath, self.components.tarballsPath.text)
551
refpath = os.path.join(self.parent.cfg.get('ConfigData', 'projects'), self.parent.components.baseDir.text)
553
title = 'Select path to project tarballs directory'
554
result = dialog.directoryDialog(self, title, refpath)
557
path = self.parent.getRelativePath(refpath, result.path)
558
self.components.tarballsPath.text = path
560
def on_appLicenceBtn_mouseClick(self, event):
561
basepath = os.path.join(self.parent.cfg.get('ConfigData', 'projects'), self.parent.components.baseDir.text)
562
basepath = os.path.join(basepath, self.components.appLicence.text)
563
refpath = os.path.join(self.parent.cfg.get('ConfigData', 'projects'), self.parent.components.baseDir.text)
565
title = 'Select path to project licence file'
566
result = dialog.openFileDialog(self, title, refpath)
569
path = self.parent.getRelativePath(refpath, result.paths[0])
570
self.components.appLicence.text = path
572
def on_btnOK_mouseClick(self, event):
573
old = copy.deepcopy(self.parent.project)
574
self.parent.project.set('Project', 'buildfilespath', self.parent.pathSplit(self.components.buildPath.text))
575
self.parent.project.set('Project', 'distfilespath', self.parent.pathSplit(self.components.distPath.text))
576
self.parent.project.set('Project', 'pixmapspath', self.parent.pathSplit(self.components.pixmapsPath.text))
577
self.parent.project.set('Project', 'tarballspath', self.parent.pathSplit(self.components.tarballPath.text))
578
self.parent.project.set('Project', 'publisher', self.components.appPublisher.text)
579
self.parent.project.set('Project', 'appurl', self.components.appURL.text)
580
self.parent.project.set('Project', 'applicence', self.parent.pathSplit(self.components.appLicence.text))
581
self.parent.project.set('Project', 'ascii', str(int(self.components.asciiChk.checked)))
582
self.parent.project.set('Project', 'striplib', str(int(self.components.striplibsChk.checked)))
583
self.parent.project.set('Project', 'console', str(int(self.components.consoleChk.checked)))
584
self.parent.project.set('Project', 'optimize', str(int(self.components.optimizeChk.checked)))
585
self.parent.project.set('Project', 'compress', str(int(self.components.compressChk.checked)))
586
self.parent.project.set('Project', 'debug', str(int(self.components.debugChk.checked)))
587
if self.components.buildType.stringSelection == 'Single directory':
588
self.parent.project.set('Project', 'onedir', '1')
590
self.parent.project.set('Project', 'onedir', '0')
591
if self.parent.project != old: self.parent.documentChanged = True
594
def on_btnCancel_mouseClick(self, event):