1 |
# |
# |
|
# Copyright 2001-2002 Free Software Foundation |
|
|
# |
|
2 |
# This file is part of GNU Enterprise. |
# This file is part of GNU Enterprise. |
3 |
# |
# |
4 |
# GNU Enterprise is free software; you can redistribute it |
# GNU Enterprise is free software; you can redistribute it |
16 |
# write to the Free Software Foundation, Inc., 59 Temple Place |
# write to the Free Software Foundation, Inc., 59 Temple Place |
17 |
# - Suite 330, Boston, MA 02111-1307, USA. |
# - Suite 330, Boston, MA 02111-1307, USA. |
18 |
# |
# |
19 |
|
# Copyright 2001-2003 Free Software Foundation |
20 |
|
# |
21 |
# FILE: |
# FILE: |
22 |
# LayoutEditor.py |
# LayoutEditor.py |
23 |
# |
# |
29 |
import sys, os |
import sys, os |
30 |
from wxPython.wx import * |
from wxPython.wx import * |
31 |
from gnue.common import GDebug |
from gnue.common import GDebug |
32 |
from gnue.forms import GFObjects |
from gnue.forms import GFObjects |
33 |
from gnue.forms.uidrivers.wx import UIdriver as UIwxpython |
from gnue.forms.uidrivers.wx import UIdriver as UIwxpython |
34 |
from gnue.designer.PopupMenu import PageMenu |
from gnue.designer.base.PopupMenu import PageMenu |
35 |
from gnue.designer.forms import Incubator |
from gnue.designer.base.TemplateParser import TemplateParser |
36 |
from gnue.designer.TemplateParser import TemplateParser |
from gnue.designer.base.ToolPanel import * |
37 |
from gnue.common.events import Event |
from gnue.common.events import Event |
38 |
|
|
39 |
# My support files |
# My support files |
45 |
from DisplayDropTarget import DisplayDropTarget |
from DisplayDropTarget import DisplayDropTarget |
46 |
|
|
47 |
|
|
48 |
class LayoutEditor (wxPanel): |
class LayoutEditor (ToolPanel): |
49 |
def __init__(self, instance, parentWindow): |
|
50 |
wxPanel.__init__(self,parentWindow,-1) |
runtime_section = "FormsLayoutEditor" |
51 |
self.frame = instance |
default_dock = DOCK_TOPRIGHT |
52 |
self.panelColor = self.GetBackgroundColour() |
uses_feedback_header = 1 |
53 |
self._instance = instance |
|
54 |
self.rootObject = instance.rootObject |
def init(self): |
55 |
self._app = instance._app |
|
56 |
|
# TODO: blah.... historical reasons |
57 |
|
self._instance = self.instance |
58 |
|
|
59 |
|
# TODO: this needs to go away... requires toolbar to be on main frame |
60 |
|
self.frame = self.instance |
61 |
|
|
62 |
|
self._app = self.instance._app |
63 |
self.widgets = {} |
self.widgets = {} |
64 |
self.widgets.update(UIwxpython.WIDGETS) |
self.widgets.update(UIwxpython.WIDGETS) |
|
self.toolbar = LayoutEditorTools(self, self.frame) |
|
65 |
del self.widgets['GFPage'] |
del self.widgets['GFPage'] |
66 |
|
|
67 |
|
|
68 |
self.notebook = wxNotebook(self, -1, pos=wxPoint(4, 4), size=wxSize(32,32)) |
self.notebook = wxNotebook(self, -1, pos=wxPoint(4, 4), size=wxSize(32,32)) |
69 |
self.backcolor = wxWHITE |
self.backcolor = wxWHITE |
70 |
self.propBar = PropertyBar(self) |
#self.propBar = PropertyBar(self) |
71 |
|
self.toolbar = LayoutEditorTools(self, self.frame) |
72 |
|
self.blockCombo = self.toolbar.blockCombo |
73 |
|
EVT_COMBOBOX(self.toolbar, self.blockCombo.GetId(), self.OnBlockSelected) |
74 |
|
|
75 |
EVT_NOTEBOOK_PAGE_CHANGED(self,self.notebook.GetId(), self.OnPageSelected) |
EVT_NOTEBOOK_PAGE_CHANGED(self,self.notebook.GetId(), self.OnPageSelected) |
76 |
EVT_SIZE(self, self.OnSize) |
EVT_SIZE(self, self.OnSize) |
78 |
self.page = None |
self.page = None |
79 |
self.block = None |
self.block = None |
80 |
self.lastBlock = None |
self.lastBlock = None |
81 |
|
self.blockMap = {} |
82 |
self.panel = None |
self.panel = None |
83 |
self._notebookMap = {} |
self._notebookMap = {} |
84 |
self._pageList = [] # Needed by UIwxpython |
self._pageList = [] # Needed by UIwxpython |
85 |
self.positionMappings = {} |
self.positionMappings = {} |
86 |
self.widgetList = [] |
self.widgetList = [] |
87 |
|
|
88 |
|
self._currentObject = None |
89 |
self.mode = 'move' |
self.mode = 'move' |
90 |
self.__x = 0 |
self.__x = 0 |
91 |
self.__y = 0 |
self.__y = 0 |
92 |
self.__ox = 0 |
self.__ox = 0 |
93 |
self.__oy = 0 |
self.__oy = 0 |
94 |
|
|
95 |
instance.rootObject.walk (self.inventoryObject) |
|
96 |
|
# EventAware provided by ToolPanel |
97 |
|
self.registerEventListeners({ |
98 |
|
'ObjectSelected' : self.onSetCurrentObject, |
99 |
|
'ObjectCreated' : self.onCreateObject, |
100 |
|
'ObjectModified' : self.onModifyObject, |
101 |
|
'ObjectDeleted' : self.onDeleteObject, |
102 |
|
}) |
103 |
|
|
104 |
|
self.instance.rootObject.walk (self.inventoryObject) |
105 |
|
self._rebuildBlockCombo() |
106 |
try: |
try: |
107 |
self._setCurrentPage(self._notebookMap[0]) |
self._setCurrentPage(self._notebookMap[0]) |
108 |
except KeyError: |
except KeyError: |
109 |
pass |
pass |
110 |
|
|
111 |
self.frame.SetToolBar(self.toolbar) |
self._setFeedback() |
112 |
|
|
113 |
|
## TODO: Fix me |
114 |
|
self.instance.SetToolBar(self.toolbar) |
115 |
|
## |
116 |
|
|
117 |
def inventoryObject(self, object): |
def inventoryObject(self, object): |
118 |
if object._type == 'GFPage': |
if object._type == 'GFPage': |
135 |
self.notebook.AddPage(self.workspacescroll,object.name) |
self.notebook.AddPage(self.workspacescroll,object.name) |
136 |
object.__workspace = self.workspace |
object.__workspace = self.workspace |
137 |
self.drawPage(object) |
self.drawPage(object) |
138 |
|
if object._type == 'GFBlock': |
139 |
|
self.blockMap[object.name.lower()] = object |
140 |
def onSetCurrentObject (self, object, handler): |
if not self.block: |
141 |
|
self._setCurrentBlock(object) |
142 |
|
|
143 |
|
def onSetCurrentObject (self, event): |
144 |
|
object = event.object |
145 |
|
handler = event.originator |
146 |
self._currentObject = object |
self._currentObject = object |
147 |
if object == None: |
if object == None: |
148 |
for o in self._currentSelection.keys(): |
for o in self._currentSelection.keys(): |
149 |
o.setSelected(0) |
o.setSelected(0) |
150 |
return |
return |
151 |
if hasattr(object, '_widgetHandler'): |
## if hasattr(object, '_widgetHandler'): |
152 |
self.propBar.setCurrentObject(object) |
## self.propBar.setCurrentObject(object) |
153 |
if handler != "Forms::LayoutEditor": |
if handler != "Forms::LayoutEditor": |
154 |
self._setCurrentPage(object) |
self._setCurrentPage(object) |
155 |
|
self._setCurrentBlock(object) |
156 |
|
self._setFeedback() |
157 |
|
|
158 |
|
def _setCurrentBlock(self,object): |
159 |
|
if not object: |
160 |
|
return |
161 |
|
block = object.findParentOfType('GFBlock') |
162 |
|
if not block: |
163 |
|
if object._type == 'GFEntry': |
164 |
|
block = object._block |
165 |
|
if block: |
166 |
|
self.block = block |
167 |
|
self.blockCombo.SetValue(block.name) |
168 |
|
## self._setFeedback() |
169 |
|
|
170 |
def _setCurrentPage(self, object): |
def _rebuildBlockCombo(self): |
171 |
|
# TODO |
172 |
|
srt = self.blockMap.keys() |
173 |
|
srt.sort() |
174 |
|
self.blockComboList = [] |
175 |
|
self.blockCombo.Clear() |
176 |
|
for key in srt: |
177 |
|
block = self.blockMap[key] |
178 |
|
self.blockCombo.Append(block.name) |
179 |
|
self.blockComboList.append(block) |
180 |
|
if self.block: |
181 |
|
self.blockCombo.SetValue(self.block.name) |
182 |
|
|
183 |
|
def OnBlockSelected(self, event): |
184 |
|
s= event.GetSelection() |
185 |
|
block = self.blockComboList[s] |
186 |
|
if block != self.block: |
187 |
|
self.dispatchEvent('ObjectSelected', |
188 |
|
object = block, |
189 |
|
originator = None) |
190 |
|
|
191 |
|
def _setFeedback(self): |
192 |
|
|
193 |
|
object = self._currentObject |
194 |
|
|
195 |
|
ft = "" |
196 |
|
|
197 |
|
if object: |
198 |
|
try: ft += 'Name: % (%s)' % (object.name, object._type[2:]) |
199 |
|
except: pass |
200 |
|
|
201 |
|
try: ft += ' x: %s' % object.Char__x |
202 |
|
except: pass |
203 |
|
|
204 |
|
try: ft += ' y: %s' % object.Char__y |
205 |
|
except: pass |
206 |
|
|
207 |
|
try: ft += ' w: %s' % object.Char__width |
208 |
|
except: pass |
209 |
|
|
210 |
|
try: |
211 |
|
if object.Char__height > 1: |
212 |
|
ft += ' h: %s' % object.Char__height |
213 |
|
except: |
214 |
|
pass |
215 |
|
|
216 |
|
self.setHeaderText(ft) |
217 |
|
|
218 |
|
|
219 |
|
def _setCurrentPage(self, object): |
220 |
page = isinstance(object, GFObjects.GFPage) and object or \ |
page = isinstance(object, GFObjects.GFPage) and object or \ |
221 |
object.findParentOfType('GFPage') |
object.findParentOfType('GFPage') |
222 |
|
|
252 |
object._widgetHandler.setSelected(1) |
object._widgetHandler.setSelected(1) |
253 |
|
|
254 |
|
|
255 |
def onCreateObject (self, object, handler): |
def onCreateObject (self, event): |
256 |
|
object = event.object |
257 |
|
handler = event.originator |
258 |
self._currentSelection = {} |
self._currentSelection = {} |
259 |
if object == None: |
if object == None: |
260 |
return |
return |
270 |
|
|
271 |
self.inventoryObject(object) |
self.inventoryObject(object) |
272 |
self._setCurrentPage(origpage) |
self._setCurrentPage(origpage) |
273 |
|
if object._type == 'GFBlock': |
274 |
|
self.blockMap[object.name.lower()] = object |
275 |
|
self._rebuildBlockCombo() |
276 |
|
|
277 |
|
|
278 |
def onModifyObject (self, object, handler, modifications): |
def onModifyObject (self, event): |
279 |
|
object = event.object |
280 |
|
handler = event.originator |
281 |
if object == None: |
if object == None: |
282 |
return |
return |
283 |
|
|
284 |
# TODO: adjust label width to match new length...this shouldn't be here |
# TODO: adjust label width to match new length...this shouldn't be here |
285 |
if object._type == 'GFLabel': |
if object._type == 'GFLabel': |
286 |
mods = [] |
mods = [] |
287 |
for field, value in modifications: |
for field in event.new.keys(): |
288 |
|
value = event.new[field] |
289 |
if field=='text': |
if field=='text': |
|
#TODO: this will butcher align=center setups |
|
290 |
if (not hasattr(object,'alignment')) or ( object.alignment == 'left'): |
if (not hasattr(object,'alignment')) or ( object.alignment == 'left'): |
291 |
object.width=len(value) |
if not hasattr(object,'Char__width') or object.Char__width != len(value): |
292 |
mods.append( ('width',len(value)) ) |
object.Char__width=len(value) |
293 |
else: |
# TODO: This should probably trigger a new ObjectModified event |
294 |
mods = modifications |
event.new['Char:width'] = object.Char__width |
|
|
|
|
self.propBar.onModifyObject(object, handler, mods) |
|
295 |
|
|
296 |
|
## self.propBar.onModifyObject(object, event) |
297 |
|
|
298 |
if handler != "Forms::LayoutEditor": |
if handler != "Forms::LayoutEditor": |
299 |
if object._type == 'GFPage': |
if object._type == 'GFPage': |
307 |
if object in (self.rootObject, self.page) or object in self.widgetList: |
if object in (self.rootObject, self.page) or object in self.widgetList: |
308 |
self.refreshPage(self.page) |
self.refreshPage(self.page) |
309 |
|
|
310 |
|
if object._type == 'GFBlock': |
311 |
|
del self.blockMap[event.old['name'].lower()] |
312 |
|
self.blockMap[object.name.lower()] = object |
313 |
|
self._rebuildBlockCombo |
314 |
|
|
315 |
|
self._setFeedback() |
316 |
|
|
317 |
def onDeleteObject (self, object, handler): |
|
318 |
|
def onDeleteObject (self, event): |
319 |
|
object = event.object |
320 |
|
handler = event.originator |
321 |
|
|
322 |
self._currentObject = None |
self._currentObject = None |
323 |
|
|
397 |
self.borderPercentage = (float(gConfig('borderPercentage')) / 100) |
self.borderPercentage = (float(gConfig('borderPercentage')) / 100) |
398 |
self.textPercentage = (float(gConfig('textPercentage')) / 100) |
self.textPercentage = (float(gConfig('textPercentage')) / 100) |
399 |
|
|
400 |
width = self.rootObject.width |
width = self.rootObject._layout.Char__width |
401 |
height = self.rootObject.height |
height = self.rootObject._layout.Char__height |
402 |
|
|
403 |
self.widgetWidth = (self.charWidth * self.borderPercentage) |
self.widgetWidth = (self.charWidth * self.borderPercentage) |
404 |
self.widgetHeight = (self.charHeight * self.borderPercentage) + 3 |
self.widgetHeight = (self.charHeight * self.borderPercentage) + 3 |
453 |
self.widgetList.append(object) |
self.widgetList.append(object) |
454 |
|
|
455 |
def OnSize(self, event): |
def OnSize(self, event): |
456 |
self.propBar.SetSize(wxSize(self.GetClientSize().x, self.propBar.GetSize().y)) |
## self.propBar.SetSize(wxSize(self.GetClientSize().x, self.propBar.GetSize().y)) |
457 |
self.propBar.SetPosition(wxPoint(0, self.GetClientSize().y - self.propBar.GetSize().y)) |
## self.propBar.SetPosition(wxPoint(0, self.GetClientSize().y - self.propBar.GetSize().y)) |
458 |
self.notebook.SetSize(wxSize(self.GetClientSize().x-8, self.GetClientSize().y - 8 - self.propBar.GetSize().y)) |
## self.notebook.SetSize(wxSize(self.GetClientSize().x-8, self.GetClientSize().y - 8 - self.propBar.GetSize().y)) |
459 |
|
self.notebook.SetSize(wxSize(self.GetClientSize().x-8, self.GetClientSize().y - 8))# - self.propBar.GetSize().y)) |
460 |
|
|
461 |
def OnPageSelected(self, event): |
def OnPageSelected(self, event): |
462 |
p = self._notebookMap[event.GetSelection()] |
p = self._notebookMap[event.GetSelection()] |
463 |
if p != self.page: |
if p != self.page: |
464 |
self._instance.onSetCurrentObject(p, "Forms::LayoutEditor") |
self.dispatchEvent('ObjectSelected', object=p, originator="Forms::LayoutEditor") |
465 |
self._setCurrentPage(p) |
self._setCurrentPage(p) |
466 |
|
|
467 |
|
|
|
def OnBlockSelected(self, event): |
|
|
b = self.blockList[event.GetSelection()] |
|
|
# if p != self.page: |
|
|
self._instance.onSetCurrentObject(b, None) |
|
|
|
|
|
|
|
468 |
def OnLeftDown(self, event): |
def OnLeftDown(self, event): |
469 |
# Save starting coordinates for cross-selection box |
# Save starting coordinates for cross-selection box |
470 |
x, y = event.GetPositionTuple() |
x, y = event.GetPositionTuple() |
556 |
|
|
557 |
def selectWidgetInArea(self, object, x1, y1, x2, y2): |
def selectWidgetInArea(self, object, x1, y1, x2, y2): |
558 |
try: |
try: |
559 |
if x1 <= object.x <= x2 and \ |
if x1 <= object.Char__x <= x2 and \ |
560 |
y1 <= object.y <= y2: |
y1 <= object.Char__y <= y2: |
561 |
self._currentSelection[object._widgetHandler] = 1 |
self._currentSelection[object._widgetHandler] = 1 |
562 |
object._widgetHandler.setSelected(1) |
object._widgetHandler.setSelected(1) |
563 |
except AttributeError: |
except AttributeError: |
566 |
|
|
567 |
|
|
568 |
def OnRightUp(self, event): |
def OnRightUp(self, event): |
569 |
self.toolbar.resetTool(self.mode) |
## self.toolbar.resetTool(self.mode) |
570 |
self.mode = 'move' |
self.mode = 'move' |
571 |
|
|
572 |
x, y = event.GetPositionTuple() |
x, y = event.GetPositionTuple() |
582 |
block = self._currentObject._type == 'GFBlock' and self._currentObject or \ |
block = self._currentObject._type == 'GFBlock' and self._currentObject or \ |
583 |
self._currentObject.findParentOfType('GFBlock') |
self._currentObject.findParentOfType('GFBlock') |
584 |
|
|
585 |
menu.AppendMenu(wxNewId(), 'Form', PageMenu(self._instance, form, x, y)) |
menu.AppendMenu(wxNewId(), 'Form', PageMenu(self.instance, form, x, y)) |
586 |
if page: |
if page: |
587 |
menu.AppendMenu(wxNewId(), page.name, PageMenu(self._instance, page, x, y)) |
menu.AppendMenu(wxNewId(), page.name, PageMenu(self.instance, page, x, y)) |
588 |
if block: |
if block: |
589 |
menu.AppendMenu(wxNewId(), block.name, PageMenu(self._instance, block, x, y)) |
menu.AppendMenu(wxNewId(), block.name, PageMenu(self.instance, block, x, y)) |
590 |
|
|
591 |
self.panel.PopupMenu(menu, event.GetPosition()) |
self.panel.PopupMenu(menu, event.GetPosition()) |
592 |
|
|
626 |
if event.KeyCode() == WXK_DOWN: |
if event.KeyCode() == WXK_DOWN: |
627 |
for widget in self._currentSelection.keys(): |
for widget in self._currentSelection.keys(): |
628 |
widget.relativeMove(0,1) |
widget.relativeMove(0,1) |
629 |
|
elif event.KeyCode() == WXK_DELETE and \ |
630 |
|
len(self._currentSelection.keys()): |
631 |
|
for object in self._currentSelection.keys(): |
632 |
|
self.dispatchEvent('ObjectDeleted', object=object.object, |
633 |
|
originator=self) |
634 |
|
|
635 |
def startPrePositioningTemplate(self, template): |
def startPrePositioningTemplate(self, template): |
636 |
self.mode = 'positioning' |
self.mode = 'positioning' |
640 |
|
|
641 |
|
|
642 |
def endPrePositioningTemplate(self, x, y, width=None, height=None): |
def endPrePositioningTemplate(self, x, y, width=None, height=None): |
643 |
TemplateParser(self._instance, self._instance.rootObject, |
TemplateParser(self.instance, self.instance.rootObject, |
644 |
self._instance, self.__template, currentObject=self.block or self.page).run(x=x, y=y, |
self.instance, self.__template, currentObject=self.block or self.page).run(x=x, y=y, |
645 |
width=width, |
width=width, |
646 |
height=height) |
height=height) |
647 |
self._instance.dispatchEvent(Event('EndWizard', template=self.__template)) |
self.instance.dispatchEvent(Event('EndWizard', template=self.__template)) |
648 |
self.mode = 'move' |
self.mode = 'move' |
649 |
|
|
650 |
|
|