4 :author: Dr. Gunnar Schwant
5 :contact: g.schwant@gmx.de
9 import browser
, images
, re
, sys
, os
, time
, ConfigParser
10 from wxPython
.wx
import *
11 from wxPython
.lib
.dialogs
import wxMultipleChoiceDialog
, \
12 wxScrolledMessageDialog
13 from wxPython
.lib
.imagebrowser
import ImageDialog
14 from wxPython
.help import *
16 from controls
import CustomStyledTextCtrl
17 from controls
import CustomTreeCtrl
18 from controls
import CustomStatusBar
19 from docutilsadapter
import publish_document
, get_errors
, \
20 get_rest_bibl_fields
, publishers
, publish_document
21 from docutils
.utils
import relative_path
22 from urllib
import quote
23 from wxPython
.lib
.buttons
import *
26 #-------------------------------------------------------------------------
28 #-------------------------------------------------------------------------
33 factory_path
= os
.path
.dirname(__file__
)
35 factory_path
= os
.path
.abspath(sys
.path
[0])
37 if not os
.path
.isdir(factory_path
):
38 factory_path
= os
.path
.abspath(sys
.path
[0])
41 f
= open(os
.path
.join(factory_path
, 'conf.pth'))
42 DATA
= f
.readline().splitlines()[0]
45 DATA
= os
.path
.join(factory_path
, 'docfactory.dat')
48 [wxID_WXNEWPROJ
, wxID_WXNEWREST
, wxID_WXOPENFILE
,
49 wxID_WXREMFILE
, wxID_WXSAVEFILE
, wxID_WXEXITAPP
, wxID_WXPUBL
, wxID_WXPUBLALL
,
50 wxID_WXPROJSETTINGS
, wxID_WXINSERTPATH
, wxID_WXINSERTIMAGE
,
51 wxID_WXINSERTFIGURE
, wxID_WXCLOSEFILE
, wxID_WXVIEWEOLS
, wxID_WXEOLSTOCR
,
52 wxID_WXEOLSTOLF
, wxID_WXEOLSTOCRLF
, wxID_WXEOLSTO
, wxID_WXVIEWEDGE
,
53 wxID_WXCUTSELECTION
, wxID_WXCOPYSELECTION
, wxID_WXPASTESELECTION
,
54 wxID_WXUNDO
, wxID_WXREDO
, wxID_WXGOTO
, wxID_WXSELECTALL
, wxID_WXVIEWWS
,
55 wxID_WXDELETEPROJ
, wxID_WXFONTSIZE
, wxID_WXSMALLFONT
, wxID_WXNORMALFONT
,
56 wxID_WXBIGFONT
, wxID_WXINSERT
, wxID_WXBTNBOLD
, wxID_WXBTNITALIC
,
57 wxID_WXBTNLITERAL
, wxID_WXBTNLINK
, wxID_WXBTNIMAGE
, wxID_WXBTNTOOL
,
58 wxID_WXINSERTHYPERLINK
, wxID_WXBTNPASTE
, wxID_WXBTNCOPY
, wxID_WXRUNTOOL
,
59 wxID_WXBTNCUT
, wxID_WXBTNREDO
, wxID_WXBTNUNDO
, wxID_WXBTNSAVE
,
60 wxID_WXBTNOPEN
, wxID_WXBTNNEW
, wxID_WXBTNPUBLISH
, wxID_WXBTNABOUT
,
61 wxID_WXFINDREPLACE
, wxID_WXBACKUPFILES
] = map(lambda init_menubar
: wxNewId(), range(53))
63 # Accelerator-Table for key commands
64 ACCEL
= [(wxACCEL_NORMAL
,WXK_F7
,wxID_WXPUBL
),
65 (wxACCEL_NORMAL
,WXK_F8
,wxID_WXRUNTOOL
),
66 (wxACCEL_CTRL
,ord('F'),wxID_WXFINDREPLACE
),
67 (wxACCEL_CTRL
,ord('G'),wxID_WXGOTO
),
68 (wxACCEL_CTRL
,ord('N'),wxID_WXNEWREST
),
69 (wxACCEL_CTRL
,ord('O'),wxID_WXOPENFILE
),
70 (wxACCEL_CTRL
,ord('S'),wxID_WXSAVEFILE
),
71 (wxACCEL_ALT
,ord('X'),wxID_WXEXITAPP
)]
73 #-------------------------------------------------------------------------
75 def get_file_extension(filename
):
76 return os
.path
.splitext(filename
)[1]
78 #-------------------------------------------------------------------------
83 self
.directory
= 'Nobody expects the spamish inquisition.'
87 if file not in self
.files
:
88 self
.files
.append(file)
90 raise 'File is already part of this project.'
92 def remove(self
, file):
93 if file in self
.files
:
94 self
.files
.remove(file)
96 #-------------------------------------------------------------------------
98 class CustomLog(wxPyLog
):
99 def __init__(self
, textCtrl
, logTime
=0):
100 wxPyLog
.__init
__(self
)
102 self
.logTime
= logTime
104 def DoLogString(self
, message
, timeStamp
):
106 message
= time
.strftime('%X', time
.localtime(timeStamp
)) + \
108 self
.tc
.AppendText(message
+ '\n')
110 #-------------------------------------------------------------------------
112 class DocFactoryFrame(wxFrame
):
113 def __init__(self
, projects
=[], initial_file
=None):
115 self
, NULL
, -1, NAME
, wxDefaultPosition
, (800, 600),
116 style
=wxDEFAULT_FRAME_STYLE
)
118 self
.projects
= projects
123 self
.activeitem
= None
125 self
.language_code
= 'en'
128 bmp
= images
.getLogoSmallBitmap()
129 mask
= wxMaskColour(bmp
, wxWHITE
)
131 logoicon
= wxEmptyIcon()
132 logoicon
.CopyFromBitmap(bmp
)
133 self
.SetIcon(logoicon
)
135 self
.init_preferences()
139 self
.SetAcceleratorTable(wxAcceleratorTable(ACCEL
))
142 splitter
= wxSplitterWindow(self
, -1, style
=wxNO_3D|wxSP_3D
)
143 splitter2
= wxSplitterWindow(splitter
, -1, style
=wxNO_3D|wxSP_3D
)
146 self
.log
= wxTextCtrl(splitter2
, -1,
147 style
= wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL
)
149 # Set the wxWindows log target to be this textctrl
150 wxLog_SetActiveTarget(CustomLog(self
.log
))
154 self
.tree
= CustomTreeCtrl(splitter
, tID
, style
=wxTR_HAS_BUTTONS |
155 wxTR_HAS_VARIABLE_ROW_HEIGHT
)
156 EVT_TREE_ITEM_ACTIVATED(self
.tree
, tID
, self
.on_tree_item_activated
)
158 # make an image list for tree
159 self
.im0
= self
.im1
= self
.im2
= -1
160 self
.il
= wxImageList(16, 16)
161 self
.im0
= self
.il
.Add(images
.getLogoSmallBitmap())
162 self
.im1
= self
.il
.Add(images
.getProjectBitmap())
163 self
.im2
= self
.il
.Add(images
.getFile1Bitmap())
164 self
.tree
.SetImageList(self
.il
)
170 self
.nb
= wxNotebook(splitter2
, tID
, style
=wxCLIP_CHILDREN
)
171 EVT_NOTEBOOK_PAGE_CHANGED(self
.nb
, tID
, self
.on_notebook_page_changed
)
174 self
.InitEditorPage()
177 self
.sb
= CustomStatusBar(self
)
178 self
.SetStatusBar(self
.sb
)
181 if initial_file
!= None:
182 self
.load_initial_file(initial_file
)
186 # add the windows to the splitter and split it.
187 splitter2
.SplitHorizontally(self
.nb
, self
.log
)
188 splitter
.SplitVertically(self
.tree
, splitter2
)
190 splitter
.SetSashPosition(180, 1)
191 splitter
.SetMinimumPaneSize(20)
192 splitter2
.SetSashPosition(450, 1)
193 splitter2
.SetMinimumPaneSize(20)
195 # Some global state variables.
196 self
.projectdirty
= 0
198 EVT_CLOSE(self
, self
.on_close_window
)
200 def init_menubar(self
):
201 self
.mainmenu
= wxMenuBar()
206 menu
.Append(wxID_WXNEWREST
, 'New\tCtrl+N',
207 'Create a new txt-file and add to project')
208 EVT_MENU(self
, wxID_WXNEWREST
, self
.on_file_new
)
209 menu
.Append(wxID_WXOPENFILE
, 'Open...\tCtrl+O',
211 EVT_MENU(self
, wxID_WXOPENFILE
, self
.on_file_open
)
212 menu
.Append(wxID_WXCLOSEFILE
, 'Close',
214 EVT_MENU(self
, wxID_WXCLOSEFILE
, self
.on_file_close
)
215 menu
.Enable(wxID_WXCLOSEFILE
, 0)
216 menu
.Append(wxID_WXSAVEFILE
, 'Save\tCtrl+S', 'Save file now')
217 EVT_MENU(self
, wxID_WXSAVEFILE
, self
.on_file_save
)
218 menu
.Enable(wxID_WXSAVEFILE
, 0)
219 menu
.Append(wxID_WXREMFILE
, 'Remove From Project',
220 'Remove file from project')
221 EVT_MENU(self
, wxID_WXREMFILE
, self
.on_file_remove
)
222 menu
.Enable(wxID_WXREMFILE
, 0)
223 menu
.AppendSeparator()
224 menu
.Append(wxID_WXPUBL
, 'Publish...\tF7',
226 EVT_MENU(self
, wxID_WXPUBL
, self
.on_publish
)
227 menu
.Enable(wxID_WXPUBL
, 0)
228 menu
.AppendSeparator()
229 menu
.Append(wxID_WXEXITAPP
, 'Exit\tAlt+X', 'Exit program')
230 EVT_MENU(self
, wxID_WXEXITAPP
, self
.on_app_exit
)
231 self
.mainmenu
.Append (menu
, '&File')
235 menu
.Append(wxID_WXUNDO
, 'Undo\tCtrl-Z', 'Undo')
236 EVT_MENU(self
, wxID_WXUNDO
, self
.on_undo
)
237 menu
.Enable(wxID_WXUNDO
, 0)
238 menu
.Append(wxID_WXREDO
, 'Redo\tCtrl-Y', 'Redo')
239 EVT_MENU(self
, wxID_WXREDO
, self
.on_redo
)
240 menu
.Enable(wxID_WXREDO
, 0)
241 menu
.AppendSeparator()
242 menu
.Append(wxID_WXCUTSELECTION
, 'Cut\tCtrl-X', 'Cut')
243 EVT_MENU(self
, wxID_WXCUTSELECTION
, self
.on_cut
)
244 menu
.Enable(wxID_WXCUTSELECTION
, 0)
245 menu
.Append(wxID_WXCOPYSELECTION
, 'Copy\tCtrl-C', 'Copy')
246 EVT_MENU(self
, wxID_WXCOPYSELECTION
, self
.on_copy
)
247 menu
.Enable(wxID_WXCOPYSELECTION
, 0)
248 menu
.Append(wxID_WXPASTESELECTION
, 'Paste\tCtrl-V', 'Paste')
249 EVT_MENU(self
, wxID_WXPASTESELECTION
, self
.on_paste
)
250 menu
.Enable(wxID_WXPASTESELECTION
, 0)
251 menu
.Append(wxID_WXSELECTALL
, 'Select all\tCtrl-A', 'Select the entire file')
252 EVT_MENU(self
, wxID_WXSELECTALL
, self
.on_select_all
)
253 menu
.Enable(wxID_WXSELECTALL
, 0)
254 menu
.AppendSeparator()
256 submenu
.Append(wxID_WXINSERTFIGURE
, 'Figure',
258 EVT_MENU(self
, wxID_WXINSERTFIGURE
, self
.on_insert_figure
)
259 submenu
.Append(wxID_WXINSERTHYPERLINK
, 'Hyperlink', 'Insert a hyperlink')
260 EVT_MENU(self
, wxID_WXINSERTHYPERLINK
, self
.on_btn_hyperlink
)
261 submenu
.Append(wxID_WXINSERTIMAGE
, 'Image', 'Insert an image')
262 EVT_MENU(self
, wxID_WXINSERTIMAGE
, self
.on_insert_image
)
263 submenu
.Append(wxID_WXINSERTPATH
, 'Path', 'Insert a path')
264 EVT_MENU(self
, wxID_WXINSERTPATH
, self
.on_insert_path
)
265 menu
.AppendMenu(wxID_WXINSERT
, 'Insert', submenu
)
266 menu
.Enable(wxID_WXINSERT
, 0)
267 menu
.AppendSeparator()
269 submenu
.Append(wxID_WXEOLSTOCR
,'CR',
270 'Change all end of line characters to CR (\\r)')
271 EVT_MENU(self
, wxID_WXEOLSTOCR
, self
.on_eols_to_cr
)
272 submenu
.Append(wxID_WXEOLSTOLF
,'LF',
273 'Change all end of line characters to LF (\\n)')
274 EVT_MENU(self
, wxID_WXEOLSTOLF
, self
.on_eols_to_lf
)
275 submenu
.Append(wxID_WXEOLSTOCRLF
,'CRLF',
276 'Change all end of line characters to LF (\\r\\n)')
277 EVT_MENU(self
, wxID_WXEOLSTOCRLF
, self
.on_eols_to_crlf
)
278 menu
.AppendMenu(wxID_WXEOLSTO
, 'Change all EOLs to', submenu
)
279 menu
.Enable(wxID_WXEOLSTO
, 0)
280 menu
.AppendSeparator()
281 menu
.Append(wxID_WXFINDREPLACE
, 'Find && Replace...\tCtrl-F', 'Find and replace')
282 EVT_MENU(self
, wxID_WXFINDREPLACE
, self
.on_findreplace_show
)
283 EVT_COMMAND_FIND(self
, -1, self
.on_find
)
284 EVT_COMMAND_FIND_NEXT(self
, -1, self
.on_find
)
285 EVT_COMMAND_FIND_REPLACE(self
, -1, self
.on_find
)
286 EVT_COMMAND_FIND_REPLACE_ALL(self
, -1, self
.on_find
)
287 EVT_COMMAND_FIND_CLOSE(self
, -1, self
.on_find_close
)
288 menu
.Append(wxID_WXGOTO
, 'Goto line...\tCtrl-G', 'Goto a specific line in the file')
289 EVT_MENU(self
, wxID_WXGOTO
, self
.on_goto
)
290 menu
.Enable(wxID_WXGOTO
, 0)
291 self
.mainmenu
.Append (menu
, '&Edit')
295 menu
.Append(wxID_WXNEWPROJ
, 'New', 'Create a new project')
296 EVT_MENU(self
, wxID_WXNEWPROJ
, self
.on_project_new
)
297 menu
.Append(wxID_WXDELETEPROJ
, 'Delete...',
298 'Delete one or more projects')
299 EVT_MENU(self
, wxID_WXDELETEPROJ
, self
.on_project_delete
)
300 menu
.Append(wxID_WXPUBLALL
, 'Publish...',
301 'Publish all txt-files of active project')
302 EVT_MENU(self
, wxID_WXPUBLALL
, self
.on_publish_all
)
303 menu
.Enable(wxID_WXPUBLALL
, 0)
304 menu
.AppendSeparator()
305 menu
.Append(wxID_WXPROJSETTINGS
, 'Project Settings...',
306 'Edit project settings')
307 EVT_MENU(self
, wxID_WXPROJSETTINGS
, self
.on_project_settings
)
308 if len(self
.projects
) == 0:
309 menu
.Enable(wxID_WXDELETEPROJ
, 0)
310 menu
.Enable(wxID_WXPROJSETTINGS
, 0)
311 self
.mainmenu
.Append (menu
, 'Pr&oject')
317 menu
.Append(wxID_WXVIEWEOLS
, 'View EOL markers',
318 'Show or hide end-of-line markers', wxITEM_CHECK
)
319 EVT_MENU(self
, wxID_WXVIEWEOLS
, self
.on_view_eols
)
320 menu
.Check(wxID_WXVIEWEOLS
, self
.preferences
['eol_markers'])
321 menu
.Append(wxID_WXVIEWEDGE
, 'View right edge indicator',
322 'Toggle display of the right edge indicator (75 characters)',
324 EVT_MENU(self
, wxID_WXVIEWEDGE
, self
.on_view_edge
)
325 menu
.Check(wxID_WXVIEWEDGE
, self
.preferences
['right_edge_indicator'])
326 menu
.Append(wxID_WXVIEWWS
, 'View whitespace',
327 'Show or hide whitespace', wxITEM_CHECK
)
328 EVT_MENU(self
, wxID_WXVIEWWS
, self
.on_view_ws
)
329 menu
.Check(wxID_WXVIEWWS
, self
.preferences
['whitespace'])
330 menu
.AppendSeparator()
332 submenu
.Append(wxID_WXSMALLFONT
,'Small',
333 'Reduce font', wxITEM_RADIO
)
334 EVT_MENU(self
, wxID_WXSMALLFONT
, self
.on_font_small
)
335 submenu
.Append(wxID_WXNORMALFONT
,'Normal',
336 'Restore font', wxITEM_RADIO
)
337 EVT_MENU(self
, wxID_WXNORMALFONT
, self
.on_font_normal
)
338 submenu
.Append(wxID_WXBIGFONT
,'Big',
339 'Magnify font', wxITEM_RADIO
)
340 EVT_MENU(self
, wxID_WXBIGFONT
, self
.on_font_big
)
341 if self
.preferences
['fontsize'] == 'small':
342 submenu
.Check(wxID_WXSMALLFONT
, 1)
343 elif self
.preferences
['fontsize'] == 'big':
344 submenu
.Check(wxID_WXBIGFONT
, 1)
346 submenu
.Check(wxID_WXNORMALFONT
, 1)
347 menu
.AppendMenu(wxID_WXFONTSIZE
, 'Fontsize', submenu
)
348 menu
.AppendSeparator()
349 menu
.Append(wxID_WXBACKUPFILES
, 'Backup files',
350 'Backup files as [filename].bak', wxITEM_CHECK
)
351 EVT_MENU(self
, wxID_WXBACKUPFILES
, self
.on_backup_files
)
352 menu
.Check(wxID_WXBACKUPFILES
, self
.preferences
['backup_files'])
353 self
.mainmenu
.Append(menu
, '&Preferences')
358 menu
.Append(exitID
, 'Configure', 'Configure toolbox')
359 EVT_MENU(self
, exitID
, self
.on_configure_tools
)
360 menu
.Append(wxID_WXRUNTOOL
, 'Open...\tF8', 'Open toolbox')
361 EVT_MENU(self
, wxID_WXRUNTOOL
, self
.on_run_tool
)
362 self
.mainmenu
.Append (menu
, '&Toolbox')
367 menu
.Append(exitID
, 'About', 'About')
368 EVT_MENU(self
, exitID
, self
.on_help_about
)
369 self
.mainmenu
.Append (menu
, '&Help')
371 self
.SetMenuBar(self
.mainmenu
)
373 def init_preferences(self
):
374 self
.preferences
= {}
375 if os
.path
.exists(DATA
):
377 cfg
= ConfigParser
.ConfigParser()
379 if cfg
.has_section('preferences'):
380 for pref
in cfg
.options('preferences'):
381 if pref
in ('eol_markers', 'right_edge_indicator', \
382 'whitespace', 'backup_files'):
383 self
.preferences
[pref
] = cfg
.getboolean('preferences', pref
)
385 self
.preferences
[pref
] = cfg
.get('preferences', pref
)
387 customMsgBox(self
, '%s:\n%s\n%s' % sys
.exc_info(), 'error')
388 if not self
.preferences
.has_key('eol_markers'):
389 self
.preferences
['eol_markers'] = 0
390 if not self
.preferences
.has_key('right_edge_indicator'):
391 self
.preferences
['right_edge_indicator'] = 1
392 if not self
.preferences
.has_key('whitespace'):
393 self
.preferences
['whitespace'] = 0
394 if not self
.preferences
.has_key('fontsize'):
395 self
.preferences
['fontsize'] = 'normal'
396 if not self
.preferences
.has_key('backup_files'):
397 self
.preferences
['backup_files'] = 0
399 def init_toolbar(self
):
400 self
.toolbar
= tb
= self
.CreateToolBar(wxTB_HORIZONTAL|wxTB_FLAT|wxNO_BORDER
)
401 bmp
= images
.getNewBitmap()
402 mask
= wxMaskColour(bmp
, wxBLUE
)
404 tb
.AddLabelTool(wxID_WXBTNNEW
, 'New', bmp
, shortHelp
='New',
405 longHelp
='Create a new file')
406 EVT_TOOL(tb
, wxID_WXBTNNEW
, self
.on_file_new
)
407 bmp
= images
.getOpenBitmap()
408 mask
= wxMaskColour(bmp
, wxWHITE
)
410 tb
.AddLabelTool(wxID_WXBTNOPEN
, 'Open', bmp
, shortHelp
='Open',
411 longHelp
='Open an existing file')
412 EVT_TOOL(tb
, wxID_WXBTNOPEN
, self
.on_file_open
)
413 bmp
= images
.getSaveBitmap()
414 mask
= wxMaskColour(bmp
, wxWHITE
)
416 tb
.AddLabelTool(wxID_WXBTNSAVE
, 'Save', bmp
, shortHelp
='Save',
417 longHelp
='Save the active file')
418 EVT_TOOL(tb
, wxID_WXBTNSAVE
, self
.on_file_save
)
419 tb
.EnableTool(wxID_WXBTNSAVE
, 0)
421 bmp
= images
.getCutBitmap()
422 mask
= wxMaskColour(bmp
, wxWHITE
)
424 tb
.AddLabelTool(wxID_WXBTNCUT
, 'Cut', bmp
, shortHelp
='Cut',
425 longHelp
='Cut the selection and put it on the Clipboard')
426 EVT_TOOL(tb
, wxID_WXBTNCUT
, self
.on_cut
)
427 tb
.EnableTool(wxID_WXBTNCUT
, 0)
428 bmp
= images
.getCopyBitmap()
429 mask
= wxMaskColour(bmp
, wxBLUE
)
431 tb
.AddLabelTool(wxID_WXBTNCOPY
, 'Copy', bmp
, shortHelp
='Copy',
432 longHelp
='Copy the selection and put it on the Clipboard')
433 EVT_TOOL(tb
, wxID_WXBTNCOPY
, self
.on_copy
)
434 tb
.EnableTool(wxID_WXBTNCOPY
, 0)
435 bmp
= images
.getPasteBitmap()
436 mask
= wxMaskColour(bmp
, wxBLUE
)
438 tb
.AddLabelTool(wxID_WXBTNPASTE
, 'Paste', bmp
, shortHelp
='Paste',
439 longHelp
='Insert Clipboard contents')
440 EVT_TOOL(tb
, wxID_WXBTNPASTE
, self
.on_paste
)
441 tb
.EnableTool(wxID_WXBTNPASTE
, 0)
443 bmp
= images
.getUndoBitmap()
444 mask
= wxMaskColour(bmp
, wxWHITE
)
446 tb
.AddLabelTool(wxID_WXBTNUNDO
, 'Undo', bmp
, shortHelp
='Undo',
447 longHelp
='Undo the last action')
448 EVT_TOOL(tb
, wxID_WXBTNUNDO
, self
.on_undo
)
449 tb
.EnableTool(wxID_WXBTNUNDO
, 0)
450 bmp
= images
.getRedoBitmap()
451 mask
= wxMaskColour(bmp
, wxWHITE
)
453 tb
.AddLabelTool(wxID_WXBTNREDO
, 'Redo', bmp
, shortHelp
='Redo',
454 longHelp
='Redo the previously undone action')
455 EVT_TOOL(tb
, wxID_WXBTNREDO
, self
.on_redo
)
456 tb
.EnableTool(wxID_WXBTNREDO
, 0)
458 bmp
= images
.getLinkBitmap()
459 mask
= wxMaskColour(bmp
, wxBLUE
)
461 tb
.AddLabelTool(wxID_WXBTNLINK
, 'Hyperlink', bmp
,
462 shortHelp
='Insert hyperlink',
463 longHelp
='Insert hyperlink')
464 EVT_TOOL(tb
, wxID_WXBTNLINK
, self
.on_btn_hyperlink
)
465 tb
.EnableTool(wxID_WXBTNLINK
, 0)
466 bmp
= images
.getImageBitmap()
467 mask
= wxMaskColour(bmp
, wxBLUE
)
469 tb
.AddLabelTool(wxID_WXBTNIMAGE
, 'Image', bmp
,
470 shortHelp
='Insert image',
471 longHelp
='Insert image')
472 EVT_TOOL(tb
, wxID_WXBTNIMAGE
, self
.on_btn_image
)
473 tb
.EnableTool(wxID_WXBTNIMAGE
, 0)
475 bmp
= images
.getPublishBitmap()
476 mask
= wxMaskColour(bmp
, wxRED
)
478 tb
.AddLabelTool(wxID_WXBTNPUBLISH
, 'Publish', bmp
, shortHelp
='Publish file',
479 longHelp
='Publish file')
480 EVT_TOOL(tb
, wxID_WXBTNPUBLISH
, self
.on_publish
)
481 tb
.EnableTool(wxID_WXBTNPUBLISH
, 0)
483 bmp
= images
.getToolBitmap()
484 mask
= wxMaskColour(bmp
, wxBLUE
)
486 tb
.AddLabelTool(wxID_WXBTNTOOL
, 'Toolbox', bmp
, shortHelp
='Open toolbox',
487 longHelp
='Open toolbox')
488 EVT_TOOL(tb
, wxID_WXBTNTOOL
, self
.on_run_tool
)
490 bmp
= images
.getBoldBitmap()
491 mask
= wxMaskColour(bmp
, wxWHITE
)
493 tb
.AddLabelTool(wxID_WXBTNBOLD
, 'Bold', bmp
, shortHelp
='Bold', longHelp
='Bold')
494 EVT_TOOL(tb
, wxID_WXBTNBOLD
, self
.on_format_word
)
495 tb
.EnableTool(wxID_WXBTNBOLD
, 0)
496 bmp
= images
.getItalicBitmap()
497 mask
= wxMaskColour(bmp
, wxWHITE
)
499 tb
.AddLabelTool(wxID_WXBTNITALIC
, 'Italic', bmp
, shortHelp
='Italic', longHelp
='Italic')
500 EVT_TOOL(tb
, wxID_WXBTNITALIC
, self
.on_format_word
)
501 tb
.EnableTool(wxID_WXBTNITALIC
, 0)
502 bmp
= images
.getPreBitmap()
503 mask
= wxMaskColour(bmp
, wxWHITE
)
505 tb
.AddLabelTool(wxID_WXBTNLITERAL
, 'literal', bmp
, shortHelp
='Literal', longHelp
='Literal')
506 EVT_TOOL(tb
, wxID_WXBTNLITERAL
, self
.on_format_word
)
507 tb
.EnableTool(wxID_WXBTNLITERAL
, 0)
508 if wxPlatform
!= '__WXMAC__':
510 self
.formats
= {'Title' : '=', 'Subtitle' : '-',
511 'Heading 1' : '=', 'Heading 2' : '-',
512 'Heading 3' : '~', 'Heading 4' : '`'}
513 formats
= self
.formats
.keys()
516 self
.combobox_format
= wxComboBox(tb
, exitID
, '',
518 style
=wxCB_DROPDOWN|wxCB_READONLY
)
519 tb
.AddControl(self
.combobox_format
)
520 EVT_COMBOBOX(tb
, exitID
, self
.on_format_paragraph
)
522 bmp
= images
.getAboutBitmap()
523 mask
= wxMaskColour(bmp
, wxWHITE
)
525 tb
.AddLabelTool(wxID_WXBTNABOUT
, 'About', bmp
, shortHelp
='About',
526 longHelp
='Display program information')
527 EVT_TOOL(tb
, wxID_WXBTNABOUT
, self
.on_help_about
)
530 def init_tools(self
):
532 if os
.path
.exists(DATA
):
534 cfg
= ConfigParser
.ConfigParser()
536 if cfg
.has_section('tools'):
537 for i
in range(len(cfg
.options('tools'))):
538 self
.tools
[i
+1] = [i
+1] \
539 + cfg
.get('tools', str(i
+1)).split(';')
541 customMsgBox(self
, '%s:\n%s\n%s' % sys
.exc_info(), 'error')
544 self
.tree
.DeleteAllItems()
545 self
.root
= self
.tree
.AddRoot('Workspace', self
.im0
)
546 self
.tree
.SetPyData(self
.root
, None)
547 for proj
in self
.projects
:
548 child
= self
.tree
.AppendItem(self
.root
, proj
.name
, self
.im1
)
549 self
.tree
.SetPyData(child
, None)
550 for file in proj
.files
:
551 last
= self
.tree
.AppendItem(child
, file, self
.im2
)
552 self
.tree
.SetPyData(last
, None)
553 self
.tree
.SortChildren(self
.root
)
554 for file in self
.files
:
555 last
= self
.tree
.AppendItem(self
.root
, file, self
.im2
)
556 self
.tree
.SetPyData(last
, None)
558 self
.activateMenuItemsProjectOpen(0)
559 self
.activateMenuItemsFileSelected(0)
560 self
.activeitem
= self
.root
561 self
.tree
.SelectItem(self
.activeitem
)
562 self
.tree
.Expand(self
.activeitem
)
563 if self
.editor
!= None:
564 self
.nb
.SetPageText(0, 'Editor')
566 self
.editor
.Enable(0)
567 self
.activateMenuItemsFileSelected(0)
568 if self
.nb
.GetPageCount() > 1:
569 self
.nb
.DeletePage(1)
571 def InitEditorPage(self
):
574 self
.editor
= CustomStyledTextCtrl(self
.nb
, edID
, self
.log
)
575 self
.editor
.SetViewEOL(self
.preferences
['eol_markers'])
576 self
.editor
.SetEdgeMode(self
.preferences
['right_edge_indicator'])
577 self
.editor
.SetViewWhiteSpace(self
.preferences
['whitespace'])
578 if self
.preferences
['fontsize'] == 'small':
579 self
.editor
.SetZoom(-2)
580 elif self
.preferences
['fontsize'] == 'big':
581 self
.editor
.SetZoom(2)
583 self
.editor
.SetZoom(0)
585 self
.editor
.Enable(0)
586 self
.nb
.AddPage(self
.editor
, 'Editor')
587 self
.nb
.SetSelection(0)
589 # --------------------------------------------------------------------
591 # --------------------------------------------------------------------
593 def activateMenuItemsProjectOpen(self
, value
):
594 menu
= self
.mainmenu
.GetMenu(self
.mainmenu
.FindMenu('Project'))
595 if len(self
.projects
) > 0 and value
:
596 menu
.Enable(wxID_WXDELETEPROJ
, value
)
597 menu
.Enable(wxID_WXPROJSETTINGS
, value
)
598 menu
.Enable(wxID_WXPUBLALL
, value
)
600 def activateMenuItemsFileSelected(self
, value
):
601 menu
= self
.mainmenu
.GetMenu(self
.mainmenu
.FindMenu('File'))
602 if self
.project
!= None:
603 menu
.Enable(wxID_WXREMFILE
, value
)
605 menu
.Enable(wxID_WXREMFILE
, 0)
606 menu
.Enable(wxID_WXCLOSEFILE
, value
)
607 menu
.Enable(wxID_WXSAVEFILE
, value
)
608 menu
.Enable(wxID_WXPUBL
, value
)
609 menu
= self
.mainmenu
.GetMenu(self
.mainmenu
.FindMenu('Edit'))
610 menu
.Enable(wxID_WXUNDO
, value
)
611 menu
.Enable(wxID_WXREDO
, value
)
612 menu
.Enable(wxID_WXCUTSELECTION
, value
)
613 menu
.Enable(wxID_WXCOPYSELECTION
, value
)
614 menu
.Enable(wxID_WXPASTESELECTION
, value
)
615 menu
.Enable(wxID_WXSELECTALL
, value
)
616 menu
.Enable(wxID_WXINSERT
, value
)
617 menu
.Enable(wxID_WXEOLSTO
, value
)
618 menu
.Enable(wxID_WXFINDREPLACE
, value
)
619 menu
.Enable(wxID_WXGOTO
, value
)
620 self
.toolbar
.EnableTool(wxID_WXBTNSAVE
, value
)
621 self
.toolbar
.EnableTool(wxID_WXBTNLINK
, value
)
622 self
.toolbar
.EnableTool(wxID_WXBTNIMAGE
, value
)
623 self
.toolbar
.EnableTool(wxID_WXBTNBOLD
, value
)
624 self
.toolbar
.EnableTool(wxID_WXBTNITALIC
, value
)
625 self
.toolbar
.EnableTool(wxID_WXBTNLITERAL
, value
)
626 self
.toolbar
.EnableTool(wxID_WXBTNPASTE
, value
)
627 self
.toolbar
.EnableTool(wxID_WXBTNCOPY
, value
)
628 self
.toolbar
.EnableTool(wxID_WXBTNCUT
, value
)
629 self
.toolbar
.EnableTool(wxID_WXBTNREDO
, value
)
630 self
.toolbar
.EnableTool(wxID_WXBTNUNDO
, value
)
631 self
.toolbar
.EnableTool(wxID_WXBTNPUBLISH
, value
)
633 def CheckEditorChanges(self
):
635 if self
.editor
!= None:
636 if self
.editor
.IsModified
:
637 dlg
=wxMessageDialog(self
, 'Save changes?', NAME
,
638 wxYES_NO | wxCANCEL | wxICON_QUESTION
)
639 result
= dlg
.ShowModal()
640 if result
== wxID_YES
:
641 file = self
.tree
.GetItemText(self
.activeitem
)
642 go_ahead
= self
.editor
.SaveFile(file, self
.preferences
['backup_files'])
643 if result
== wxID_CANCEL
:
648 def delete_project(self
, project
):
649 if project
in self
.projects
:
650 self
.projects
.remove(project
)
654 customMsgBox(self
, '%s:\n%s\n%s' % sys
.exc_info(), 'error')
657 def htmlfile(self
, file, dir):
658 htmlfile
= os
.path
.join(dir,
659 os
.path
.splitext(os
.path
.basename(file))[0] \
663 def insert_hyperlink(self
):
664 item
= self
.activeitem
665 itemimage
= self
.tree
.GetItemImage(item
)
666 file = self
.tree
.GetItemText(item
)
667 if self
.project
!= None:
668 dir = self
.project
.directory
670 dir = os
.path
.dirname(file)
672 dlg
= hyperlinkDlg(self
, directory
=dir, project
=self
.project
)
674 if dlg
.ShowModal() == wxID_OK
:
675 target
= dlg
.GetPath()
680 selection
= self
.editor
.GetSelectedText()
681 curpos
= self
.editor
.GetCurrentPos()
683 self
.editor
.BeginUndoAction()
684 selection
= '`%s`' % selection
685 self
.editor
.ReplaceSelection(selection
+ '_')
686 endpos
= self
.editor
.GetTextLength()
687 self
.editor
.GotoPos(endpos
)
688 text
= '\n\n.. _%s: %s' % (selection
, target
)
689 self
.editor
.ReplaceSelection(text
)
690 self
.editor
.GotoPos(curpos
+ 3)
691 self
.editor
.EndUndoAction()
693 text
= '\n\n.. _``: %s\n' % target
694 self
.editor
.ReplaceSelection(text
)
695 self
.editor
.GotoPos(curpos
+ 7)
697 def insert_image(self
, directive
):
698 item
= self
.activeitem
699 itemimage
= self
.tree
.GetItemImage(item
)
700 file = self
.tree
.GetItemText(item
)
701 if self
.imagedir
== None:
702 if self
.project
!= None:
703 dir = self
.project
.directory
705 dir = os
.path
.dirname(file)
708 dlg
= ImageDialog(self
, dir)
711 if dlg
.ShowModal() == wxID_OK
:
712 target
= dlg
.GetFile()
713 self
.imagedir
= os
.path
.dirname(target
)
718 if self
.project
!= None:
719 dir = self
.project
.directory
721 dir = os
.path
.dirname(file)
722 dlg
= wxDirDialog(self
, 'Calculate path relative'
723 ' to which outputdirectory?', dir)
724 if dlg
.ShowModal() == wxID_OK
:
730 selection
= self
.editor
.GetSelectedText()
731 if selection
!= '' and directive
== 'image':
732 self
.editor
.BeginUndoAction()
733 curpos
= self
.editor
.GetCurrentPos()
734 selection
= '|%s|' % selection
735 self
.editor
.ReplaceSelection(selection
)
736 endpos
= self
.editor
.GetTextLength()
737 self
.editor
.GotoPos(endpos
)
738 text
= '\n\n.. %s %s:: %s' % (selection
, directive
,
739 quote(relative_path(self
.htmlfile(file,dir),
741 self
.editor
.ReplaceSelection(text
)
742 self
.editor
.GotoPos(curpos
+ 2)
743 self
.editor
.EndUndoAction()
745 text
= '\n\n.. %s:: %s\n\n' % (directive
,
746 quote(relative_path(self
.htmlfile(file,dir),
748 self
.editor
.ReplaceSelection(text
)
750 def load_initial_file(self
, file):
751 if os
.path
.exists(file):
753 self
.files
.append(file)
756 self
.open_file_in_editor(file)
757 last
= self
.tree
.AppendItem(parent
, file, self
.im2
)
758 self
.tree
.SetPyData(last
, None)
759 self
.tree
.SetItemBold(self
.activeitem
, 0)
760 self
.tree
.SetItemTextColour(self
.activeitem
, wxBLACK
)
761 self
.activeitem
= last
762 self
.tree
.SetItemBold(self
.activeitem
, 1)
763 self
.tree
.SetItemTextColour(self
.activeitem
, wxBLUE
)
764 self
.tree
.EnsureVisible(self
.activeitem
)
765 self
.tree
.SelectItem(self
.activeitem
)
766 parent
= self
.tree
.GetItemParent(self
.activeitem
)
767 self
.tree
.SetItemBold(parent
, 1)
768 self
.tree
.SetItemTextColour(parent
, wxBLUE
)
770 customMsgBox(self
, '%s:\n%s\n%s' % sys
.exc_info(), 'error')
772 customMsgBox(self
, 'Can not find %s.' % file, 'error')
774 def open_file_in_editor(self
, file):
775 if self
.nb
.GetPageCount() > 1:
776 self
.nb
.DeletePage(1)
777 self
.nb
.SetSelection(0)
778 self
.editor
.LoadFile(file)
779 self
.set_editor_language_code(file)
780 self
.nb
.SetPageText(0, 'Editor: %s' %
781 os
.path
.basename(file))
782 self
.editor
.Enable(1)
783 self
.activateMenuItemsFileSelected(1)
784 self
.editor
.IsModified
= 0
786 def project_save(self
):
789 self
.projectdirty
= 0
791 customMsgBox(self
, '%s:\n%s\n%s' % sys
.exc_info(), 'error')
793 def publishFile(self
, infile
, outfile
, outdir
, writer
):
797 t
= time
.localtime(time
.time())
798 st
= time
.strftime('%d-%b-%Y, %H:%M:%S', t
)
799 wxLogMessage('%s: Publishing %s' % (st
, writer
))
800 wxLogMessage('SOURCE: %s' % infile
)
801 outfile_fullpath
= os
.path
.join(outdir
, outfile
)
802 wxLogMessage('DESTINATION: %s' % outfile_fullpath
)
803 if outfile_fullpath
== infile
:
804 customMsgBox(self
, 'Destination and source are identical.'
805 '\nNo processing.', 'wakeup')
806 warning_lines
= error_lines
= []
809 publish_document(writer
, infile
, outfile
, outdir
)
811 warning_lines
, error_lines
= get_errors(self
.log
.GetValue())
812 linecount
= self
.editor
.GetLineCount()
813 self
.editor
.MarkerDeleteAll(0)
814 self
.editor
.MarkerDeleteAll(1)
815 if warning_lines
!= []:
816 for line
in warning_lines
:
818 self
.editor
.MarkerAdd(line
, 0)
819 self
.editor
.GotoLine(warning_lines
[-1])
820 if error_lines
!= []:
821 for line
in error_lines
:
823 self
.editor
.MarkerAdd(line
, 1)
824 self
.editor
.GotoLine(error_lines
[-1])
825 self
.editor
.IsModified
= 0
826 if os
.path
.exists(outfile_fullpath
):
827 if self
.nb
.GetPageCount() > 1:
828 self
.nb
.DeletePage(1)
829 if get_file_extension(outfile
) in ['.html', '.htm']:
830 # init html-viewer page
831 if wxPlatform
== '__WXMSW__':
832 htmlprv
= browser
.IEHtmlPanel(self
.nb
, self
, self
.log
,
833 'file://%s' % quote(outfile_fullpath
))
835 htmlprv
= browser
.HtmlPanel(self
.nb
, self
, self
.log
,
837 self
.nb
.AddPage(htmlprv
, 'HTML-Viewer: %s'
839 if warning_lines
== error_lines
== []:
840 self
.nb
.SetSelection(1)
841 t
= time
.localtime(time
.time())
842 st
= time
.strftime('%d-%b-%Y, %H:%M:%S: ', t
)
843 wxLogMessage('%sFinished.' % st
)
847 def save_preferences(self
):
848 cfg
= ConfigParser
.ConfigParser()
851 if not cfg
.has_section('preferences'):
852 cfg
.add_section('preferences')
853 for pref
in self
.preferences
.keys():
854 cfg
.set('preferences', pref
,
855 self
.preferences
[pref
])
860 customMsgBox(self
, '%s:\n%s\n%s' % sys
.exc_info(), 'error')
862 def save_projects(self
):
863 cfg
= ConfigParser
.ConfigParser()
865 for section
in cfg
.sections():
866 if section
[:19] == 'docfactory_project:':
867 cfg
.remove_section(section
)
868 for project
in self
.projects
:
869 section
= 'docfactory_project: %s' % project
.name
870 cfg
.add_section(section
)
871 cfg
.set(section
, 'outputdirectory', project
.directory
)
873 for file in project
.files
:
874 files
= '%s;%s' % (files
, file)
877 cfg
.set(section
, 'files', files
)
882 def set_editor_language_code(self
, file=None):
884 if self
.project
!= None:
885 directory
= self
.project
.directory
887 directory
= os
.path
.split(os
.path
.abspath(file))[0]
888 docutils_conf
= os
.path
.join(directory
, 'docutils.conf')
889 if os
.path
.exists(docutils_conf
):
891 cfg
= ConfigParser
.ConfigParser()
892 cfg
.read(docutils_conf
)
893 if cfg
.has_option('general', 'language_code'):
894 language_code
= cfg
.get('general', 'language_code')
896 print '%s:\n%s\n%s' % sys
.exc_info()
897 self
.editor
.bibliographic_fields
= get_rest_bibl_fields(language_code
)
899 # --------------------------------------------------------------------
901 # --------------------------------------------------------------------
903 def on_app_exit(self
, event
):
906 def on_backup_files(self
, event
):
907 self
.preferences
['backup_files'] = not self
.preferences
['backup_files']
909 def on_btn_image(self
, event
):
910 self
.insert_image('image')
912 def on_close_window(self
, event
):
914 if self
.projectdirty
:
915 dlg
=wxMessageDialog(self
, 'Save project?', NAME
,
916 wxYES_NO | wxCANCEL | wxICON_QUESTION
)
917 result
= dlg
.ShowModal()
918 if result
== wxID_YES
:
920 if result
== wxID_CANCEL
:
924 if go_ahead
and self
.CheckEditorChanges():
927 def on_configure_tools(self
, event
):
930 if dlg
.ShowModal() == wxID_OK
:
931 self
.tools
= dlg
.get_tools()
933 cfg
= ConfigParser
.ConfigParser()
936 if cfg
.has_section('tools'):
937 cfg
.remove_section('tools')
938 cfg
.add_section('tools')
939 for tool
in self
.tools
.values():
940 cfg
.set('tools', str(tool
[0]),
941 '%s;%s;%s' % (tool
[1],tool
[2],tool
[3]))
946 customMsgBox(self
, '%s:\n%s\n%s' % sys
.exc_info(), 'error')
948 def on_copy(self
, event
):
951 def on_cut(self
, event
):
954 def on_eols_to_cr(self
, event
):
956 self
.editor
.ConvertEOLs(1)
959 def on_eols_to_lf(self
, event
):
961 self
.editor
.ConvertEOLs(2)
964 def on_eols_to_crlf(self
, event
):
966 self
.editor
.ConvertEOLs(0)
969 def on_file_close(self
, event
):
970 if self
.CheckEditorChanges():
971 if self
.nb
.GetPageCount() > 1:
972 self
.nb
.DeletePage(1)
973 self
.nb
.SetPageText(0, 'Editor')
975 self
.editor
.Enable(0)
976 self
.activateMenuItemsFileSelected(0)
977 item
= self
.activeitem
978 parent
= self
.tree
.GetItemParent(item
)
979 self
.tree
.SetItemBold(item
, 0)
980 self
.tree
.SetItemTextColour(item
, wxBLACK
)
981 if parent
== self
.root
:
982 self
.files
.remove(self
.tree
.GetItemText(item
))
983 self
.tree
.Delete(item
)
984 self
.activeitem
= parent
985 self
.tree
.SelectItem(self
.activeitem
)
987 def on_file_open(self
, event
):
991 if self
.CheckEditorChanges():
993 if self
.project
!= None:
994 dir = self
.project
.directory
995 parent
= self
.tree
.GetItemParent(self
.activeitem
)
996 if parent
== self
.root
:
997 parent
= self
.activeitem
1002 wildcard
= 'Text (*.txt)|*.txt|' \
1003 'All files (*.*)|*.*'
1005 dlg
= wxFileDialog (self
, 'Open file',
1007 wxOPEN|wxFILE_MUST_EXIST
)
1008 if dlg
.ShowModal() == wxID_OK
:
1009 file = dlg
.GetPath()
1010 if parent
== self
.root
:
1011 if file not in self
.files
:
1012 self
.files
.append(file)
1014 customMsgBox(self
, '%s already in workspace.' % file,
1018 if file not in self
.project
.files
:
1019 self
.project
.add(file)
1022 customMsgBox(self
, '%s already part of project "%s".'
1023 % (file, self
.project
.name
),
1031 self
.open_file_in_editor(file)
1032 last
= self
.tree
.AppendItem(parent
, file, self
.im2
)
1033 self
.tree
.SetPyData(last
, None)
1034 self
.tree
.SetItemBold(self
.activeitem
, 0)
1035 self
.tree
.SetItemTextColour(self
.activeitem
, wxBLACK
)
1036 self
.activeitem
= last
1037 self
.tree
.SetItemBold(self
.activeitem
, 1)
1038 self
.tree
.SetItemTextColour(self
.activeitem
, wxBLUE
)
1039 self
.tree
.EnsureVisible(self
.activeitem
)
1040 self
.tree
.SelectItem(self
.activeitem
)
1041 parent
= self
.tree
.GetItemParent(self
.activeitem
)
1042 self
.tree
.SetItemBold(parent
, 1)
1043 self
.tree
.SetItemTextColour(parent
, wxBLUE
)
1045 def on_file_new(self
, event
):
1048 if self
.project
!= None:
1049 dir = self
.project
.directory
1053 dlg
= wxFileDialog (self
, 'Create new file',
1055 wxSAVE|wxOVERWRITE_PROMPT
)
1056 if dlg
.ShowModal() == wxID_OK
:
1057 file = dlg
.GetPath()
1063 dlg
= wxTextEntryDialog(
1064 self
, 'Enter a title for this document:', 'Title', '',
1067 if dlg
.ShowModal() == wxID_OK
:
1068 title
= dlg
.GetValue()
1076 f
.write(len(title
)*'='+'\n')
1078 f
.write(len(title
)*'='+'\n')
1080 if self
.project
!= None:
1081 self
.project
.add(file)
1083 parent
= self
.tree
.GetItemParent(self
.activeitem
)
1084 if parent
== self
.root
:
1085 parent
= self
.activeitem
1087 self
.files
.append(file)
1089 self
.open_file_in_editor(file)
1090 last
= self
.tree
.AppendItem(parent
, file, self
.im2
)
1091 self
.tree
.SetPyData(last
, None)
1092 self
.tree
.SetItemBold(self
.activeitem
, 0)
1093 self
.tree
.SetItemTextColour(self
.activeitem
, wxBLACK
)
1094 self
.activeitem
= last
1095 self
.tree
.SetItemBold(self
.activeitem
, 1)
1096 self
.tree
.SetItemTextColour(self
.activeitem
, wxBLUE
)
1097 self
.tree
.EnsureVisible(self
.activeitem
)
1098 self
.tree
.SelectItem(self
.activeitem
)
1100 customMsgBox(self
, '%s:\n%s\n%s' % sys
.exc_info(),
1104 def on_file_remove(self
, event
):
1105 item
= self
.tree
.GetSelection()
1106 file = self
.tree
.GetItemText(item
)
1107 self
.activeitem
= self
.tree
.GetItemParent(item
)
1108 self
.tree
.Delete(item
)
1109 self
.project
.remove(file)
1111 self
.nb
.SetPageText(0, 'Editor')
1113 self
.editor
.Enable(0)
1114 self
.activateMenuItemsFileSelected(0)
1115 dlg
=wxMessageDialog(
1116 self
, 'Delete file %s from disk?' % file, NAME
,
1117 wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION
)
1118 result
= dlg
.ShowModal()
1119 if result
== wxID_YES
:
1123 customMsgBox(self
, '%s:\n%s\n%s' % sys
.exc_info(),
1127 def on_file_save(self
, event
):
1129 file = self
.tree
.GetItemText(self
.activeitem
)
1130 wxLogMessage('Saving %s.' % file)
1131 go_ahead
= self
.editor
.SaveFile(file, self
.preferences
['backup_files'])
1133 if self
.nb
.GetPageCount() > 1:
1134 self
.nb
.DeletePage(1)
1136 def on_publish(self
, event
):
1138 item
= self
.activeitem
1139 file = self
.tree
.GetItemText(item
)
1140 if self
.editor
.IsModified
:
1141 wxLogMessage('Saving %s.' % file)
1143 go_ahead
= self
.editor
.SaveFile(file, self
.preferences
['backup_files'])
1145 if go_ahead
and os
.path
.exists(file):
1146 dlg
= publishDlg(self
, infile
=file, project
=self
.project
)
1148 if dlg
.ShowModal() == wxID_OK
:
1149 outfile
, outdir
, writer
= dlg
.GetValues()
1154 self
.publishFile(file, outfile
, outdir
, writer
)
1156 def on_publish_all(self
, event
):
1158 item
= self
.activeitem
1159 file = self
.tree
.GetItemText(item
)
1160 if self
.editor
.IsModified
:
1161 wxLogMessage('Saving %s.' % file)
1163 go_ahead
= self
.editor
.SaveFile(file, self
.preferences
['backup_files'])
1166 writers
= publishers
.keys()
1168 dlg
= wxSingleChoiceDialog(self
, 'Please select a writer:',
1169 'Publish "%s"' % self
.project
.name
,
1170 writers
, wxOK|wxCANCEL
)
1171 dlg
.SetSelection(writers
.index('HTML'))
1173 if dlg
.ShowModal() == wxID_OK
:
1174 writer
= writers
[dlg
.GetSelection()]
1180 files_to_publish
= []
1181 for file in self
.project
.files
:
1182 if os
.path
.splitext(file)[1] == '.txt':
1183 files_to_publish
.append(file)
1184 max = len(files_to_publish
)
1185 dlg
= wxProgressDialog('Publishing "%s"' % self
.project
.name
,
1189 wxPD_CAN_ABORT | wxPD_APP_MODAL
)
1193 while keepGoing
and count
< max:
1194 infile
= files_to_publish
[count
]
1195 outfile
= '%s%s' % (os
.path
.splitext(os
.path
.split(infile
)[1])[0],
1196 publishers
[writer
][2])
1197 outdir
= self
.project
.directory
1198 keepGoing
= dlg
.Update(count
, outfile
)
1199 t
= time
.localtime(time
.time())
1200 st
= time
.strftime('%d-%b-%Y, %H:%M:%S', t
)
1201 wxLogMessage('\n%s: Publishing %s' % (st
, writer
))
1202 wxLogMessage('SOURCE: %s' % infile
)
1203 outfile_fullpath
= os
.path
.join(outdir
, outfile
)
1204 wxLogMessage('DESTINATION: %s' % outfile_fullpath
)
1206 publish_document(writer
, infile
, outfile
, outdir
)
1208 wxLogMessage('ERROR: %s (%s)' % sys
.exc_info()[:2])
1209 error_files
.append((infile
, sys
.exc_info()[1]))
1212 if error_files
!= []:
1213 msg
= 'Due to severe errors the following files have ' \
1214 'not been published properly: \n'
1215 for file in error_files
:
1216 msg
= '%s\n%s\n(%s)\n' % (msg
, file[0], file[1])
1217 msg
= '%s\nHINT: You should try to publish the files ' \
1218 'in question separately first. If that works, ' \
1219 'you can try to publish all files again.' % msg
1220 dlg
= wxScrolledMessageDialog(self
, msg
, "WARNING!")
1225 def on_find(self
, event
):
1226 et
= event
.GetEventType()
1227 if et
== wxEVT_COMMAND_FIND_REPLACE
or et
== wxEVT_COMMAND_FIND_REPLACE_ALL
:
1228 replacetxt
= event
.GetReplaceString()
1229 self
.sb
.SetStatusText('', 0)
1230 findtxt
= event
.GetFindString()
1231 length
= len(findtxt
)
1232 lastpos
= self
.editor
.GetTextLength()
1233 flags
= event
.GetFlags()
1234 if flags
in (1, 3, 5, 7):
1236 # whole word / match case
1237 regexp
= re
.compile(r
'\b%s\b' % findtxt
)
1239 # no whole word / match case
1240 regexp
= re
.compile(r
'%s' % findtxt
)
1242 # whole word / no match case
1243 regexp
= re
.compile(r
'\b%s\b' % findtxt
, re
.IGNORECASE
)
1245 # no whole word / no match case
1246 regexp
= re
.compile(findtxt
, re
.IGNORECASE
)
1249 print 'Unknown combination of flags.'
1251 if et
== wxEVT_COMMAND_FIND_REPLACE_ALL
:
1253 self
.editor
.BeginUndoAction()
1254 origtxt
= self
.editor
.GetText()
1255 if regexp
.search(origtxt
) != None:
1256 self
.editor
.SetText(regexp
.sub(replacetxt
, origtxt
))
1257 self
.sb
.SetStatusText('Replaced.', 0)
1259 self
.sb
.SetStatusText('No match found.', 0)
1260 self
.editor
.EndUndoAction()
1263 currpos
= self
.editor
.GetCurrentPos()
1264 if et
== wxEVT_COMMAND_FIND_REPLACE
and currpos
!= 0:
1265 self
.editor
.ReplaceSelection(replacetxt
)
1266 currpos
= self
.editor
.GetCurrentPos()
1267 lastpos
= self
.editor
.GetTextLength()
1268 origtxt
= self
.editor
.GetTextRange(currpos
, lastpos
)
1269 position
= len(regexp
.split(origtxt
)[0])
1270 startpos
= currpos
+ position
1271 if startpos
< lastpos
:
1272 self
.editor
.GotoPos(startpos
+ len(regexp
.findall(origtxt
)[0]))
1273 self
.editor
.SetAnchor(startpos
)
1275 self
.sb
.SetStatusText('Can not find "%s". Next search will '
1276 'start from beginning.' % findtxt
, 0)
1277 self
.editor
.GotoPos(0)
1279 def on_find_close(self
, event
):
1280 event
.GetDialog().Destroy()
1282 def on_findreplace_show(self
, event
):
1283 data
= wxFindReplaceData()
1284 dlg
= wxFindReplaceDialog(self
, data
, 'Find & Replace',
1289 def on_font_small(self
, event
):
1290 self
.preferences
['fontsize'] = 'small'
1291 self
.editor
.SetZoom(-2)
1292 self
.save_preferences()
1294 def on_font_normal(self
, event
):
1295 self
.preferences
['fontsize'] = 'normal'
1296 self
.editor
.SetZoom(0)
1297 self
.save_preferences()
1299 def on_font_big(self
, event
):
1300 self
.preferences
['fontsize'] = 'big'
1301 self
.editor
.SetZoom(2)
1302 self
.save_preferences()
1304 def on_format_paragraph(self
, event
):
1305 self
.nb
.SetSelection(0)
1306 line_no
= self
.editor
.GetCurrentLine()
1307 self
.editor
.GotoLine(line_no
)
1308 startpos
= self
.editor
.GetCurrentPos()
1309 line
= self
.editor
.GetLine(line_no
)
1310 endpos
= startpos
+ len(line
)
1311 self
.editor
.SetSelection(startpos
, endpos
)
1312 format
= event
.GetString()
1313 if format
in ['Title','Subtitle']:
1314 overline
= (len(line
)-1)*self
.formats
[format
]+'\n'
1317 underline
= (len(line
)-1)*self
.formats
[format
]+'\n'
1318 line_below
= self
.editor
.GetLine(line_no
+1)
1319 if line
!= underline
and line_below
!= underline
:
1320 self
.editor
.ReplaceSelection('\n%s%s%s\n' % (overline
,
1323 self
.editor
.GotoPos(startpos
)
1325 def on_format_word(self
, event
):
1326 self
.nb
.SetSelection(0)
1327 selection
= self
.editor
.GetSelectedText()
1329 if event
.GetId() == wxID_WXBTNBOLD
:
1331 elif event
.GetId() == wxID_WXBTNITALIC
:
1333 elif event
.GetId() == wxID_WXBTNLITERAL
:
1337 selection
= selection
.replace('*','').replace('`','').strip()
1338 selection
= '%s%s%s' % (symbol
,selection
,symbol
)
1339 self
.editor
.ReplaceSelection(selection
)
1341 def on_goto(self
, event
):
1343 for i
in range(self
.editor
.GetLineCount()+1)[1:]:
1344 values
.append(str(i
))
1345 dlg
= wxSingleChoiceDialog(self
, 'Select a line number:', 'Goto line...',
1346 values
, wxOK|wxCANCEL
)
1347 if dlg
.ShowModal() == wxID_OK
:
1348 self
.editor
.GotoLine(int(dlg
.GetStringSelection())-1)
1351 def on_help_about(self
, event
):
1353 Event handler for menu
1354 option *Help -> About*.
1356 dlg
= aboutDlg(self
)
1363 def on_insert_figure(self
, event
):
1364 self
.insert_image('figure')
1366 def on_btn_hyperlink(self
, event
):
1367 self
.insert_hyperlink()
1369 def on_insert_image(self
, event
):
1370 self
.insert_image('image')
1372 def on_insert_path(self
, event
):
1373 item
= self
.activeitem
1374 itemimage
= self
.tree
.GetItemImage(item
)
1375 file = self
.tree
.GetItemText(item
)
1376 if self
.project
!= None:
1377 dir = self
.project
.directory
1379 dir = os
.path
.dirname(file)
1380 dlg
= wxFileDialog (self
, 'Choose file',
1382 wxOPEN|wxFILE_MUST_EXIST
)
1384 if dlg
.ShowModal() == wxID_OK
:
1385 target
= dlg
.GetPath()
1389 if self
.project
!= None:
1390 dir = self
.project
.directory
1392 dir = os
.path
.dirname(file)
1393 dlg
= wxDirDialog(self
, 'Calculate path relative'
1394 ' to which outputdirectory?', dir)
1395 if dlg
.ShowModal() == wxID_OK
:
1401 self
.editor
.ReplaceSelection(
1402 quote(relative_path(self
.htmlfile(file,dir), target
)))
1405 def on_notebook_page_changed(self
, event
):
1408 def on_paste(self
, event
):
1411 def on_project_delete(self
, event
):
1412 available_projects
= []
1413 for project
in self
.projects
:
1414 available_projects
.append(project
.name
)
1415 if available_projects
!= []:
1416 available_projects
.sort()
1417 dlg
= wxMultipleChoiceDialog(self
, 'Select the projects which you want to' \
1418 '\ndelete or press "Cancel" to abort.',
1422 if dlg
.ShowModal() == wxID_OK
:
1423 selection
= dlg
.GetValueString()
1424 for project_name
in selection
:
1425 for project
in self
.projects
:
1426 if project
.name
== project_name
:
1427 self
.delete_project(project
)
1430 customMsgBox(self
, 'Sorry, I don\'t remember any projects.',
1433 def on_project_new(self
, event
):
1436 other_project_names
= []
1437 for project
in self
.projects
:
1438 other_project_names
.append(project
.name
)
1440 if self
.CheckEditorChanges():
1441 project
= DocProject()
1442 dlg
= projectSettingsDlg(self
, project
, other_project_names
)
1444 if dlg
.ShowModal() == wxID_CANCEL
:
1447 self
.project
= project
1448 self
.project
.name
, self
.project
.directory
= dlg
.getValues()
1453 self
.projects
.append(self
.project
)
1454 self
.save_projects()
1457 customMsgBox(self
, '%s:\n%s\n%s' % sys
.exc_info(), 'error')
1459 def on_project_settings(self
, event
):
1462 other_project_names
= []
1463 for project
in self
.projects
:
1464 if project
.name
!= self
.project
.name
:
1465 other_project_names
.append(project
.name
)
1467 dlg
= projectSettingsDlg(self
, self
.project
, other_project_names
)
1469 if dlg
.ShowModal() == wxID_CANCEL
:
1472 name
, directory
= dlg
.getValues()
1473 self
.set_editor_language_code()
1478 if self
.project
.name
!= name
:
1479 self
.projectdirty
= 1
1481 for project
in self
.projects
:
1482 if project
.name
== self
.project
.name
:
1484 self
.project
.name
= name
1485 if self
.project
.directory
!= directory
:
1486 self
.project
.directory
= directory
1487 self
.projectdirty
= 1
1489 if self
.projectdirty
:
1494 def on_redo(self
, event
):
1497 def on_run_tool(self
, event
):
1500 for tool
in self
.tools
.values():
1501 choices
.append('%s: %s' % (tool
[0],tool
[1]))
1502 dlg
= wxSingleChoiceDialog(self
, 'Select a tool...', 'Toolbox',
1503 choices
, wxOK|wxCANCEL
)
1505 if dlg
.ShowModal() == wxID_OK
:
1506 tool_id
=int(dlg
.GetStringSelection().split(':')[0])
1507 for key
in self
.tools
.keys():
1508 if self
.tools
[key
][0] == tool_id
:
1516 tool
= self
.tools
[tool_key
]
1517 item
= self
.activeitem
1518 file = self
.tree
.GetItemText(item
)
1519 curdir
= os
.getcwd()
1521 replmts
= {'$[FileDir]': os
.path
.split(file)[0],
1522 '$[FilePath]': file,
1523 '$[FileName]': os
.path
.split(file)[1],
1524 '$[FileBase]': os
.path
.splitext(os
.path
.basename(file))[0],
1525 '$[ProjectDir]': self
.project
.directory
}
1527 for str in replmts
.keys():
1528 command
= command
.replace(str, replmts
[str])
1530 for str in replmts
.keys():
1531 directory
= directory
.replace(str, replmts
[str])
1534 customMsgBox(self
, '%s:\n%s\n%s' % sys
.exc_info(), 'error')
1536 t
= time
.localtime(time
.time())
1537 st
= time
.strftime('%d-%b-%Y, %H:%M:%S', t
)
1538 wxLogMessage('%s: %s' % (st
, tool
[1]))
1539 wxLogMessage('COMMAND: %s\nDIRECTORY: %s' % (command
, directory
))
1543 t
= time
.localtime(time
.time())
1544 st
= time
.strftime('%d-%b-%Y, %H:%M:%S', t
)
1545 wxLogMessage('%s: Finished.' % st
)
1547 customMsgBox(self
, '%s:\n%s\n%s' % sys
.exc_info(), 'error')
1550 def on_select_all(self
, event
):
1551 self
.editor
.SelectAll()
1553 def on_tree_item_activated(self
, event
):
1554 item
=event
.GetItem()
1557 if item
!= self
.activeitem \
1558 and self
.tree
.GetItemImage(self
.activeitem
) == self
.im2
:
1559 go_ahead
= self
.CheckEditorChanges()
1562 self
.nb
.SetSelection(0)
1563 if item
!= self
.activeitem
:
1564 if self
.activeitem
!= self
.root
:
1565 olditemparent
= self
.tree
.GetItemParent(self
.activeitem
)
1566 self
.tree
.SetItemBold(olditemparent
, 0)
1567 self
.tree
.SetItemTextColour(olditemparent
, wxBLACK
)
1568 self
.tree
.SetItemBold(self
.activeitem
, 0)
1569 self
.tree
.SetItemTextColour(self
.activeitem
, wxBLACK
)
1570 self
.activeitem
= item
1571 self
.tree
.SetItemBold(item
, 1)
1572 if item
!= self
.root
:
1573 self
.tree
.SetItemTextColour(item
, wxBLUE
)
1578 itemparent
= self
.tree
.GetItemParent(item
)
1579 itemimage
= self
.tree
.GetItemImage(item
)
1582 if itemimage
== self
.im2
:
1583 # file is part of project:
1584 if self
.tree
.GetItemImage(itemparent
) == self
.im1
:
1585 self
.tree
.SetItemBold(itemparent
, 1)
1586 self
.tree
.SetItemTextColour(itemparent
, wxBLUE
)
1587 project_name
= self
.tree
.GetItemText(itemparent
)
1588 for project
in self
.projects
:
1589 if project
.name
== project_name
:
1590 self
.project
= project
1591 self
.activateMenuItemsProjectOpen(1)
1592 # file is not part of project:
1595 self
.activateMenuItemsProjectOpen(0)
1596 file=self
.tree
.GetItemText(item
)
1597 if os
.path
.exists(file):
1598 self
.open_file_in_editor(file)
1601 self
.editor
.Enable(0)
1602 self
.nb
.SetPageText(0, 'Editor')
1603 self
.activateMenuItemsFileSelected(0)
1604 parent
= self
.tree
.GetItemParent(item
)
1605 self
.tree
.SetItemBold(item
, 0)
1606 self
.tree
.SetItemTextColour(item
, wxBLACK
)
1607 self
.activeitem
= parent
1608 dlg
=wxMessageDialog(self
, '%s does not exist.\nRemove '
1609 'from project?' % file,
1610 NAME
, wxYES_NO | wxICON_QUESTION
)
1611 if dlg
.ShowModal() == wxID_YES
:
1612 self
.tree
.Delete(item
)
1613 self
.project
.remove(file)
1616 self
.tree
.SelectItem(self
.activeitem
)
1619 elif itemimage
== self
.im1
:
1620 project_name
= self
.tree
.GetItemText(item
)
1621 for project
in self
.projects
:
1622 if project
.name
== project_name
:
1623 self
.project
= project
1624 self
.activateMenuItemsProjectOpen(1)
1625 self
.nb
.SetPageText(0, 'Editor')
1627 self
.editor
.Enable(0)
1628 self
.activateMenuItemsFileSelected(0)
1630 # item is neither file nor project:
1632 self
.nb
.SetPageText(0, 'Editor')
1634 self
.editor
.Enable(0)
1636 self
.activateMenuItemsProjectOpen(0)
1637 self
.activateMenuItemsFileSelected(0)
1639 def on_undo(self
, event
):
1642 def on_view_eols(self
, event
):
1643 self
.preferences
['eol_markers'] = not self
.preferences
['eol_markers']
1644 self
.editor
.SetViewEOL(self
.preferences
['eol_markers'])
1645 self
.save_preferences()
1647 def on_view_edge(self
, event
):
1648 self
.preferences
['right_edge_indicator'] = not self
.preferences
['right_edge_indicator']
1649 self
.editor
.SetEdgeMode(self
.preferences
['right_edge_indicator'])
1650 self
.save_preferences()
1652 def on_view_ws(self
, event
):
1653 self
.preferences
['whitespace'] = not self
.preferences
['whitespace']
1654 self
.editor
.SetViewWhiteSpace(self
.preferences
['whitespace'])
1655 self
.save_preferences()
1657 #---------------------------------------------------------------------------
1659 class FactoryApp(wxApp
):
1661 provider
= wxSimpleHelpProvider()
1662 wxHelpProvider_Set(provider
)
1664 if self
.init_projects():
1665 wxInitAllImageHandlers()
1666 if len(sys
.argv
) > 1:
1667 frame
= DocFactoryFrame(self
.projects
, sys
.argv
[1])
1669 frame
= DocFactoryFrame(self
.projects
)
1670 self
.SetTopWindow(frame
)
1675 def init_projects(self
):
1676 if os
.path
.exists(DATA
):
1678 cfg
= ConfigParser
.ConfigParser()
1680 for section
in cfg
.sections():
1681 if section
[:19] == 'docfactory_project:':
1682 project
= DocProject()
1683 project
.name
= section
.split(': ')[1]
1684 project
.directory
= cfg
.get(section
, 'outputdirectory')
1685 if cfg
.has_option(section
, 'files'):
1686 project
.files
= cfg
.get(section
, 'files').split(';')
1687 if project
.files
== ['']:
1689 self
.projects
.append(project
)
1691 f
= open('error.txt', 'w')
1692 f
.write('%s:\n%s\n%s' % sys
.exc_info())
1697 #--------------------------------------------------------------------------
1703 #--------------------------------------------------------------------------
1705 if __name__
== '__main__':
1708 #--------------------------------------------------------------------------