1 # -*- coding: UTF-8 -*-
6 # Copyright (C) 2006 Facundo Batista <facundo@taniquetil.com.ar>
8 # This file is placed under the Python 2.3 license, see
9 # http://www.python.org/2.3/license.html
13 import wx
.html
as html
14 import user
, codecs
, os
16 from docutils
.core
import publish_file
19 # We must integrate this with gettext() later
30 wxID_CONFIGURATION
= 202
36 # Key: what you'll see in the radiobox
37 # Value: (writer name for docutils, file extension)
38 FORMATS
= {"HTML": ("html", ".html"),
39 "LaTeX": ("latex", ".tex"),
40 "XML": ("xml", ".xml"),
43 class ControlPanel(wx
.Panel
):
44 """Panel with the files selections grid."""
46 def __init__(self
, parent
, vsProc
):
47 wx
.Panel
.__init
__(self
, parent
, -1, style
=wx
.WANTS_CHARS
)
52 gbs
= wx
.GridBagSizer(3, 4)
56 label
= wx
.StaticText(self
, -1, _("Source file:"))
60 self
.teSource
= wx
.TextCtrl(self
, id, "", size
=(200,-1), style
=wx
.TE_PROCESS_ENTER
)
61 wx
.EVT_TEXT_ENTER(self
.teSource
, id, self
.enteredSourceText
)
62 gbs
.Add(self
.teSource
, (0,1), flag
=wx
.EXPAND
)
63 self
.vsProc
.registerEditor(self
.teSource
, "")
65 sBtn
= wx
.Button(self
, wx
.ID_OPEN
)
66 wx
.EVT_BUTTON(sBtn
, wx
.ID_OPEN
, parent
.onFileOpen
)
71 label
= wx
.StaticText(self
, -1, _("Destination file:"))
75 self
.teDestin
= wx
.TextCtrl(self
, id, "", size
=(200,-1), style
=wx
.TE_PROCESS_ENTER
)
76 wx
.EVT_TEXT_ENTER(self
.teDestin
, id, self
.enteredDestinText
)
77 gbs
.Add(self
.teDestin
, (1,1), flag
=wx
.EXPAND
)
78 self
.vsProc
.registerEditor(self
.teDestin
, "")
80 dBtn
= wx
.Button(self
, wx
.ID_SAVE
)
81 wx
.EVT_BUTTON(dBtn
, wx
.ID_SAVE
, parent
.onDestChooser
)
86 self
.options
= ["HTML", "LaTeX", "XML"]
87 self
.rbFormat
= wx
.RadioBox(self
, id, _("Destination format"), wx
.DefaultPosition
, wx
.DefaultSize
, self
.options
, 1, style
=wx
.RA_SPECIFY_COLS
)
88 wx
.EVT_RADIOBOX(self
.rbFormat
, id, self
.rbSelection
)
89 gbs
.Add(self
.rbFormat
, (0,3), (3,1))
93 procBtn
= wx
.Button(self
, id, _("Process"))
94 wx
.EVT_BUTTON(procBtn
, id, parent
.goProcess
)
95 vsProc
.registerAction(procBtn
)
96 gbs
.Add(procBtn
, (2,4))
101 def enteredSourceText(self
, event
):
102 self
.parent
.onFileOpen(None, self
.teSource
.GetValue())
105 def enteredDestinText(self
, event
):
106 self
.parent
.onDestChooser(None, self
.teDestin
.GetValue())
109 def rbSelection(self
, event
):
110 # check what was chosen
111 chosen
= event
.GetSelection()
112 format
= self
.options
[chosen
]
114 # change the filename
115 filename
= self
.teDestin
.GetValue()
116 for ext
in [x
[1] for x
in FORMATS
.values()]:
117 if filename
.endswith(ext
):
118 filename
= filename
[:-len(ext
)]
119 filename
+= FORMATS
[format
][1]
120 self
.teDestin
.SetValue(filename
)
121 self
.enteredDestinText(None)
126 class TextsPanel(wx
.Panel
):
127 """Panel with the texts fields."""
129 def __init__(self
, parent
, vsProc
):
130 wx
.Panel
.__init
__(self
, parent
, -1, style
=wx
.WANTS_CHARS
)
133 box
= wx
.BoxSizer(wx
.HORIZONTAL
)
136 self
.oText
= wx
.TextCtrl(self
, -1, size
=(200, 100), style
=wx
.TE_MULTILINE|wx
.TE_RICH2|wx
.TE_READONLY
)
137 box
.Add(self
.oText
, 1, wx
.EXPAND|wx
.ALL
, border
=10)
138 self
.vsProc
.registerEditor(self
.oText
, "")
139 # put monospaced font
140 font
= self
.oText
.GetFont()
141 font
= wx
.Font(font
.GetPointSize(), wx
.TELETYPE
, font
.GetStyle(), font
.GetWeight(), font
.GetUnderlined())
142 self
.oText
.SetFont(font
)
145 self
.dText
= html
.HtmlWindow(self
, -1, style
=wx
.NO_FULL_REPAINT_ON_RESIZE
)
146 if "gtk2" in wx
.PlatformInfo
:
147 self
.dText
.SetStandardFonts()
148 box
.Add(self
.dText
, 1, wx
.EXPAND|wx
.ALL
, border
=10)
153 def setSourceText(self
, text
):
154 self
.vsProc
.setEditorState(self
.oText
, bool(text
))
155 self
.oText
.SetValue(text
)
158 def setDestinText(self
, filename
):
159 self
.dText
.LoadPage(filename
)
161 class MenuEnabler(object):
162 '''Receives all the items that must be enabled or disabled according to if the there's an open project or not.'''
163 def __init__(self
, menuBar
, itemList
):
164 self
.menuBar
= menuBar
165 self
.itemList
= itemList
167 def Enable(self
, newState
):
168 for item
in self
.itemList
:
169 self
.menuBar
.Enable(item
, newState
)
173 class MyFrame(wx
.Frame
):
174 def __init__(self
, parent
, ID
, title
):
175 wx
.Frame
.__init
__(self
, parent
, ID
, title
, pos
=(-1,-1), size
=wx
.Size(600, 400))
177 self
.CreateStatusBar()
178 self
.previousMessage
= ""
179 self
.statusBar(_("Welcome to Docutils"))
180 menuBar
= wx
.MenuBar()
182 # Validator to check if the project is open and enable/disable the menu
183 self
.vsSourceOpen
= validator
.ValidationSupervisor(self
.statusBar
, "originIsOpen")
186 self
.vsProc
= validator
.ValidationSupervisor(self
.statusBar
, "vsProcess")
190 menu
.Append(wxID_OPEN
, _("&Open")+"\tCtrl-O", _("Open a source file to process"))
191 menu
.Append(wxID_CLOSE
, _("&Close")+"\tCtrl-W", _("Close the current source file"))
192 menu
.Append(wxID_EXIT
, _("&Exit")+"\tCtrl-Q", _("Exit Docutils"))
193 menuBar
.Append(menu
, _("&File"))
194 wx
.EVT_MENU(self
, wxID_OPEN
, self
.onFileOpen
)
195 wx
.EVT_MENU(self
, wxID_CLOSE
, self
.onFileClose
)
196 wx
.EVT_MENU(self
, wxID_EXIT
, self
.onFileExit
)
197 enablerItemList
.append(wxID_CLOSE
)
200 menu
.Append(wxID_PROCESS
, _("&Process"), _("Process the origin file"))
201 menu
.Append(wxID_CONFIGURATION
, _("&Configure"), _("Configure Distutils options"))
202 menuBar
.Append(menu
, _("&Actions"))
203 wx
.EVT_MENU(self
, wxID_PROCESS
, self
.onNotImplementedYet
)
204 wx
.EVT_MENU(self
, wxID_CONFIGURATION
, self
.onNotImplementedYet
)
205 enablerItemList
.append(wxID_PROCESS
)
208 menu
.Append(wxID_USERGUIDE
, _("&User guide")+"\tF1", _("Browse the user guide"))
209 menu
.Append(wxID_ABOUT
, _("&About Docutils"), _("Show information about Docutils"))
210 menuBar
.Append(menu
, _("&Help"))
211 wx
.EVT_MENU(self
, wxID_USERGUIDE
, self
.onNotImplementedYet
)
212 wx
.EVT_MENU(self
, wxID_ABOUT
, self
.onNotImplementedYet
)
214 # finish setting up the menu
215 self
.SetMenuBar(menuBar
)
217 # Enabling and disabling options
218 menuEnablerOpen
= MenuEnabler(menuBar
, enablerItemList
)
219 self
.vsSourceOpen
.registerAction(menuEnablerOpen
)
220 self
.vsSourceOpen
.registerEditor(self
, "")
223 self
.cp
= ControlPanel(self
, self
.vsProc
)
224 self
.tp
= TextsPanel(self
, self
.vsProc
)
226 allBox
= wx
.BoxSizer(wx
.VERTICAL
)
227 allBox
.Add(self
.cp
, 0, wx
.EXPAND | wx
.ALL
, border
=5)
228 allBox
.Add(self
.tp
, 1, wx
.EXPAND | wx
.ALL
, border
=5)
229 self
.SetSizer(allBox
)
232 wx
.EVT_CLOSE(self
, self
.onFileExit
)
237 def statusBar(self
, message
):
238 if message
== self
.previousMessage
:
240 self
.SetStatusText(message
)
241 self
.previousMessage
= message
244 def onNotImplementedYet(self
, event
):
245 self
.SetStatusText(_("ERROR: Menu option not yet implemented"))
249 #~ def OnAbout(self, event):
250 #~ dlg = wx.MessageDialog(self, "This sample program shows off\n"
251 #~ "frames, menus, statusbars, and this\n"
252 #~ "message dialog.",
253 #~ "About Me", wx.ICON_EXCLAMATION | wx.ICON_INFORMATION)
257 def onFileOpen(self
, event
, filename
=None):
258 if filename
is not None:
259 if not os
.access(filename
, os
.R_OK
):
260 dlg
= wx
.MessageDialog(self
, _('Such file does not exists!'), _('Error'), wx
.OK | wx
.ICON_ERROR
)
265 # open a user selected file
266 wildcard
= _("Text files (*.txt)") + "|*.txt|" + \
267 _("All files (*.*)") + "|*.*"
268 dlg
= wx
.FileDialog(self
, _("Choose a source file to process"), user
.home
, wildcard
=wildcard
, style
=wx
.OPEN|wx
.HIDE_READONLY
)
270 if dlg
.ShowModal() != wx
.ID_OK
:
272 self
.statusBar(_("The file selection was cancelled"))
275 filename
= dlg
.GetPath()
279 self
.tp
.setSourceText(codecs
.open(filename
).read())
280 self
.cp
.teSource
.SetValue(filename
)
281 self
.vsSourceOpen
.setEditorState(self
, True)
282 self
.vsProc
.setEditorState(self
.cp
.teSource
, True)
283 self
.statusBar(_("A new source file was opened"))
286 def onFileClose(self
, event
):
288 self
.tp
.setSourceText("")
289 self
.cp
.teSource
.SetValue("")
290 self
.cp
.teDestin
.SetValue("")
292 self
.vsProc
.setEditorState(self
.cp
.teSource
, False)
293 self
.vsProc
.setEditorState(self
.cp
.teDestin
, False)
294 self
.vsSourceOpen
.setEditorState(self
, False)
297 def onFileExit(self
, event
):
300 def onDestChooser(self
, event
, filename
=None):
302 # let's ask the project filename
303 wildcard
= _("Text files (*.txt)") + "|*.txt|" + \
304 _("All files (*.*)") + "|*.*"
305 dlg
= wx
.FileDialog(self
, _("Choose a file to save the result"), user
.home
, wildcard
=wildcard
, style
=wx
.SAVE
)
306 if dlg
.ShowModal() != wx
.ID_OK
:
308 self
.statusBar(_("The file selection was cancelled"))
311 filename
= dlg
.GetPath()
314 # append the correct extension if we need to
315 format
= self
.cp
.rbFormat
.GetStringSelection()
316 ext
= FORMATS
[format
][1]
317 if not filename
.endswith(ext
):
320 # check file permission
321 if os
.access(filename
, os
.F_OK
)and not os
.access(filename
, os
.W_OK
):
322 dlg
= wx
.MessageDialog(self
, _('Such name is not valid for a writable file!'), _('Error'), wx
.OK | wx
.ICON_ERROR
)
328 self
.cp
.teDestin
.SetValue(filename
)
329 self
.vsProc
.setEditorState(self
.cp
.teDestin
, True)
330 self
.statusBar(_("A destination file was selected"))
333 def goProcess(self
, event
):
335 inp
= self
.cp
.teSource
.GetValue()
336 out
= self
.cp
.teDestin
.GetValue()
337 format
= self
.cp
.rbFormat
.GetStringSelection()
340 wn
= FORMATS
[format
][0]
341 publish_file(source_path
=inp
, destination_path
=out
, writer_name
=wn
)
342 self
.tp
.setDestinText(out
)
348 frame
= MyFrame(None, -1, "Docutils")
350 self
.SetTopWindow(frame
)
353 if __name__
== "__main__":