-
Notifications
You must be signed in to change notification settings - Fork 0
/
GUI2Exe.py
4154 lines (3132 loc) · 157 KB
/
GUI2Exe.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# -*- coding: utf-8 -*-
########### GUI2Exe SVN repository information ###################
# $Date$
# $Author$
# $Revision$
# $URL$
# $Id$
########### GUI2Exe SVN repository information ###################
"""
Description
===========
GUI2Exe is a Graphical User Interface frontend to all the "executable builders"
available for the Python programming language. It can be used to build standalone
Windows executables, Linux applications and Mac OS application bundles and
plugins starting from Python scripts.
GUI2Exe is (my) first attempt to unify all the available "executable builders"
for Python in a single and simple to use graphical user interface.
GUI2Exe supports the following compilers:
* py2exe (Windows)
* py2app (Mac OS)
* PyInstaller (all platforms)
* cx_Freeze (Windows and Linux)
* bbFreeze (Windows and Linux)
* VendorID (Windows and Linux) - testers required!!
Features
========
GUI2Exe has a number of features, namely:
* Saves and stores your work in a database, displaying all your projects in a
tree control. To load an existing project, simply double click on it;
* Possibility to export the Setup.py file (menu File => Export setup file...),
even though you shouldn't ever need anymore to have a Setup.py file.
Everything is done automagically inside GUI2Exe;
* Ability to change the Python version to use to build the executable (menu
Options => Change Python version);
* Allows the user to insert custom Python code in the "in-memory" Setup.py
file, which will be properly included at runtime during the building process
(menu Options => Add custom code...);
* Allows the user to add post-processing custom code, which will be executed
at the end of the building process. Useful for cleaning up (menu Options =>
Insert post compilation code);
* Possibility to view the full build output coming from the compiler (menu
Builds => Show full build output);
* Allows the user to add data_files (for the executable builders that support
this option) either by selecting a bunch of files all together or using a
directory-recursive approach, which will include all files and sub-folders
in the selected folders as data_files (menu Options => Recurse sub-dirs for
data_files option);
* "Super" tooltips for the users to better understand the various options
(menu Options => Show tooltips);
* GUI2Exe projects can be saved also to a file (and not only in the database):
the exported project may then be checked into version control software like
CVS or SVN, modified and then reloaded into GUI2Exe (menu File => Save
project as...);
* Ability to test the executable: if the executable crashes, GUI2Exe will
notice it and report to you the traceback for inspection (menu Builds =>
Test executable);
* [py2exe-only]: After a building process, choosing the menu Builds => Missing
modules or Builds => Binary dependencies, you will be presented respectively
with a list of modules py2exe thinks are missing or a list of binary
dependencies (dlls) py2exe has found;
* [py2exe-only]: Possibility to use UPX compression on dlls/exes while compiling;
* [py2exe-only]: Automatic generation of simple Inno Setup scripts;
* [py2exe-only]: Support for more keywords in the Target class (i.e., all distutils
keywords are now supported);
* [py2exe-only]: Easy access to the most recent error log file via the menu
Builds => Examine error log file;
* Easy access to the distribution folder via the menu Builds => Open distribution
folder;
* [py2exe-only]: A new distribution folder "Explorer" dialog allows to check which
PYDs and DLLs are included, and to quickly exclude them and then rebuild the script,
with "undo" capabilities;
* [py2exe-only]: Support for services, com_servers and ctypes_com_servers (testers required!!);
* Ability to switch between standard menus and custom FlatMenus (MSW and GTK only);
* Support for a pure-Python RibbonBar in place of the standard menus (MSW only).
And much more :-D
Project information
===================
Project home page & downloads:
http://code.google.com/p/gui2exe
Bleeding edge SVN repository:
svn checkout http://gui2exe.googlecode.com/svn/trunk/ gui2exe-read-only
Project mailing list:
http://groups.google.com/group/gui2exe
Latest revision: Andrea Gavana, 07 May 2012 21.00 GMT
Version 0.5.3
"""
__author__ = "Andrea Gavana <[email protected]>, <[email protected]>"
__date__ = "01 Apr 2007, 13:15 GMT"
__version__ = "0.5.3"
__docformat__ = "epytext"
# Start the imports
import sys
import os
# Do this for MultiVersions install of wxPython
# We need to import wxversion before importing wx itself...
try:
import wxversion
wxversion.ensureMinimal("2.8")
except ImportError:
pass
# Now we can import wx
import wx
if wx.VERSION < (2, 8, 8, 0):
print "wxPython >= 2.8.8.0 is required"
sys.exit(1)
import time
sys.path.append("extern")
reload(sys)
sys.setdefaultencoding(sys.getfilesystemencoding())
del sys.setdefaultencoding
# Used to start the compiled executable
if sys.version[0:3] >= "(2,4)":
# subprocess is new in 2.4
import subprocess
import wx.lib.dialogs
# This is somehow needed by distutils, otherwise it bombs on Windows
# when you have py2App installed (!)
if wx.Platform == "__WXMAC__":
import wx.aui as aui
try:
import setuptools
except ImportError:
pass
else:
import extern.aui as aui
import extern.flatmenu as FM
import extern.ribbon as RB
# I need webbrowser for the help and tips and tricks
import webbrowser
# Used to clean up the distribution folder
import shutil
# Get the translation module
import locale
# Let's import few modules I have written for GUI2Exe
from ProjectTreeCtrl import ProjectTreeCtrl
from MessageWindow import MessageWindow
from ExecutableProperties import ExecutableProperties
from AUINotebookPage import AUINotebookPage
from GenericMessageDialog import GenericMessageDialog
from DataBase import DataBase
from Project import Project
from Process import Process
from Widgets import CustomCodeViewer, Py2ExeMissing, PyBusyInfo, BuildDialog, PreferencesDialog
from Widgets import ExceptionHook, ExplorerDialog, VendorIDDialog, ProgressGauge
from Utilities import GetLangId, GetAvailLocales, now, CreateBitmap, ColourClientData
from Utilities import opj, odict, PrintTree, ConnectionThread, GetLabelWithoutAccelerator
from Utilities import AddOverlay
from Constants import _auiImageList, _pywildspec, _defaultCompilers, _manifest_template, _pywild
from AllIcons import catalog
# And import the fancy AdvancedSplash
import AdvancedSplash as AS
# I need this for restorable perspectives:
ID_FirstPerspective = wx.ID_HIGHEST + 10000
# Some ids to avoid using FindMenu...
ID_CleanDist = ID_FirstPerspective + 2000
ID_DeleteBuild = ID_CleanDist + 1
ID_ShowTip = ID_CleanDist + 2
ID_Recurse = ID_CleanDist + 3
ID_Missing = ID_CleanDist + 4
ID_AutoSave = ID_CleanDist + 5
ID_UPX = ID_CleanDist + 6
ID_Inno = ID_CleanDist + 7
ID_Modern = ID_CleanDist + 8
ID_Classic = ID_CleanDist + 9
ID_Top = ID_CleanDist + 10
ID_Bottom = ID_CleanDist + 11
ID_NB_Default = ID_CleanDist + 12
ID_NB_FF2 = ID_CleanDist + 13
ID_NB_VC71 = ID_CleanDist + 14
ID_NB_VC8 = ID_CleanDist + 15
ID_NB_Chrome = ID_CleanDist + 16
ID_Explorer = ID_CleanDist + 17
ID_ExportSetup = ID_CleanDist + 18
ID_AddCustom = ID_CleanDist + 19
ID_AddPost = ID_CleanDist + 20
ID_TestExe = ID_CleanDist + 21
ID_ViewSetup = ID_CleanDist + 22
ID_TestSetup = ID_CleanDist + 23
ID_ShowBuild = ID_CleanDist + 24
ID_ExamineLog = ID_CleanDist + 25
ID_BinaryDependencies = ID_CleanDist + 26
ID_Distribution = ID_CleanDist + 27
ID_SaveProject = ID_CleanDist + 28
ID_SaveProjectAs = ID_CleanDist + 29
ID_UseFlatMenu = ID_CleanDist + 30
ID_UseNormalMenu = ID_CleanDist + 31
ID_UseRibbonBar = ID_CleanDist + 32
ID_SetVendorID = ID_CleanDist + 33
ID_SetPyInstaller = ID_CleanDist + 34
ID_RelativePaths = ID_CleanDist + 35
ID_ChangePython = ID_CleanDist + 36
ID_SwitchDatabase = ID_CleanDist + 37
ID_SaveConfig = ID_CleanDist + 38
ID_API = ID_CleanDist + 39
ID_Compilers = ID_CleanDist + 40
ID_Tips = ID_CleanDist + 41
ID_Upgrade = ID_CleanDist + 42
ID_Translate = ID_CleanDist + 43
ID_Contact = ID_CleanDist + 44
ID_DOCKING = ID_CleanDist + 45
ID_NOTEBOOK1 = ID_CleanDist + 46
ID_NOTEBOOK2 = ID_CleanDist + 47
ID_MENU = ID_CleanDist + 48
ID_AUI_Provider = ID_CleanDist + 49
ID_MSW_Provider = ID_CleanDist + 50
ID_PRIMARY_COLOUR = ID_CleanDist + 51
ID_SECONDARY_COLOUR = ID_CleanDist + 52
ID_PERSPECTIVES = ID_CleanDist + 53
# Some ids for the popup menu on tabs (GTK and MSW only)
ID_CloseTab = ID_CleanDist + 54
ID_CloseAllTabs = ID_CleanDist + 55
ID_SaveProject = ID_CleanDist + 56
ID_SaveAllProjects = ID_CleanDist + 57
# Define a translation class
class _(unicode):
def __new__(cls, original=''):
new = unicode.__new__(cls, wx.GetTranslation(original))
new.original = original
return new
# It looks like that, while py2exe and py2app are installed on site-packages
# (or at least you can actually __import__ them), for the other 2 beasts
# is far more complicated, at least on Windows
def ImportCompilers():
""" Simple function that imports the available compilers (if any). """
compilers = odict()
for compiler in _defaultCompilers:
try:
module = __import__(compiler)
compilers[compiler] = module.__version__
except ImportError:
# No compiler, no party
pass
except AttributeError:
try:
compilers[compiler] = module.version
except:
# cx_Freeze has no version number in its installation
# Hey developer, what about adding a __version__
# attribute to cx_Freeze? It's not rocket science...
compilers[compiler] = "(No version)"
except: # any other error
pass
return compilers
# Ok, now get the compilers...
_compilers = ImportCompilers()
class GUI2Exe(wx.Frame):
""" Main wx.Frame class for our application. """
def __init__(self, parent, id=-1, title="", pos=wx.DefaultPosition, size=wx.DefaultSize,
style=wx.DEFAULT_FRAME_STYLE):
"""
Default wx.Frame class constructor.
**Parameters:**
* `parent`: The window parent. This may be NULL. If it is non-NULL, the frame will
always be displayed on top of the parent window on Windows
* `id`: The window identifier. It may take a value of -1 to indicate a default value
* `title`: The caption to be displayed on the frame's title bar
* `pos`: The window position. A value of (-1, -1) indicates a default position, chosen
by either the windowing system or wxWidgets, depending on platform
* `size`: The window size. A value of (-1, -1) indicates a default size, chosen by either
the windowing system or wxWidgets, depending on platform
* `style`: the frame style. See ``wx.Frame`` for possible styles.
"""
wx.Frame.__init__(self, parent, id, title, pos, size, style)
# Yes, I know, I am obsessively addicted to wxAUI
self._mgr = aui.AuiManager()
self._mgr.SetManagedWindow(self)
# Some default starting values for our class
# where are we
self.installDir = wx.GetApp().GetInstallDir()
self.autoSave = True # use autoSave?
self.deleteBuild = True # delete the "build" directory (recommended)
self.cleanDist = False # Clean up the "dist" directory
self.process = None # keeps track of the compilation subprocess
self.exeTimer = wx.Timer(self) # I use that to monitor exe failures
self.timerCount = 0 # same as above
self.processTimer = wx.Timer(self) # used to monitor the external process
self.gaugeTimer = wx.Timer(self) # Used to update the progress bar in the notebook tab
self.pythonVersion = sys.executable # Default Python executable
self.pyInstallerPath = None # Where PyInstaller lives
self.sibPath = ("", "make") # Where VendorID sib.py lives and whether to use GNU Make or MS NMake
self.recurseSubDirs = False # Recurse sub-directories for the data_files option
self.showTips = True # Show tooltips for various compiler options
self.relativePaths = False # Use relative paths instead of absolute ones for data_files, icon_resources etc...
self.currentTab = None
self._fmb = None
# To store the aui perspectives
self.perspectives = []
self.perspectives_names = []
# To periodically save opened projects
self.autosaveTimer = wx.Timer(self, wx.ID_ANY)
# Create the status bar
self.CreateBar()
# Set frame properties (title, icon...)
self.SetProperties()
self.menu_choice = wx.GetApp().GetPreferences("Use_Custom_Menu", default=0)
# Create the menu bar (lots of code, mostly always the same)
self.CreateMenuBar()
if wx.Platform != "__WXMAC__":
# Add a FlatMenuBar as an option instead of the menubar
self.CreateFlatMenuBar()
if wx.Platform == "__WXMSW__":
self.BuildRibbonBar()
self.CreateAUIRibbonBar()
# Build the aui.AuiNotebook image list
# But why in the world is so different from wx.Notebook???
self.BuildNBImageList()
# Look if there already exists a database for GUI2Exe
dbName = self.CheckForDatabase()
# This is the left CustomTreeCtrl that holds all our projects
self.projectTree = ProjectTreeCtrl(self)
# This is the main window, the central pane
nbStyle = aui.AUI_NB_DEFAULT_STYLE|aui.AUI_NB_WINDOWLIST_BUTTON
if wx.Platform != "__WXMAC__":
nbStyle += aui.AUI_NB_TAB_FLOAT + aui.AUI_NB_DRAW_DND_TAB
nbStyle = wx.GetApp().GetPreferences("Notebook_Style", default=nbStyle)
self.notebook_style = nbStyle
self.mainPanel = aui.AuiNotebook(self, -1, style=nbStyle)
# Let's be fancy and add a special logging window
self.messageWindow = MessageWindow(self)
# Add a small panel to show the executable properties
self.executablePanel = ExecutableProperties(self)
# Call the database. This actually populates the project tree control
self.dataBase = DataBase(self, dbName)
# Check if we had a very hard crash (irreversible)
if self.dataBase.hasError:
strs = _("The database file and its backup seem to be broken.\n\n" \
"Please go to the /USER/Application Data/.GUI2Exe/ folder\n" \
"and delete the GUI2Exe database file.")
self.RunError(2, strs)
self.Destroy()
return
# Add the panes to the wxAUI manager
# Very nice the bug introduced in wxPython 2.8.3 about wxAUI Maximize buttons...
self._mgr.AddPane(self.projectTree, aui.AuiPaneInfo().Left().
Caption(_("GUI2Exe Projects")).MinSize(wx.Size(250, -1)).
FloatingSize(wx.Size(200, 300)).Layer(1).MaximizeButton().
Name("GUI2ExeProjects").MinimizeButton())
self._mgr.AddPane(self.executablePanel, aui.AuiPaneInfo().Left().
Caption(_("Executable Properties")).MinSize(wx.Size(200, 100)).
BestSize(wx.Size(200, size[1]/6)).MaxSize(wx.Size(200, 100)).
FloatingSize(wx.Size(200, 200)).Layer(1).Position(1).MaximizeButton().
Name("ExecutableProperties").MinimizeButton())
self._mgr.GetPane(self.executablePanel).dock_proportion = 100000/4
self._mgr.AddPane(self.mainPanel, aui.AuiPaneInfo().CenterPane().Name("MainPanel"))
self._mgr.AddPane(self.messageWindow, aui.AuiPaneInfo().Bottom().
Caption(_("Messages And Actions")).MinSize(wx.Size(200, 100)).
FloatingSize(wx.Size(500, 300)).BestSize(wx.Size(200, size[1]/6)).
MaximizeButton().Name("MessagesAction").MinimizeButton())
# Set all the flags for wxAUI
self.SetAllFlags()
# Bind the main frame events
self.BindEvents()
# Save the current perspective to be reloaded later if requested
self.perspectives.append(self._mgr.SavePerspective())
# Update the wxAUI manager
self._mgr.Update()
# Sort the tree children
self.projectTree.SortItems()
# Read the default configuration file.
self.ReadConfigurationFile()
# Disable the Run and Dry-Run buttons
self.messageWindow.NoPagesLeft(False)
# Apply the user preferences
wx.CallAfter(self.ApplyPreferences)
transdict = dict(dateAndTime=now())
self.SendMessage(0, _("GUI2Exe succesfully started at %(dateAndTime)s")%transdict)
# ================================== #
# GUI2Exe methods called in __init__ #
# ================================== #
def CreateBar(self):
""" Creates the GUI2Exe status bar. """
# Come on, let's see how fast the menubar is able to delete the text
# I have in the status bar...
self.statusBar = self.CreateStatusBar(2, wx.ST_SIZEGRIP)
self.statusBar.SetStatusWidths([-1, -2])
self.FillStatusBar()
def MenuData(self):
""" Handles all the information used to build the menu bar. """
# That's really a bunch of data...
return ((_("&File"),
(_("&New project...")+"\tCtrl+N", _("Add a new project to the project tree"), "project", wx.ID_NEW, self.OnNewProject, "",
[_("File Options"), 0, ""]),
("", "", "", "", "", "", ""),
(_("&Save project") + "\tCtrl+S", _("Save the current project to database"), "save_project", ID_SaveProject, self.OnSaveProject, "",
[_("File Options"), 0, ""]),
(_("&Save project as...")+"\tCtrl+Shift+S", _("Save the current project to a file"), "save_to_file", ID_SaveProjectAs, self.OnExportProject, "",
[_("File Options"), 0, ""]),
("", "", "", "", "", "", ""),
(_("&Export setup file...")+"\tCtrl+E", _("Export the Setup.py file"), "export_setup", ID_ExportSetup, self.OnExportSetup, "",
[_("Export"), 0, ""]),
("", "", "", "", "", "", ""),
(_("Switch project &database...")+"\tCtrl+D", _("Load another GUI2Exe database file"), "switch_db", ID_SwitchDatabase, self.OnSwitchDB, "",
[_("Database"), 0, ""]),
("", "", "", "", "", "", ""),
(_("&Quit") + "\tCtrl+Q", _("Exit GUI2Exe"), "exit", wx.ID_EXIT, self.OnClose, "",
[_("Quit"), 0, ""])),
(_("&Options"),
(_("Use &AutoSave"), _("AutoSaves your work every minute"), "", ID_AutoSave, self.OnAutoSave, wx.ITEM_CHECK,
[_("Autosave"), 0, "autosave"]),
("", "", "", "", "", "", ""),
(_('De&lete "build" directory'), _("Delete the build folder at every compilation"), "", ID_DeleteBuild, self.OnDeleteBuild, wx.ITEM_CHECK,
[_("Dist Folders"), 0, "builddir"]),
(_('Clea&n "dist" directory'), _("Clean the distribution folder at every compilation"), "", ID_CleanDist, self.OnCleanDist, wx.ITEM_CHECK,
[_("Dist Folders"), 0, "distdir"]),
("", "", "", "", "", "", ""),
(_("&Recurse sub-dirs for data_files option"), _("Recurse sub-directories for data_files option if checked"), "", ID_Recurse, self.OnRecurseSubDir, wx.ITEM_CHECK,
[_("Folders"), 0, "recurse"]),
(_("Show t&ooltips"), _("show tooltips for the various compiler options"), "", ID_ShowTip, self.OnShowTip, wx.ITEM_CHECK,
[_("Tooltips"), 0, "tooltips"]),
("", "", "", "", "", "", ""),
(_("Change &Python version...") + "\tCtrl+H", _("Temporarily changes the Python version"), "python_version", ID_ChangePython, self.OnChangePython, "",
[_("Python"), 0, ""]),
("", "", "", "", "", "", ""),
(_("Set P&yInstaller path...") + "\tCtrl+Y", _("Sets the PyInstaller installation path"), "PyInstaller_small", ID_SetPyInstaller, self.OnSetPyInstaller, "",
[_("Builders Path"), 0, ""]),
(_("Set &VendorID path...") + "\tCtrl+V", _("Sets the VendorID sib.py installation path"), "VendorID_small", ID_SetVendorID, self.OnSetVendorID, "",
[_("Builders Path"), 0, ""]),
("", "", "", "", "", "", ""),
(_("Use &relative paths") + "\tCtrl+T", _("Use relative paths instead of absolute ones in data_files, icon_resources etc..."), "", ID_RelativePaths, self.OnRelativePaths, wx.ITEM_CHECK,
[_("Folders"), 0, "path"]),
("", "", "", "", "", "", ""),
(_("Add &custom code...")+"\tCtrl+U", _("Add custom code to the setup script"), "custom_code", ID_AddCustom, self.OnCustomCode, "",
[_("Customization"), 0, ""]),
(_("&Insert post compilation code...")+"\tCtrl+I", _("Add custom code to be executed after the building process"), "post_compile", ID_AddPost, self.OnPostCompilationCode, "",
[_("Customization"), 0, ""]),
("", "", "", "", "", "", ""),
(_('Use &UPX compression'), _("Uses UPX compression on dlls when available (Py2exe only)"), "", ID_UPX, self.OnUseUPX, wx.ITEM_CHECK,
[_("UPX"), 0, "upx"]),
(_('Create Inno &Setup Script'), _("Creates and compiles a simple Inno Setup script (Py2exe only)"), "", ID_Inno, self.OnInno, wx.ITEM_CHECK,
[_("Inno Setup"), 0, "inno"]),
("", "", "", "", "", "", ""),
(_("Preferences..."), _("Edit preferences/settings"), "preferences", wx.ID_PREFERENCES, self.OnPreferences, "",
[_(""), 0, ""])),
(_("&Builds"),
(_("&Test executable") + "\tCtrl+R", _("Test the compiled file (if it exists)"), "runexe", ID_TestExe, self.OnTestExecutable, "",
[_("Tests"), 0, ""]),
("", "", "", "", "", "", ""),
(_("View &setup script") + "\tCtrl+P", _("View the auto-generated setup script"), "view_setup", ID_ViewSetup, self.OnViewSetup, "",
[_("Setup Scripts"), 0, ""]),
(_("&Check setup script syntax") + "\tCtrl+X", _("Check the syntax of the auto-generated setup script"), "spellcheck", ID_TestSetup, self.OnCheckSyntax, "",
[_("Setup Scripts"), 0, ""]),
("", "", "", "", "", "", ""),
(_("Show &full build output")+"\tCtrl+F", _("View the full build output for the current compiler"), "full_build", ID_ShowBuild, self.OnViewFullBuild, "",
[_("Executables"), 0, ""]),
("", "", "", "", "", "", ""),
(_("&Examine error log file")+"\tCtrl+L", _("Shows the most recent error log file for the executable"), "log_file", ID_ExamineLog, self.OnShowLog, "",
[_("Executables"), 0, ""]),
(_("&Open distribution folder")+"\tCtrl+Shift+O", _("Opens the distribution folder"), "dist_folder", ID_Distribution, self.OnOpenDist, "",
[_("Executables"), 0, ""]),
("", "", "", "", "", "", ""),
(_("&Explorer")+"\tCtrl+Shift+E", _("Distribution folder explorer to check DLLs and PYDs"), "explorer", ID_Explorer, self.OnExplorer, "",
[_(""), 0, ""]),
("", "", "", "", "", "", ""),
(_("&Missing modules") + "\tCtrl+M", _("What the compiler thinks are the missing modules (py2exe only)"), "missingmodules", ID_Missing, self.OnViewMissing, "",
[_("Binaries"), 0, ""]),
(_("&Binary dependencies") + "\tCtrl+B", _("What the compiler says are the binary dependencies (py2exe only)"), "binarydependencies", ID_BinaryDependencies, self.OnViewMissing, "",
[_("Binaries"), 0, ""])),
(_("&View"),
(_("Save &panes configuration..."), _("Save the current GUI panes configuration"), "save_aui_config", ID_SaveConfig, self.OnSaveConfig, "",
[_("GUI Appearance"), 0, ""]),
(_("Restore original &GUI") + "\tCtrl+G", _("Restore the original GUI appearance"), "restore_aui", ID_FirstPerspective, self.OnRestorePerspective, "",
[_("GUI Appearance"), 0, ""])),
(_("&Help"),
(_("GUI2Exe &help") + "\tF1", _("Opens the GUI2Exe help"), "help2", wx.ID_HELP, self.OnHelp, "",
[_("API And Help"), 0, ""]),
(_("GUI2Exe &API") + "\tF2", _("Opens the GUI2Exe API reference"), "api_reference", ID_API, self.OnAPI, "",
[_("API And Help"), 0, ""]),
("", "", "", "", "", "", ""),
(_("Compiler s&witches") + "\tF3", _("Show compilers switches and common options"), "compiler_switches", ID_Compilers, self.OnCompilerSwitches, "",
[_("Compilers"), 0, ""]),
(_("&Tips and tricks") + "\tF4", _("Show compilation tips and tricks"), "tips_and_tricks", ID_Tips, self.OnTipsAndTricks, "",
[_("Compilers"), 0, ""]),
("", "", "", "", "", "", ""),
(_("Check for &upgrade") + "\tF9", _("Check for a GUI2Exe upgrade"), "upgrade", ID_Upgrade, self.OnCheckUpgrade, "",
[_("GUI2Exe"), 0, ""]),
(_("Translate &GUI2Exe") + "\tF10", _("Help translating GUI2Exe in your language!"), "translate", ID_Translate, self.OnTranslate, "",
[_("GUI2Exe"), 0, ""]),
("", "", "", "", "", "", ""),
(_("&Contact the Author..."), _("Contact Andrea Gavana by e-mail"), "contact", ID_Contact, self.OnContact, "",
[_("GUI2Exe"), 0, ""]),
(_("&About GUI2Exe..."), _("About GUI2Exe and the Creator..."), "about", wx.ID_ABOUT, self.OnAbout, "",
[_("About"), 0, ""])))
def HasRibbon(self):
""" Returns whether GUI2Exe supports the RibbonBar (MSW only at the moment). """
return wx.Platform == "__WXMSW__"
def HasFlatMenu(self):
""" Returns whether GUI2Exe supports the FlatMenuBar (MSW and GTK only at the moment). """
return self._fmb is not None
def BuildRibbonBar(self):
""" Builds a RibbonBar for GUI2Exe. """
menuData = self.MenuData()
self._ribbon = RB.RibbonBar(self, wx.ID_ANY)
self.ribbonChecks1 = {ID_AutoSave: [self.autoSave],
ID_CleanDist: [self.cleanDist],
ID_DeleteBuild: [self.deleteBuild],
ID_ShowTip: [self.showTips],
ID_Recurse: [self.recurseSubDirs],
ID_UPX: [False],
ID_Inno: [False],
ID_MSW_Provider: [False],
ID_AUI_Provider: [False],
ID_RelativePaths: [self.relativePaths]}
self.ribbonChecks2 = {"AutoSave": ID_AutoSave,
"Clean_Dist": ID_CleanDist,
"Delete_Build": ID_DeleteBuild,
"Show_Tooltips": ID_ShowTip,
"Recurse_Subdirs": ID_Recurse,
"Use_Relative_Paths": ID_RelativePaths}
# loop over the bunch of data above
for eachMenuData in self.MenuData():
menuLabel = eachMenuData[0]
menuItems = eachMenuData[1:]
label = menuLabel.original.strip("&")
tab = RB.RibbonPage(self._ribbon, wx.ID_ANY, label, self.CreateBitmap(label))
addedPanels = []
for eachLabel, eachStatus, eachIcon, eachId, eachHandler, eachKind, ribbonData in menuItems:
if not ribbonData:
continue
panelName, isDropDown, customBmp = ribbonData
panelIcon = (eachIcon and [eachIcon] or [customBmp])[0]
if panelName:
if panelName not in addedPanels:
panel = RB.RibbonPanel(tab, wx.ID_ANY, panelName, self.CreateBitmap(panelIcon+"32"))
addedPanels.append(panelName)
buttonBar = RB.RibbonButtonBar(panel)
else:
panelName = GetLabelWithoutAccelerator(eachLabel)
panel = RB.RibbonPanel(tab, wx.ID_ANY, panelName, self.CreateBitmap(panelIcon+"32"))
buttonBar = RB.RibbonButtonBar(panel)
if eachId == ID_FirstPerspective:
self.configMenuRibbon = tab
bmp = (customBmp and [customBmp] or [eachIcon])[0]
label = GetLabelWithoutAccelerator(eachLabel)
bmp2 = self.CreateBitmap(bmp)
bmp1 = self.CreateBitmap(bmp+"32")
if eachKind in [wx.ITEM_NORMAL, ""]:
buttonBar.AddSimpleButton(eachId, label, bmp1, bmp2)
else:
bmp3 = self.CreateBitmap(bmp + "checked32")
bmp4 = self.CreateBitmap(bmp + "checked")
button = buttonBar.AddCheckButton(eachId, label, bmp1, bmp2, bmp3, bmp4)
self.ribbonChecks1[eachId].append(button)
# Bind the event
self.Bind(RB.EVT_RIBBONBUTTONBAR_CLICKED, eachHandler, id=eachId)
gui_layout_panel = self.configMenuRibbon.GetChildren()[0]
gui_layout_bar = gui_layout_panel.GetChildren()[0]
gui_layout_bar.AddDropdownButton(ID_PERSPECTIVES, _("Perspectives"), self.CreateBitmap("perspectives"))
self.Bind(RB.EVT_RIBBONBUTTONBAR_DROPDOWN_CLICKED, self.OnRestorePerspectiveRibbon, id=ID_PERSPECTIVES)
self._ribbon.Realize()
max_size = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_X)
pn = aui.AuiPaneInfo()
pn.Name("RibbonBar")
pn.Top()
pn.MinSize(wx.Size(max_size/2, self._ribbon.GetBestSize().height))
pn.LeftDockable(False)
pn.RightDockable(False)
pn.ToolbarPane()
pn.BestSize(wx.Size(max_size, self._ribbon.GetBestSize().height))
pn.Gripper(False)
pn.Resizable(False)
self._mgr.AddPane(self._ribbon, pn)
def SetRibbonChecks(self):
""" Checks/Unchecks the ribbon items. """
if not self.HasRibbon():
return
for ids, items in self.ribbonChecks1.items():
value, button = items
button.Check(value)
self._ribbon.Refresh()
def CreateMenu(self, menuData, flat=False):
"""
Creates a menu based on input menu data.
**Parameters:**
* `menuData`: the menu item label, bitmap, longtip etc...
* `flat`: whether it is a FlatMenu or a standard wx.Menu.
"""
Menu = (flat and [FM.FlatMenu()] or [wx.Menu()])[0]
MenuItem = (flat and [FM.FlatMenuItem] or [wx.MenuItem])[0]
event = (flat and [FM.EVT_FLAT_MENU_SELECTED] or [wx.EVT_MENU])[0]
# Here is a bit trickier than what presented in Robin and Noel book,
# but not that much.
for eachLabel, eachStatus, eachIcon, eachId, eachHandler, eachKind, dummy in menuData:
if not eachLabel:
Menu.AppendSeparator()
continue
# There are also few check menu items around...
kind = (eachKind and [eachKind] or [wx.ITEM_NORMAL])[0]
menuItem = MenuItem(Menu, eachId, eachLabel, eachStatus, kind=kind)
if eachIcon:
# Check menu items usually don't have associated icons
menuItem.SetBitmap(self.CreateBitmap(eachIcon))
Menu.AppendItem(menuItem)
if eachId == ID_DeleteBuild:
# By default the "remove build directory" is on
menuItem.Check(True)
if eachId == ID_ShowTip:
# By default we activate the tooltips, unless in the wx.Config
# it's set to False
menuItem.Check(True)
# Only store the meaningful menus...
if eachId == ID_FirstPerspective:
if flat:
self.configMenuFlat = Menu
else:
self.configMenu = Menu
# Bind the event
self.Bind(event, eachHandler, menuItem)
return Menu
def AUIMenuData(self):
"""
Handles all the information used to build the additional menus in the menu bar.
(Windows and GTK only).
"""
menuData = (((_("&Docking style"), _("Changes the docking style"), "docking", "", "", ID_DOCKING, "", self.OnDockingRibbon),
((_("&Modern style"), _("Modern docking style"), ID_Modern, self.OnDocking, wx.ITEM_RADIO),
(_("&Classic style"), _("Classic docking style"), ID_Classic, self.OnDocking, wx.ITEM_RADIO))),
((_("&Notebook style"), _("Changes the notebook style"), "notebook", "notebook2", _("Tabs style"), ID_NOTEBOOK1,
ID_NOTEBOOK2, self.OnNotebookRibbon),
((_("Tabs at &top"), _("Notebook tabs are shown at the top"), ID_Top, self.OnNotebook, wx.ITEM_RADIO),
(_("Tabs at &bottom"), _("Notebook tabs are shown at the bottom"), ID_Bottom, self.OnNotebook, wx.ITEM_RADIO),
("", "", "", "", ""),
(_("&Default tab style"), _("Default style for notebook tabs"), ID_NB_Default, self.OnNotebook, wx.ITEM_RADIO),
(_("&Firefox 2 tab style"), _("Firefox 2 style for notebook tabs"), ID_NB_FF2, self.OnNotebook, wx.ITEM_RADIO),
(_("&VC71 tab style"), _("Visual Studio 2003 style for notebook tabs"), ID_NB_VC71, self.OnNotebook, wx.ITEM_RADIO),
(_("VC8 Tab tab &style"), _("Visual Studio 2005 style for notebook tabs"), ID_NB_VC8, self.OnNotebook, wx.ITEM_RADIO),
(_("&Chrome tab style"), _("Google Chrome style for notebook tabs"), ID_NB_Chrome, self.OnNotebook, wx.ITEM_RADIO))),
((_("&Menu choice"), _("Changes the menu appearance between standard menu and FlatMenu"), "menu", "", "", ID_MENU, "", self.OnMenuRibbon),
((_("&Standard menu style"), _("Standard (platform-based) menu"), ID_UseNormalMenu, self.OnMenu, wx.ITEM_RADIO),
(_("&FlatMenu style"), _("FlatMenu style"), ID_UseFlatMenu, self.OnMenu, wx.ITEM_RADIO),
(_("&RibbonBar style"), _("RibbonBar style"), ID_UseRibbonBar, self.OnMenu, wx.ITEM_RADIO)))
)
return menuData
def CreateAUIMenu(self, flat):
"""
Creates additional menus under 'View' to personalize the AUI settings (GTK and MSW only).
**Parameters:**
* `flat`: whether it is a FlatMenu or a standard wx.Menu.
"""
Menu = (flat and [FM.FlatMenu] or [wx.Menu])[0]
MenuItem = (flat and [FM.FlatMenuItem] or [wx.MenuItem])[0]
event = (flat and [FM.EVT_FLAT_MENU_SELECTED] or [wx.EVT_MENU])[0]
configMenu = (flat and [self.configMenuFlat] or [self.configMenu])[0]
menuData = self.AUIMenuData()
for indx, top in enumerate(menuData):
father, data = top
title, helpString, bmp1, bmp2, title2, id1, id2, ribbonHandler = father
# Add sub-menu to main menu
menu = Menu()
bmp = self.CreateBitmap(bmp1)
item = MenuItem(configMenu, wx.ID_ANY, title, helpString, wx.ITEM_NORMAL, menu)
item.SetBitmap(bmp)
configMenu.InsertItem(indx, item)
for subData in data:
eachLabel, eachStatus, eachId, eachHandler, eachKind = subData
if not eachLabel:
menu.AppendSeparator()
continue
item = MenuItem(menu, eachId, eachLabel, eachStatus, eachKind)
menu.AppendItem(item)
self.Bind(event, eachHandler, id=eachId)
configMenu.InsertSeparator(2)
configMenu.InsertSeparator(4)
def CreateAUIRibbonBar(self):
"""
Creates additional menus under 'View' tab to personalize the AUI settings (MSW only).
"""
self._bitmap_creation_dc = wx.MemoryDC()
self._colour_data = wx.ColourData()
menuData = self.AUIMenuData()
for indx, top in enumerate(menuData):
father, data = top
title, helpString, bmp1, bmp2, title2, id1, id2, ribbonHandler = father
panelName = GetLabelWithoutAccelerator(father[0].split()[0])
handler = data[0][3]
# Add sub-menu to main menu
bmpa = self.CreateBitmap(bmp1)
bmpb = self.CreateBitmap(bmp1+"32")
panel = RB.RibbonPanel(self.configMenuRibbon, wx.ID_ANY, panelName, bmpb)
buttonBar = RB.RibbonButtonBar(panel)
buttonBar.AddDropdownButton(id1, panelName, bmpb, bmpa)
# Bind the event
self.Bind(RB.EVT_RIBBONBUTTONBAR_DROPDOWN_CLICKED, ribbonHandler, id=id1)
if title2:
bmpa = self.CreateBitmap(bmp2)
bmpb = self.CreateBitmap(bmp2+"32")
buttonBar.AddDropdownButton(id2, title2, bmpb, bmpa)
# Bind the event
self.Bind(RB.EVT_RIBBONBUTTONBAR_DROPDOWN_CLICKED, ribbonHandler, id=id2)
provider_panel = RB.RibbonPanel(self.configMenuRibbon, wx.ID_ANY, "Ribbon Art", style=RB.RIBBON_PANEL_NO_AUTO_MINIMISE)
provider_bar = RB.RibbonButtonBar(provider_panel, wx.ID_ANY)
bmp1, bmp2 = self.CreateBitmap("aui_style32"), self.CreateBitmap("aui_style")
bmp3, bmp4 = self.CreateBitmap("aui_stylechecked32"), self.CreateBitmap("aui_stylechecked")
btn1 = provider_bar.AddCheckButton(ID_AUI_Provider, "AUI Provider", bmp1, bmp2, bmp3, bmp4)
bmp1, bmp2 = self.CreateBitmap("msw_style32"), self.CreateBitmap("msw_style")
bmp3, bmp4 = self.CreateBitmap("msw_stylechecked32"), self.CreateBitmap("msw_stylechecked")
btn2 = provider_bar.AddCheckButton(ID_MSW_Provider, "MSW Provider", bmp1, bmp2, bmp3, bmp4)
self.ribbonChecks1[ID_MSW_Provider].append(btn2)
self.ribbonChecks1[ID_AUI_Provider].append(btn1)
self._default_primary, self._default_secondary, self._default_tertiary = self._ribbon.GetArtProvider().GetColourScheme(1, 1, 1)
primary_panel = RB.RibbonPanel(self.configMenuRibbon, wx.ID_ANY, "Primary Colour", self.CreateBitmap("colourscheme"))
self._primary_gallery = self.PopulateColoursPanel(primary_panel, self._default_primary, ID_PRIMARY_COLOUR)
secondary_panel = RB.RibbonPanel(self.configMenuRibbon, wx.ID_ANY, "Secondary Colour", self.CreateBitmap("colourscheme"))
self._secondary_gallery = self.PopulateColoursPanel(secondary_panel, self._default_secondary, ID_SECONDARY_COLOUR)
self._ribbon.Realize()
def PopulateColoursPanel(self, panel, defc, gallery_id):
"""
Populates the primary and secondary colours for the RibbonBar.
**Parameters:**
* `panel`: the gallery parent (a RibbonPanel);
* `defc`: a default colour name (if any);
* `gallery_id`: the gallery id.
"""
gallery = wx.FindWindowById(gallery_id, panel)
if gallery:
gallery.Clear()
else:
gallery = RB.RibbonGallery(panel, gallery_id)
dc = self._bitmap_creation_dc
def_item = self.AddColourToGallery(gallery, "Default", dc, defc)
gallery.SetSelection(def_item)
self.AddColourToGallery(gallery, "BLUE", dc)
self.AddColourToGallery(gallery, "BLUE VIOLET", dc)
self.AddColourToGallery(gallery, "BROWN", dc)
self.AddColourToGallery(gallery, "CADET BLUE", dc)
self.AddColourToGallery(gallery, "CORAL", dc)
self.AddColourToGallery(gallery, "CYAN", dc)
self.AddColourToGallery(gallery, "DARK GREEN", dc)
self.AddColourToGallery(gallery, "DARK ORCHID", dc)
self.AddColourToGallery(gallery, "FIREBRICK", dc)
self.AddColourToGallery(gallery, "GOLD", dc)
self.AddColourToGallery(gallery, "GOLDENROD", dc)
self.AddColourToGallery(gallery, "GREEN", dc)
self.AddColourToGallery(gallery, "INDIAN RED", dc)
self.AddColourToGallery(gallery, "KHAKI", dc)
self.AddColourToGallery(gallery, "LIGHT BLUE", dc)
self.AddColourToGallery(gallery, "LIME GREEN", dc)
self.AddColourToGallery(gallery, "MAGENTA", dc)
self.AddColourToGallery(gallery, "MAROON", dc)
self.AddColourToGallery(gallery, "NAVY", dc)
self.AddColourToGallery(gallery, "ORANGE", dc)
self.AddColourToGallery(gallery, "ORCHID", dc)
self.AddColourToGallery(gallery, "PINK", dc)
self.AddColourToGallery(gallery, "PLUM", dc)
self.AddColourToGallery(gallery, "PURPLE", dc)
self.AddColourToGallery(gallery, "RED", dc)
self.AddColourToGallery(gallery, "SALMON", dc)
self.AddColourToGallery(gallery, "SEA GREEN", dc)
self.AddColourToGallery(gallery, "SIENNA", dc)
self.AddColourToGallery(gallery, "SKY BLUE", dc)
self.AddColourToGallery(gallery, "TAN", dc)
self.AddColourToGallery(gallery, "THISTLE", dc)
self.AddColourToGallery(gallery, "TURQUOISE", dc)
self.AddColourToGallery(gallery, "VIOLET", dc)
self.AddColourToGallery(gallery, "VIOLET RED", dc)
self.AddColourToGallery(gallery, "WHEAT", dc)
self.AddColourToGallery(gallery, "WHITE", dc)
self.AddColourToGallery(gallery, "YELLOW", dc)
return gallery
def GetGalleryColour(self, gallery, item, name=None):
"""
Returns the gallery colour associated to a gallery item.
**Parameters:**
* `gallery`: the RibbonGallery in question;
* `item`: the RibbonGallery item;
* `name`: the colour name (if any).
"""
data = gallery.GetItemClientData(item)
if name != None:
name = data.GetName()
return data.GetColour(), name
def OnHoveredColourChange(self, event):
""" Handles the RB.EVT_RIBBONGALLERY_HOVER_CHANGED event for GUI2Exe. """
# Set the background of the gallery to the hovered colour, or back to the
# default if there is no longer a hovered item.
gallery = event.GetGallery()
provider = gallery.GetArtProvider()
if event.GetGalleryItem() != None:
if provider == self._ribbon.GetArtProvider():
provider = provider.Clone()
gallery.SetArtProvider(provider)
provider.SetColour(RB.RIBBON_ART_GALLERY_HOVER_BACKGROUND_COLOUR,
self.GetGalleryColour(event.GetGallery(), event.GetGalleryItem(), None)[0])
else:
if provider != self._ribbon.GetArtProvider():
gallery.SetArtProvider(self._ribbon.GetArtProvider())
del provider
def OnPrimaryColourSelect(self, event):
""" Handles the primary colour RB.EVT_RIBBONGALLERY_SELECTED event for GUI2Exe. """
colour, name = self.GetGalleryColour(event.GetGallery(), event.GetGalleryItem(), "")
dummy, secondary, tertiary = self._ribbon.GetArtProvider().GetColourScheme(None, 1, 1)
self._ribbon.GetArtProvider().SetColourScheme(colour, secondary, tertiary)
self._default_primary = colour
self.ResetGalleryArtProviders()
self._ribbon.Refresh()
def OnSecondaryColourSelect(self, event):
""" Handles the secondary colour RB.EVT_RIBBONGALLERY_SELECTED event for GUI2Exe. """
colour, name = self.GetGalleryColour(event.GetGallery(), event.GetGalleryItem(), "")
primary, dummy, tertiary = self._ribbon.GetArtProvider().GetColourScheme(1, None, 1)
self._ribbon.GetArtProvider().SetColourScheme(primary, colour, tertiary)
self._default_secondary = colour