DocView and ActiveGrid IDE updates from Morgan Hua:
New Features: In Tab-View mode, Ctrl-number will take the user to the numbered tab view. Modified files now show an '*' astrisk in the view title. Debugger framework can now support PHP debugging. Not important for python development, but at least that means the debugger framework is more generalized. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@38852 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
20
wxPython/samples/ide/activegrid/model/projectmodel.py
Normal file
20
wxPython/samples/ide/activegrid/model/projectmodel.py
Normal file
@@ -0,0 +1,20 @@
|
||||
#----------------------------------------------------------------------------
|
||||
# Name: projectmodel.py
|
||||
# Purpose: This file contains project model information
|
||||
#
|
||||
# Author: Morgan Hua
|
||||
#
|
||||
# Created: 4/18/06
|
||||
# CVS-ID: $Id$
|
||||
# Copyright: (c) 2006 ActiveGrid, Inc.
|
||||
# License: wxWindows License
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Constants
|
||||
#----------------------------------------------------------------------------
|
||||
LANGUAGE_PYTHON = "python"
|
||||
LANGUAGE_PHP = "php"
|
||||
LANGUAGE_DEFAULT = LANGUAGE_PYTHON
|
||||
LANGUAGE_LIST = [LANGUAGE_PHP, LANGUAGE_PYTHON]
|
@@ -5,7 +5,7 @@
|
||||
# Author: Morgan Hua
|
||||
#
|
||||
# Created: 3/22/05
|
||||
# Copyright: (c) 2005 ActiveGrid, Inc.
|
||||
# Copyright: (c) 2005-2006 ActiveGrid, Inc.
|
||||
# CVS-ID: $Id$
|
||||
# License: wxWindows License
|
||||
#----------------------------------------------------------------------------
|
||||
@@ -45,8 +45,10 @@ if not ACTIVEGRID_BASE_IDE: # add licenses for non-base IDE features such as
|
||||
("PyGreSQL", "BSD", "http://www.pygresql.org"),
|
||||
("pyXML", "CNRI Python License", "http://sourceforge.net/softwaremap/trove_list.php?form_cat=194"),
|
||||
("Zolera Soap Infrastructure", "Zope Public License 2.0", "http://www.zope.org/Resources/License/"),
|
||||
("python-ldap", "Python Software Foundation License", "http://python-ldap.sourceforge.net"),
|
||||
("Sarissa", "LGPL", "http://sourceforge.net/projects/sarissa/"),
|
||||
("Dynarch DHTML Calendar", "LGPL", "http://www.dynarch.com/projects/calendar/"),
|
||||
("python-dateutil", "Python Software Foundation License", "http://labix.org/python-dateutil"),
|
||||
]
|
||||
|
||||
if wx.Platform == '__WXMSW__': # add Windows only licenses
|
||||
@@ -82,7 +84,7 @@ class AboutDialog(wx.Dialog):
|
||||
|
||||
image = wx.StaticBitmap(aboutPage, -1, splash_bmp, (0,0), (splash_bmp.GetWidth(), splash_bmp.GetHeight()))
|
||||
sizer.Add(image, 0, wx.ALIGN_CENTER|wx.ALL, 0)
|
||||
sizer.Add(wx.StaticText(aboutPage, -1, wx.GetApp().GetAppName() + _("\n%s\n\nCopyright (c) 2003-2005 ActiveGrid Incorporated and Contributors. All rights reserved.") % version), 0, wx.ALIGN_LEFT|wx.ALL, 10)
|
||||
sizer.Add(wx.StaticText(aboutPage, -1, wx.GetApp().GetAppName() + _("\n%s\n\nCopyright (c) 2003-2006 ActiveGrid Incorporated and Contributors. All rights reserved.") % version), 0, wx.ALIGN_LEFT|wx.ALL, 10)
|
||||
sizer.Add(wx.StaticText(aboutPage, -1, _("http://www.activegrid.com")), 0, wx.ALIGN_LEFT|wx.LEFT|wx.BOTTOM, 10)
|
||||
aboutPage.SetSizer(sizer)
|
||||
nb.AddPage(aboutPage, _("Copyright"))
|
||||
@@ -95,10 +97,9 @@ class AboutDialog(wx.Dialog):
|
||||
dc.SetFont(grid.GetLabelFont())
|
||||
grid.SetColLabelValue(0, _("License"))
|
||||
grid.SetColLabelValue(1, _("URL"))
|
||||
w, maxHeight = dc.GetTextExtent(_("License"))
|
||||
w, h = dc.GetTextExtent(_("URL"))
|
||||
if h > maxHeight:
|
||||
maxHeight = h
|
||||
w, h1 = dc.GetTextExtent(_("License"))
|
||||
w, h2 = dc.GetTextExtent(_("URL"))
|
||||
maxHeight = max(h1, h2)
|
||||
grid.SetColLabelSize(maxHeight + 6) # add a 6 pixel margin
|
||||
|
||||
maxW = 0
|
||||
@@ -132,7 +133,7 @@ class AboutDialog(wx.Dialog):
|
||||
|
||||
creditsPage = wx.Panel(nb, -1)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
sizer.Add(wx.StaticText(creditsPage, -1, _("ActiveGrid Development Team:\n\nLarry Abrahams\nLawrence Bruhmuller\nEric Chu\nBeth Fryer\nMatt Fryer\nJoel Hare\nMorgan Hua\nMatt McNulty\nPratik Mehta\nAlan Mullendore\nJeff Norton\nSimon Toens\nKevin Wang\nPeter Yared")), 0, wx.ALIGN_LEFT|wx.ALL, 10)
|
||||
sizer.Add(wx.StaticText(creditsPage, -1, _("ActiveGrid Development Team:\n\nLarry Abrahams\nLawrence Bruhmuller\nEric Chu\nBeth Fryer\nMatt Fryer\nFrankie Fu\nJoel Hare\nMorgan Hua\nMatt McNulty\nPratik Mehta\nAlan Mullendore\nJeff Norton\nKevin Ollivier\nMatt Small\nSimon Toens\nKevin Wang\nPeter Yared\nJeremy Yun")), 0, wx.ALIGN_LEFT|wx.ALL, 10)
|
||||
creditsPage.SetSizer(sizer)
|
||||
nb.AddPage(creditsPage, _("Credits"))
|
||||
|
||||
|
@@ -36,6 +36,7 @@ PARKING_VERTICAL = 1
|
||||
PARKING_HORIZONTAL = 2
|
||||
PARKING_OFFSET = 30 # space between shapes
|
||||
|
||||
FORCE_REDRAW_METHOD = "ForceRedraw"
|
||||
|
||||
def GetRawModel(model):
|
||||
if hasattr(model, "GetRawModel"):
|
||||
@@ -85,6 +86,7 @@ class CanvasView(wx.lib.docview.View):
|
||||
self._propShape = None
|
||||
self._maxWidth = 2000
|
||||
self._maxHeight = 16000
|
||||
self._valetParking = False
|
||||
|
||||
|
||||
def OnDraw(self, dc):
|
||||
@@ -195,6 +197,16 @@ class CanvasView(wx.lib.docview.View):
|
||||
self.SetPropertyModel(None)
|
||||
|
||||
|
||||
def SetLastRightClick(self, x, y):
|
||||
self._lastRightClick = (x,y)
|
||||
|
||||
|
||||
def GetLastRightClick(self):
|
||||
if hasattr(self, "_lastRightClick"):
|
||||
return self._lastRightClick
|
||||
return (-1,-1)
|
||||
|
||||
|
||||
def OnKeyPressed(self, event):
|
||||
key = event.KeyCode()
|
||||
if key == wx.WXK_DELETE:
|
||||
@@ -211,6 +223,7 @@ class CanvasView(wx.lib.docview.View):
|
||||
dc = wx.ClientDC(self._canvas)
|
||||
self._canvas.PrepareDC(dc)
|
||||
x, y = event.GetLogicalPosition(dc) # this takes into account scrollbar offset
|
||||
self.SetLastRightClick(x, y)
|
||||
shape = self._canvas.FindShape(x, y)[0]
|
||||
|
||||
model = None
|
||||
@@ -260,12 +273,15 @@ class CanvasView(wx.lib.docview.View):
|
||||
pass
|
||||
else:
|
||||
# click on empty part of canvas, deselect everything
|
||||
forceRedrawShapes = []
|
||||
needRefresh = False
|
||||
for shape in self._diagram.GetShapeList():
|
||||
if hasattr(shape, "GetModel"):
|
||||
if shape.Selected():
|
||||
needRefresh = True
|
||||
shape.Select(False, dc)
|
||||
if hasattr(shape, FORCE_REDRAW_METHOD):
|
||||
forceRedrawShapes.append(shape)
|
||||
if needRefresh:
|
||||
self._canvas.Redraw(dc)
|
||||
|
||||
@@ -274,7 +290,8 @@ class CanvasView(wx.lib.docview.View):
|
||||
if len(self.GetSelection()) == 0:
|
||||
self.SetPropertyShape(None)
|
||||
|
||||
|
||||
for shape in forceRedrawShapes:
|
||||
shape.ForceRedraw()
|
||||
|
||||
def OnLeftDoubleClick(self, event):
|
||||
propertyService = wx.GetApp().GetService(PropertyService.PropertyService)
|
||||
@@ -401,8 +418,20 @@ class CanvasView(wx.lib.docview.View):
|
||||
dc.EndDrawing()
|
||||
|
||||
|
||||
def SetValetParking(self, enable=True):
|
||||
""" If valet parking is enabled, remember last parking spot and try for a spot near it """
|
||||
self._valetParking = enable
|
||||
if enable:
|
||||
self._valetPosition = None
|
||||
|
||||
|
||||
def FindParkingSpot(self, width, height, parking=PARKING_HORIZONTAL, x=PARKING_OFFSET, y=PARKING_OFFSET):
|
||||
""" given a width and height, find a upper left corner where shape can be parked without overlapping other shape """
|
||||
"""
|
||||
Given a width and height, find a upper left corner where shape can be parked without overlapping other shape
|
||||
"""
|
||||
if self._valetParking and self._valetPosition:
|
||||
x, y = self._valetPosition
|
||||
|
||||
max = 700 # max distance to the right where we'll place tables
|
||||
noParkingSpot = True
|
||||
|
||||
@@ -422,6 +451,9 @@ class CanvasView(wx.lib.docview.View):
|
||||
else:
|
||||
noParkingSpot = False
|
||||
|
||||
if self._valetParking:
|
||||
self._valetPosition = (x, y)
|
||||
|
||||
return x, y
|
||||
|
||||
|
||||
@@ -518,6 +550,7 @@ class CanvasView(wx.lib.docview.View):
|
||||
self._diagram.RemoveShape(line)
|
||||
line.Delete()
|
||||
|
||||
if self._canvas:
|
||||
shape.RemoveFromCanvas(self._canvas)
|
||||
self._diagram.RemoveShape(shape)
|
||||
shape.Delete()
|
||||
@@ -698,6 +731,9 @@ class CanvasView(wx.lib.docview.View):
|
||||
self._propShape.SetTextColour("WHITE", 0)
|
||||
self._propShape.Draw(dc)
|
||||
|
||||
if hasattr(self._propShape, FORCE_REDRAW_METHOD):
|
||||
self._propShape.ForceRedraw()
|
||||
|
||||
dc.EndDrawing()
|
||||
|
||||
|
||||
|
@@ -19,7 +19,6 @@ import os
|
||||
import re
|
||||
import string
|
||||
import sys
|
||||
import DebuggerService
|
||||
import MarkerService
|
||||
from UICommon import CaseInsensitiveCompare
|
||||
_ = wx.GetTranslation
|
||||
@@ -120,16 +119,27 @@ class CodeView(STCTextEditor.TextView):
|
||||
return False
|
||||
id = event.GetId()
|
||||
if id == EXPAND_TEXT_ID:
|
||||
if self.GetCtrl().GetViewFolding():
|
||||
event.Enable(self.GetCtrl().CanLineExpand(self.GetCtrl().GetCurrentLine()))
|
||||
else:
|
||||
event.Enable(False)
|
||||
return True
|
||||
elif id == COLLAPSE_TEXT_ID:
|
||||
if self.GetCtrl().GetViewFolding():
|
||||
event.Enable(self.GetCtrl().CanLineCollapse(self.GetCtrl().GetCurrentLine()))
|
||||
else:
|
||||
event.Enable(False)
|
||||
return True
|
||||
elif (id == EXPAND_TOP_ID
|
||||
or id == COLLAPSE_TOP_ID
|
||||
or id == EXPAND_ALL_ID
|
||||
or id == COLLAPSE_ALL_ID
|
||||
or id == AUTO_COMPLETE_ID
|
||||
or id == COLLAPSE_ALL_ID):
|
||||
if self.GetCtrl().GetViewFolding():
|
||||
event.Enable(self.GetCtrl().GetTextLength() > 0)
|
||||
else:
|
||||
event.Enable(False)
|
||||
return True
|
||||
elif (id == AUTO_COMPLETE_ID
|
||||
or id == CLEAN_WHITESPACE
|
||||
or id == INDENT_LINES_ID
|
||||
or id == DEDENT_LINES_ID
|
||||
@@ -140,10 +150,12 @@ class CodeView(STCTextEditor.TextView):
|
||||
elif id == CHECK_CODE_ID:
|
||||
event.Enable(False)
|
||||
return True
|
||||
elif (id == SET_INDENT_WIDTH_ID
|
||||
or id == FOLDING_ID):
|
||||
elif id == SET_INDENT_WIDTH_ID:
|
||||
event.Enable(True)
|
||||
return True
|
||||
elif id == FOLDING_ID:
|
||||
event.Enable(self.GetCtrl().GetViewFolding())
|
||||
return True
|
||||
elif id == USE_TABS_ID:
|
||||
event.Enable(True)
|
||||
event.Check(self.GetCtrl().GetUseTabs())
|
||||
@@ -210,7 +222,7 @@ class CodeView(STCTextEditor.TextView):
|
||||
filename = document.GetFilename()
|
||||
if filename:
|
||||
rootItem = treeCtrl.AddRoot(os.path.basename(filename))
|
||||
treeCtrl.SetDoSelectCallback(rootItem, self, None)
|
||||
treeCtrl.SetDoSelectCallback(rootItem, self, (0,0))
|
||||
else:
|
||||
return True
|
||||
|
||||
@@ -232,11 +244,13 @@ class CodeView(STCTextEditor.TextView):
|
||||
if classLine:
|
||||
indent = classLine.start(0)
|
||||
itemStr = classLine.string[classLine.start(0):classLine.end(0)-1] # don't take the closing ':'
|
||||
itemStr = itemStr.replace("\n", "").replace("\r", "").replace(",\\", ",").replace(" ", "") # remove line continuations and spaces from outline view
|
||||
else:
|
||||
defLine = defPat.search(line)
|
||||
if defLine:
|
||||
indent = defLine.start(0)
|
||||
itemStr = defLine.string[defLine.start(0):defLine.end(0)]
|
||||
itemStr = itemStr.replace("\n", "").replace("\r", "").replace(",\\", ",").replace(" ", "") # remove line continuations and spaces from outline view
|
||||
|
||||
if indent == 0:
|
||||
parentItem = rootItem
|
||||
@@ -467,6 +481,9 @@ class CodeView(STCTextEditor.TextView):
|
||||
|
||||
|
||||
def OnUpdate(self, sender = None, hint = None):
|
||||
if wx.lib.docview.View.OnUpdate(self, sender, hint):
|
||||
return
|
||||
|
||||
if hint == "ViewStuff":
|
||||
self.GetCtrl().SetViewDefaults()
|
||||
elif hint == "Font":
|
||||
@@ -474,6 +491,7 @@ class CodeView(STCTextEditor.TextView):
|
||||
self.GetCtrl().SetFont(font)
|
||||
self.GetCtrl().SetFontColor(color)
|
||||
else:
|
||||
import DebuggerService
|
||||
dbg_service = wx.GetApp().GetService(DebuggerService.DebuggerService)
|
||||
if dbg_service:
|
||||
dbg_service.SetCurrentBreakpointMarkers(self)
|
||||
@@ -623,7 +641,7 @@ class CodeCtrl(STCTextEditor.TextCtrl):
|
||||
BREAKPOINT_MARKER_MASK = 0x2
|
||||
|
||||
|
||||
def __init__(self, parent, id=-1, style = wx.NO_FULL_REPAINT_ON_RESIZE):
|
||||
def __init__(self, parent, id=-1, style = wx.NO_FULL_REPAINT_ON_RESIZE, clearTab=True):
|
||||
STCTextEditor.TextCtrl.__init__(self, parent, id, style)
|
||||
|
||||
self.UsePopUp(False)
|
||||
@@ -635,7 +653,6 @@ class CodeCtrl(STCTextEditor.TextCtrl):
|
||||
self.SetMarginType(2, wx.stc.STC_MARGIN_SYMBOL)
|
||||
self.SetMarginMask(2, wx.stc.STC_MASK_FOLDERS)
|
||||
self.SetMarginSensitive(2, True)
|
||||
self.SetMarginWidth(2, 12)
|
||||
|
||||
self.SetMarginSensitive(1, False)
|
||||
self.SetMarginMask(1, 0x4)
|
||||
@@ -657,7 +674,7 @@ class CodeCtrl(STCTextEditor.TextCtrl):
|
||||
# Define the breakpoint marker
|
||||
self.MarkerDefine(CodeCtrl.BREAKPOINT_MARKER_NUM, wx.stc.STC_MARK_CIRCLE, wx.BLACK, (255,0,0))
|
||||
|
||||
if _WINDOWS: # should test to see if menu item exists, if it does, add this workaround
|
||||
if _WINDOWS and clearTab: # should test to see if menu item exists, if it does, add this workaround
|
||||
self.CmdKeyClear(wx.stc.STC_KEY_TAB, 0) # menu item "Indent Lines" from CodeService.InstallControls() generates another INDENT_LINES_ID event, so we'll explicitly disable the tab processing in the editor
|
||||
|
||||
wx.stc.EVT_STC_MARGINCLICK(self, self.GetId(), self.OnMarginClick)
|
||||
@@ -693,7 +710,7 @@ class CodeCtrl(STCTextEditor.TextCtrl):
|
||||
item = wx.MenuItem(menu, TOGGLEBREAKPOINT_ID, _("Toggle Breakpoint"))
|
||||
menu.AppendItem(item)
|
||||
self.Bind(wx.EVT_MENU, self.OnPopToggleMarker, id=TOGGLEMARKER_ID)
|
||||
item = wx.MenuItem(menu, TOGGLEMARKER_ID, _("Toggle Marker"))
|
||||
item = wx.MenuItem(menu, TOGGLEMARKER_ID, _("Toggle Bookmark"))
|
||||
menu.AppendItem(item)
|
||||
menu.AppendSeparator()
|
||||
|
||||
@@ -715,6 +732,7 @@ class CodeCtrl(STCTextEditor.TextCtrl):
|
||||
|
||||
def OnPopToggleBP(self, event):
|
||||
""" Toggle break point on right click line, not current line """
|
||||
import DebuggerService
|
||||
wx.GetApp().GetService(DebuggerService.DebuggerService).OnToggleBreakpoint(event, line=self._rightClickLine)
|
||||
|
||||
|
||||
@@ -859,6 +877,7 @@ class CodeCtrl(STCTextEditor.TextCtrl):
|
||||
|
||||
elif evt.GetMargin() == 0:
|
||||
#This is used to toggle breakpoints via the debugger service.
|
||||
import DebuggerService
|
||||
db_service = wx.GetApp().GetService(DebuggerService.DebuggerService)
|
||||
if db_service:
|
||||
db_service.OnToggleBreakpoint(evt, line=self.LineFromPosition(evt.GetPosition()))
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@
|
||||
#
|
||||
# Created: 5/23/05
|
||||
# CVS-ID: $ID:$
|
||||
# Copyright: (c) 2005 ActiveGrid, Inc.
|
||||
# Copyright: (c) 2005-2006 ActiveGrid, Inc.
|
||||
# License: wxWindows License
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
@@ -17,21 +17,16 @@ import ProjectEditor
|
||||
import os
|
||||
import os.path
|
||||
import activegrid.util.xmlutils as xmlutils
|
||||
|
||||
_ = wx.GetTranslation
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Constants
|
||||
#----------------------------------------------------------------------------
|
||||
SPACE = 10
|
||||
HALF_SPACE = 5
|
||||
|
||||
|
||||
EXTENSIONS_CONFIG_STRING = "Extensions"
|
||||
|
||||
|
||||
|
||||
# TODO: Redo extensions menu on OK, or provide alert that it won't happen until restart
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Classes
|
||||
#----------------------------------------------------------------------------
|
||||
@@ -221,10 +216,10 @@ class ExtensionOptionsPanel(wx.Panel):
|
||||
|
||||
extCtrlSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
extCtrlSizer.Add(wx.StaticText(self, -1, _("External Tools:")), 0, wx.BOTTOM, HALF_SPACE)
|
||||
self._extListBox = wx.ListBox(self, -1, size=(-1,160), style=wx.LB_SINGLE)
|
||||
self._extListBox = wx.ListBox(self, -1, style=wx.LB_SINGLE)
|
||||
self.Bind(wx.EVT_LISTBOX, self.OnListBoxSelect, self._extListBox)
|
||||
extCtrlSizer.Add(self._extListBox, 1, wx.BOTTOM | wx.EXPAND, SPACE)
|
||||
buttonSizer = wx.GridSizer(cols=2, vgap=5, hgap=10)
|
||||
buttonSizer = wx.GridSizer(cols=2, vgap=HALF_SPACE, hgap=HALF_SPACE)
|
||||
self._moveUpButton = wx.Button(self, -1, _("Move Up"))
|
||||
self.Bind(wx.EVT_BUTTON, self.OnMoveUp, self._moveUpButton)
|
||||
buttonSizer.Add(self._moveUpButton, 1, wx.EXPAND)
|
||||
@@ -244,19 +239,19 @@ class ExtensionOptionsPanel(wx.Panel):
|
||||
staticBox = wx.StaticBox(self, label=_("Selected External Tool"))
|
||||
staticBoxSizer = wx.StaticBoxSizer(staticBox, wx.VERTICAL)
|
||||
|
||||
extDetailSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=3)
|
||||
extDetailSizer = wx.FlexGridSizer(cols=2, vgap=5, hgap=5)
|
||||
extDetailSizer.AddGrowableCol(1,1)
|
||||
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Menu Item Name:")))
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Menu Item Name:")), flag=wx.ALIGN_CENTER_VERTICAL)
|
||||
self._menuItemNameTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1))
|
||||
extDetailSizer.Add(self._menuItemNameTextCtrl, 0, wx.EXPAND)
|
||||
self.Bind(wx.EVT_TEXT, self.SaveCurrentItem, self._menuItemNameTextCtrl)
|
||||
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Menu Item Description:")))
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Menu Item Description:")), flag=wx.ALIGN_CENTER_VERTICAL)
|
||||
self._menuItemDescTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1))
|
||||
extDetailSizer.Add(self._menuItemDescTextCtrl, 0, wx.EXPAND)
|
||||
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Command Path:")))
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Command Path:")), flag=wx.ALIGN_CENTER_VERTICAL)
|
||||
self._commandTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1))
|
||||
findFileButton = wx.Button(self._extDetailPanel, -1, _("Browse..."))
|
||||
def OnBrowseButton(event):
|
||||
@@ -276,21 +271,21 @@ class ExtensionOptionsPanel(wx.Panel):
|
||||
hsizer.Add(findFileButton, 0, wx.LEFT, HALF_SPACE)
|
||||
extDetailSizer.Add(hsizer, 0, wx.EXPAND)
|
||||
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Command Pre Args:")))
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Command Pre Args:")), flag=wx.ALIGN_CENTER_VERTICAL)
|
||||
self._commandPreArgsTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1))
|
||||
extDetailSizer.Add(self._commandPreArgsTextCtrl, 0, wx.EXPAND)
|
||||
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Command Post Args:")))
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Command Post Args:")), flag=wx.ALIGN_CENTER_VERTICAL)
|
||||
self._commandPostArgsTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1))
|
||||
extDetailSizer.Add(self._commandPostArgsTextCtrl, 0, wx.EXPAND)
|
||||
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("File Extensions:")))
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("File Extensions:")), flag=wx.ALIGN_CENTER_VERTICAL)
|
||||
self._fileExtTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1))
|
||||
self._fileExtTextCtrl.SetToolTipString(_("""For example: "txt, text" (comma separated) or "*" for all files"""))
|
||||
extDetailSizer.Add(self._fileExtTextCtrl, 0, wx.EXPAND)
|
||||
|
||||
self._selFileCtrl = wx.CheckBox(self._extDetailPanel, -1, _("Operate on Selected File"))
|
||||
extDetailSizer.Add(self._selFileCtrl)
|
||||
extDetailSizer.Add(self._selFileCtrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.TOP, SPACE)
|
||||
self._selFileCtrl.SetToolTipString(_("If focus is in the project, instead of operating on the project file, operate on the selected file."))
|
||||
|
||||
self._extDetailPanel.SetSizer(extDetailSizer)
|
||||
|
@@ -27,6 +27,7 @@ _ = wx.GetTranslation
|
||||
#----------------------------------------------------------------------------
|
||||
FILENAME_MARKER = _("Found in file: ")
|
||||
PROJECT_MARKER = _("Searching project: ")
|
||||
FILE_MARKER = _("Searching file: ")
|
||||
FIND_MATCHDIR = "FindMatchDir"
|
||||
FIND_MATCHDIRSUBFOLDERS = "FindMatchDirSubfolders"
|
||||
|
||||
@@ -39,6 +40,7 @@ class FindInDirService(FindService.FindService):
|
||||
#----------------------------------------------------------------------------
|
||||
# Constants
|
||||
#----------------------------------------------------------------------------
|
||||
FINDFILE_ID = wx.NewId() # for bringing up Find in File dialog box
|
||||
FINDALL_ID = wx.NewId() # for bringing up Find All dialog box
|
||||
FINDDIR_ID = wx.NewId() # for bringing up Find Dir dialog box
|
||||
|
||||
@@ -47,29 +49,39 @@ class FindInDirService(FindService.FindService):
|
||||
FindService.FindService.InstallControls(self, frame, menuBar, toolBar, statusBar, document)
|
||||
|
||||
editMenu = menuBar.GetMenu(menuBar.FindMenu(_("&Edit")))
|
||||
wx.EVT_MENU(frame, FindInDirService.FINDFILE_ID, self.ProcessEvent)
|
||||
wx.EVT_UPDATE_UI(frame, FindInDirService.FINDFILE_ID, self.ProcessUpdateUIEvent)
|
||||
editMenu.Append(FindInDirService.FINDFILE_ID, _("Find in File...\tCtrl+Shift+F"), _("Searches for the specified text in the current file"))
|
||||
wx.EVT_MENU(frame, FindInDirService.FINDALL_ID, self.ProcessEvent)
|
||||
wx.EVT_UPDATE_UI(frame, FindInDirService.FINDALL_ID, self.ProcessUpdateUIEvent)
|
||||
editMenu.Append(FindInDirService.FINDALL_ID, _("Find in Project...\tCtrl+Shift+F"), _("Searches for the specified text in all the files in the project"))
|
||||
editMenu.Append(FindInDirService.FINDALL_ID, _("Find in Project...\tCtrl+Shift+P"), _("Searches for the specified text in all the files in the project"))
|
||||
wx.EVT_MENU(frame, FindInDirService.FINDDIR_ID, self.ProcessEvent)
|
||||
wx.EVT_UPDATE_UI(frame, FindInDirService.FINDDIR_ID, self.ProcessUpdateUIEvent)
|
||||
editMenu.Append(FindInDirService.FINDDIR_ID, _("Find in Directory..."), _("Searches for the specified text in all the files in the directory"))
|
||||
editMenu.Append(FindInDirService.FINDDIR_ID, _("Find in Directory...\tCtrl+Shift+D"), _("Searches for the specified text in all the files in the directory"))
|
||||
|
||||
|
||||
def ProcessEvent(self, event):
|
||||
id = event.GetId()
|
||||
if id == FindInDirService.FINDALL_ID:
|
||||
if id == FindInDirService.FINDFILE_ID:
|
||||
view = wx.GetApp().GetDocumentManager().GetCurrentView()
|
||||
if hasattr(view, "GetCtrl") and view.GetCtrl() and hasattr(view.GetCtrl(), "GetSelectedText"):
|
||||
self.ShowFindAllDialog(view.GetCtrl().GetSelectedText())
|
||||
self.ShowFindInFileDialog(view.GetCtrl().GetSelectedText())
|
||||
else:
|
||||
self.ShowFindAllDialog()
|
||||
self.ShowFindInFileDialog()
|
||||
return True
|
||||
elif id == FindInDirService.FINDALL_ID:
|
||||
view = wx.GetApp().GetDocumentManager().GetCurrentView()
|
||||
if hasattr(view, "GetCtrl") and view.GetCtrl() and hasattr(view.GetCtrl(), "GetSelectedText"):
|
||||
self.ShowFindInProjectDialog(view.GetCtrl().GetSelectedText())
|
||||
else:
|
||||
self.ShowFindInProjectDialog()
|
||||
return True
|
||||
elif id == FindInDirService.FINDDIR_ID:
|
||||
view = wx.GetApp().GetDocumentManager().GetCurrentView()
|
||||
if hasattr(view, "GetCtrl") and view.GetCtrl() and hasattr(view.GetCtrl(), "GetSelectedText"):
|
||||
self.ShowFindDirDialog(view.GetCtrl().GetSelectedText())
|
||||
self.ShowFindInDirDialog(view.GetCtrl().GetSelectedText())
|
||||
else:
|
||||
self.ShowFindDirDialog()
|
||||
self.ShowFindInDirDialog()
|
||||
return True
|
||||
else:
|
||||
return FindService.FindService.ProcessEvent(self, event)
|
||||
@@ -77,7 +89,14 @@ class FindInDirService(FindService.FindService):
|
||||
|
||||
def ProcessUpdateUIEvent(self, event):
|
||||
id = event.GetId()
|
||||
if id == FindInDirService.FINDALL_ID:
|
||||
if id == FindInDirService.FINDFILE_ID:
|
||||
view = wx.GetApp().GetDocumentManager().GetCurrentView()
|
||||
if view and view.GetDocument() and not isinstance(view.GetDocument(), ProjectEditor.ProjectDocument): # don't search project model
|
||||
event.Enable(True)
|
||||
else:
|
||||
event.Enable(False)
|
||||
return True
|
||||
elif id == FindInDirService.FINDALL_ID:
|
||||
projectService = wx.GetApp().GetService(ProjectEditor.ProjectService)
|
||||
if projectService.GetFilesFromCurrentProject():
|
||||
event.Enable(True)
|
||||
@@ -90,7 +109,7 @@ class FindInDirService(FindService.FindService):
|
||||
return FindService.FindService.ProcessUpdateUIEvent(self, event)
|
||||
|
||||
|
||||
def ShowFindDirDialog(self, findString=None):
|
||||
def ShowFindInDirDialog(self, findString=None):
|
||||
config = wx.ConfigBase_Get()
|
||||
|
||||
frame = wx.Dialog(wx.GetApp().GetTopWindow(), -1, _("Find in Directory"), size= (320,200))
|
||||
@@ -197,7 +216,7 @@ class FindInDirService(FindService.FindService):
|
||||
# save user choice state for this and other Find Dialog Boxes
|
||||
dirString = dirCtrl.GetValue()
|
||||
searchSubfolders = subfolderCtrl.IsChecked()
|
||||
self.SaveFindDirConfig(dirString, searchSubfolders)
|
||||
self.SaveFindInDirConfig(dirString, searchSubfolders)
|
||||
|
||||
findString = findCtrl.GetValue()
|
||||
matchCase = matchCaseCtrl.IsChecked()
|
||||
@@ -213,6 +232,8 @@ class FindInDirService(FindService.FindService):
|
||||
view = messageService.GetView()
|
||||
if view:
|
||||
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
|
||||
|
||||
try:
|
||||
view.ClearLines()
|
||||
view.SetCallback(self.OnJumpToFoundLine)
|
||||
|
||||
@@ -269,6 +290,8 @@ class FindInDirService(FindService.FindService):
|
||||
view.AddLines("\n")
|
||||
|
||||
view.AddLines(_("Search completed."))
|
||||
|
||||
finally:
|
||||
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
|
||||
|
||||
return True
|
||||
@@ -276,7 +299,7 @@ class FindInDirService(FindService.FindService):
|
||||
return False
|
||||
|
||||
|
||||
def SaveFindDirConfig(self, dirString, searchSubfolders):
|
||||
def SaveFindInDirConfig(self, dirString, searchSubfolders):
|
||||
""" Save search dir patterns and flags to registry.
|
||||
|
||||
dirString = search directory
|
||||
@@ -287,7 +310,133 @@ class FindInDirService(FindService.FindService):
|
||||
config.WriteInt(FIND_MATCHDIRSUBFOLDERS, searchSubfolders)
|
||||
|
||||
|
||||
def ShowFindAllDialog(self, findString=None):
|
||||
def DoFindIn(self, findString, matchCase, wholeWord, regExpr, currFileOnly=False, jumpToFound=False):
|
||||
messageService = wx.GetApp().GetService(MessageService.MessageService)
|
||||
if not messageService:
|
||||
return
|
||||
|
||||
messageService.ShowWindow()
|
||||
|
||||
view = messageService.GetView()
|
||||
if not view:
|
||||
return
|
||||
|
||||
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
|
||||
|
||||
try:
|
||||
#Switch to messages tab.
|
||||
view.GetControl().GetParent().SetSelection(0)
|
||||
view.ClearLines()
|
||||
view.SetCallback(self.OnJumpToFoundLine)
|
||||
|
||||
projectService = wx.GetApp().GetService(ProjectEditor.ProjectService)
|
||||
|
||||
if wx.GetApp().GetDocumentManager().GetCurrentView():
|
||||
currDoc = wx.GetApp().GetDocumentManager().GetCurrentView().GetDocument()
|
||||
else:
|
||||
currDoc = None
|
||||
if currFileOnly:
|
||||
if currDoc:
|
||||
projectFilenames = [currDoc.GetFilename()]
|
||||
view.AddLines(FILE_MARKER + currDoc.GetFilename() + "\n\n")
|
||||
else:
|
||||
projectFilenames = []
|
||||
else:
|
||||
projectFilenames = projectService.GetFilesFromCurrentProject()
|
||||
|
||||
projView = projectService.GetView()
|
||||
if projView:
|
||||
projName = wx.lib.docview.FileNameFromPath(projView.GetDocument().GetFilename())
|
||||
view.AddLines(PROJECT_MARKER + projName + "\n\n")
|
||||
|
||||
firstDef = -1
|
||||
|
||||
# do search in open files first, open files may have been modified and different from disk because it hasn't been saved
|
||||
openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
|
||||
openDocsInProject = filter(lambda openDoc: openDoc.GetFilename() in projectFilenames, openDocs)
|
||||
if currDoc and currDoc in openDocsInProject:
|
||||
# make sure current document is searched first.
|
||||
openDocsInProject.remove(currDoc)
|
||||
openDocsInProject.insert(0, currDoc)
|
||||
for openDoc in openDocsInProject:
|
||||
if isinstance(openDoc, ProjectEditor.ProjectDocument): # don't search project model
|
||||
continue
|
||||
|
||||
openDocView = openDoc.GetFirstView()
|
||||
# some views don't have a in memory text object to search through such as the PM and the DM
|
||||
# even if they do have a non-text searchable object, how do we display it in the message window?
|
||||
if not hasattr(openDocView, "GetValue"):
|
||||
continue
|
||||
text = openDocView.GetValue()
|
||||
|
||||
lineNum = 1
|
||||
needToDisplayFilename = True
|
||||
start = 0
|
||||
end = 0
|
||||
count = 0
|
||||
while count != -1:
|
||||
count, foundStart, foundEnd, newText = self.DoFind(findString, None, text, start, end, True, matchCase, wholeWord, regExpr)
|
||||
if count != -1:
|
||||
if needToDisplayFilename:
|
||||
view.AddLines(FILENAME_MARKER + openDoc.GetFilename() + "\n")
|
||||
needToDisplayFilename = False
|
||||
|
||||
lineNum = openDocView.LineFromPosition(foundStart)
|
||||
line = repr(lineNum).zfill(4) + ":" + openDocView.GetLine(lineNum)
|
||||
view.AddLines(line)
|
||||
if firstDef == -1:
|
||||
firstDef = view.GetControl().GetCurrentLine() - 1
|
||||
|
||||
start = text.find("\n", foundStart)
|
||||
if start == -1:
|
||||
break
|
||||
end = start
|
||||
if not needToDisplayFilename:
|
||||
view.AddLines("\n")
|
||||
wx.GetApp().Yield(True)
|
||||
openDocNames = map(lambda openDoc: openDoc.GetFilename(), openDocs)
|
||||
|
||||
# do search in closed files, skipping the open ones we already searched
|
||||
filenames = filter(lambda filename: filename not in openDocNames, projectFilenames)
|
||||
for filename in filenames:
|
||||
try:
|
||||
docFile = file(filename, 'r')
|
||||
except IOError, (code, message):
|
||||
print _("Warning, unable to read file: '%s'. %s") % (filename, message)
|
||||
continue
|
||||
|
||||
lineNum = 1
|
||||
needToDisplayFilename = True
|
||||
line = docFile.readline()
|
||||
while line:
|
||||
count, foundStart, foundEnd, newText = self.DoFind(findString, None, line, 0, 0, True, matchCase, wholeWord, regExpr)
|
||||
if count != -1:
|
||||
if needToDisplayFilename:
|
||||
view.AddLines(FILENAME_MARKER + filename + "\n")
|
||||
needToDisplayFilename = False
|
||||
line = repr(lineNum).zfill(4) + ":" + line
|
||||
view.AddLines(line)
|
||||
if firstDef == -1:
|
||||
firstDef = view.GetControl().GetCurrentLine() - 1
|
||||
line = docFile.readline()
|
||||
lineNum += 1
|
||||
if not needToDisplayFilename:
|
||||
view.AddLines("\n")
|
||||
wx.GetApp().Yield(True)
|
||||
|
||||
view.AddLines(_("Search for '%s' completed.") % findString)
|
||||
|
||||
if jumpToFound:
|
||||
self.OnJumpToFoundLine(event=None, defLineNum=firstDef)
|
||||
|
||||
finally:
|
||||
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
|
||||
|
||||
def FindInProject(self, findString):
|
||||
self.DoFindIn(findString, matchCase=True, wholeWord=True, regExpr=True, jumpToFound=True)
|
||||
|
||||
|
||||
def ShowFindInProjectDialog(self, findString=None):
|
||||
config = wx.ConfigBase_Get()
|
||||
|
||||
frame = wx.Dialog(wx.GetApp().GetTopWindow(), -1, _("Find in Project"), size= (320,200))
|
||||
@@ -336,97 +485,80 @@ class FindInDirService(FindService.FindService):
|
||||
self.SaveFindConfig(findString, wholeWord, matchCase, regExpr)
|
||||
|
||||
frame.Destroy()
|
||||
|
||||
if status == wx.ID_OK:
|
||||
messageService = wx.GetApp().GetService(MessageService.MessageService)
|
||||
messageService.ShowWindow()
|
||||
|
||||
view = messageService.GetView()
|
||||
if view:
|
||||
view.ClearLines()
|
||||
view.SetCallback(self.OnJumpToFoundLine)
|
||||
|
||||
projectService = wx.GetApp().GetService(ProjectEditor.ProjectService)
|
||||
projectFilenames = projectService.GetFilesFromCurrentProject()
|
||||
|
||||
projView = projectService.GetView()
|
||||
if projView:
|
||||
projName = wx.lib.docview.FileNameFromPath(projView.GetDocument().GetFilename())
|
||||
view.AddLines(PROJECT_MARKER + projName + "\n\n")
|
||||
|
||||
# do search in open files first, open files may have been modified and different from disk because it hasn't been saved
|
||||
openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
|
||||
openDocsInProject = filter(lambda openDoc: openDoc.GetFilename() in projectFilenames, openDocs)
|
||||
for openDoc in openDocsInProject:
|
||||
if isinstance(openDoc, ProjectEditor.ProjectDocument): # don't search project model
|
||||
continue
|
||||
|
||||
openDocView = openDoc.GetFirstView()
|
||||
# some views don't have a in memory text object to search through such as the PM and the DM
|
||||
# even if they do have a non-text searchable object, how do we display it in the message window?
|
||||
if not hasattr(openDocView, "GetValue"):
|
||||
continue
|
||||
text = openDocView.GetValue()
|
||||
|
||||
lineNum = 1
|
||||
needToDisplayFilename = True
|
||||
start = 0
|
||||
end = 0
|
||||
count = 0
|
||||
while count != -1:
|
||||
count, foundStart, foundEnd, newText = self.DoFind(findString, None, text, start, end, True, matchCase, wholeWord, regExpr)
|
||||
if count != -1:
|
||||
if needToDisplayFilename:
|
||||
view.AddLines(FILENAME_MARKER + openDoc.GetFilename() + "\n")
|
||||
needToDisplayFilename = False
|
||||
|
||||
lineNum = openDocView.LineFromPosition(foundStart)
|
||||
line = repr(lineNum).zfill(4) + ":" + openDocView.GetLine(lineNum)
|
||||
view.AddLines(line)
|
||||
|
||||
start = text.find("\n", foundStart)
|
||||
if start == -1:
|
||||
break
|
||||
end = start
|
||||
if not needToDisplayFilename:
|
||||
view.AddLines("\n")
|
||||
openDocNames = map(lambda openDoc: openDoc.GetFilename(), openDocs)
|
||||
|
||||
# do search in closed files, skipping the open ones we already searched
|
||||
filenames = filter(lambda filename: filename not in openDocNames, projectFilenames)
|
||||
for filename in filenames:
|
||||
try:
|
||||
docFile = file(filename, 'r')
|
||||
except IOError, (code, message):
|
||||
print _("Warning, unable to read file: '%s'. %s") % (filename, message)
|
||||
continue
|
||||
|
||||
lineNum = 1
|
||||
needToDisplayFilename = True
|
||||
line = docFile.readline()
|
||||
while line:
|
||||
count, foundStart, foundEnd, newText = self.DoFind(findString, None, line, 0, 0, True, matchCase, wholeWord, regExpr)
|
||||
if count != -1:
|
||||
if needToDisplayFilename:
|
||||
view.AddLines(FILENAME_MARKER + filename + "\n")
|
||||
needToDisplayFilename = False
|
||||
line = repr(lineNum).zfill(4) + ":" + line
|
||||
view.AddLines(line)
|
||||
line = docFile.readline()
|
||||
lineNum += 1
|
||||
if not needToDisplayFilename:
|
||||
view.AddLines("\n")
|
||||
|
||||
view.AddLines(_("Search for '%s' completed.") % findString)
|
||||
|
||||
self.DoFindIn(findString, matchCase, wholeWord, regExpr)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def OnJumpToFoundLine(self, event):
|
||||
def ShowFindInFileDialog(self, findString=None):
|
||||
config = wx.ConfigBase_Get()
|
||||
|
||||
frame = wx.Dialog(wx.GetApp().GetTopWindow(), -1, _("Find in File"), size= (320,200))
|
||||
borderSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
contentSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
lineSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
lineSizer.Add(wx.StaticText(frame, -1, _("Find what:")), 0, wx.ALIGN_CENTER | wx.RIGHT, HALF_SPACE)
|
||||
if not findString:
|
||||
findString = config.Read(FindService.FIND_MATCHPATTERN, "")
|
||||
findCtrl = wx.TextCtrl(frame, -1, findString, size=(200,-1))
|
||||
lineSizer.Add(findCtrl, 0, wx.LEFT, HALF_SPACE)
|
||||
contentSizer.Add(lineSizer, 0, wx.BOTTOM, SPACE)
|
||||
wholeWordCtrl = wx.CheckBox(frame, -1, _("Match whole word only"))
|
||||
wholeWordCtrl.SetValue(config.ReadInt(FindService.FIND_MATCHWHOLEWORD, False))
|
||||
matchCaseCtrl = wx.CheckBox(frame, -1, _("Match case"))
|
||||
matchCaseCtrl.SetValue(config.ReadInt(FindService.FIND_MATCHCASE, False))
|
||||
regExprCtrl = wx.CheckBox(frame, -1, _("Regular expression"))
|
||||
regExprCtrl.SetValue(config.ReadInt(FindService.FIND_MATCHREGEXPR, False))
|
||||
contentSizer.Add(wholeWordCtrl, 0, wx.BOTTOM, SPACE)
|
||||
contentSizer.Add(matchCaseCtrl, 0, wx.BOTTOM, SPACE)
|
||||
contentSizer.Add(regExprCtrl, 0, wx.BOTTOM, SPACE)
|
||||
borderSizer.Add(contentSizer, 0, wx.TOP | wx.BOTTOM | wx.LEFT, SPACE)
|
||||
|
||||
buttonSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
findBtn = wx.Button(frame, wx.ID_OK, _("Find"))
|
||||
findBtn.SetDefault()
|
||||
BTM_SPACE = HALF_SPACE
|
||||
if wx.Platform == "__WXMAC__":
|
||||
BTM_SPACE = SPACE
|
||||
buttonSizer.Add(findBtn, 0, wx.BOTTOM, BTM_SPACE)
|
||||
buttonSizer.Add(wx.Button(frame, wx.ID_CANCEL), 0)
|
||||
borderSizer.Add(buttonSizer, 0, wx.ALL, SPACE)
|
||||
|
||||
frame.SetSizer(borderSizer)
|
||||
frame.Fit()
|
||||
|
||||
frame.CenterOnParent()
|
||||
status = frame.ShowModal()
|
||||
|
||||
# save user choice state for this and other Find Dialog Boxes
|
||||
findString = findCtrl.GetValue()
|
||||
matchCase = matchCaseCtrl.IsChecked()
|
||||
wholeWord = wholeWordCtrl.IsChecked()
|
||||
regExpr = regExprCtrl.IsChecked()
|
||||
self.SaveFindConfig(findString, wholeWord, matchCase, regExpr)
|
||||
|
||||
frame.Destroy()
|
||||
|
||||
if status == wx.ID_OK:
|
||||
self.DoFindIn(findString, matchCase, wholeWord, regExpr, currFileOnly=True)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def OnJumpToFoundLine(self, event=None, defLineNum=-1):
|
||||
messageService = wx.GetApp().GetService(MessageService.MessageService)
|
||||
if defLineNum == -1:
|
||||
lineText, pos = messageService.GetView().GetCurrLine()
|
||||
if lineText == "\n" or lineText.find(FILENAME_MARKER) != -1 or lineText.find(PROJECT_MARKER) != -1:
|
||||
else:
|
||||
lineText = messageService.GetView().GetControl().GetLine(defLineNum)
|
||||
pos = 0
|
||||
|
||||
if lineText == "\n" or lineText.find(FILENAME_MARKER) != -1 or lineText.find(PROJECT_MARKER) != -1 or lineText.find(FILE_MARKER) != -1:
|
||||
return
|
||||
lineEnd = lineText.find(":")
|
||||
if lineEnd == -1:
|
||||
@@ -435,7 +567,10 @@ class FindInDirService(FindService.FindService):
|
||||
lineNum = int(lineText[0:lineEnd])
|
||||
|
||||
text = messageService.GetView().GetText()
|
||||
if defLineNum == -1:
|
||||
curPos = messageService.GetView().GetCurrentPos()
|
||||
else:
|
||||
curPos = messageService.GetView().GetControl().GetLineEndPosition(defLineNum)
|
||||
|
||||
startPos = text.rfind(FILENAME_MARKER, 0, curPos)
|
||||
endPos = text.find("\n", startPos)
|
||||
@@ -464,5 +599,3 @@ class FindInDirService(FindService.FindService):
|
||||
# time, we don't see the selection, it is scrolled off screen
|
||||
foundView.SetSelection(startPos - 1 + len(lineText[lineEnd:].rstrip("\n")), startPos)
|
||||
wx.GetApp().GetService(OutlineService.OutlineService).LoadOutline(foundView, position=startPos)
|
||||
|
||||
|
||||
|
@@ -119,7 +119,7 @@ class HtmlCtrl(CodeEditor.CodeCtrl):
|
||||
|
||||
|
||||
def SetViewDefaults(self):
|
||||
CodeEditor.CodeCtrl.SetViewDefaults(self, configPrefix = "Html", hasWordWrap = True, hasTabs = True)
|
||||
CodeEditor.CodeCtrl.SetViewDefaults(self, configPrefix = "Html", hasWordWrap = True, hasTabs = True, hasFolding=True)
|
||||
|
||||
|
||||
def GetFontAndColorFromConfig(self):
|
||||
@@ -156,7 +156,7 @@ class HtmlCtrl(CodeEditor.CodeCtrl):
|
||||
class HtmlOptionsPanel(STCTextEditor.TextOptionsPanel):
|
||||
|
||||
def __init__(self, parent, id):
|
||||
STCTextEditor.TextOptionsPanel.__init__(self, parent, id, configPrefix = "Html", label = "HTML", hasWordWrap = True, hasTabs = True)
|
||||
STCTextEditor.TextOptionsPanel.__init__(self, parent, id, configPrefix = "Html", label = "HTML", hasWordWrap = True, hasTabs = True, hasFolding=True)
|
||||
|
||||
|
||||
def GetIcon(self):
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -36,16 +36,16 @@ class MarkerService(wx.lib.pydocview.DocService):
|
||||
|
||||
editMenu = menuBar.GetMenu(menuBar.FindMenu(_("&Edit")))
|
||||
editMenu.AppendSeparator()
|
||||
editMenu.Append(MarkerService.MARKERTOGGLE_ID, _("Toggle &Marker\tCtrl+M"), _("Toggles a jump marker to text line"))
|
||||
editMenu.Append(MarkerService.MARKERTOGGLE_ID, _("Toggle &Bookmark\tCtrl+M"), _("Toggles a bookmark at text line"))
|
||||
wx.EVT_MENU(frame, MarkerService.MARKERTOGGLE_ID, frame.ProcessEvent)
|
||||
wx.EVT_UPDATE_UI(frame, MarkerService.MARKERTOGGLE_ID, frame.ProcessUpdateUIEvent)
|
||||
editMenu.Append(MarkerService.MARKERDELALL_ID, _("Clear Markers"), _("Removes all jump markers from selected file"))
|
||||
editMenu.Append(MarkerService.MARKERDELALL_ID, _("Clear Bookmarks"), _("Removes all jump bookmarks from selected file"))
|
||||
wx.EVT_MENU(frame, MarkerService.MARKERDELALL_ID, frame.ProcessEvent)
|
||||
wx.EVT_UPDATE_UI(frame, MarkerService.MARKERDELALL_ID, frame.ProcessUpdateUIEvent)
|
||||
editMenu.Append(MarkerService.MARKERNEXT_ID, _("Marker Next\tF4"), _("Moves to next marker in selected file"))
|
||||
editMenu.Append(MarkerService.MARKERNEXT_ID, _("Bookmark Next\tF4"), _("Moves to next bookmark in selected file"))
|
||||
wx.EVT_MENU(frame, MarkerService.MARKERNEXT_ID, frame.ProcessEvent)
|
||||
wx.EVT_UPDATE_UI(frame, MarkerService.MARKERNEXT_ID, frame.ProcessUpdateUIEvent)
|
||||
editMenu.Append(MarkerService.MARKERPREV_ID, _("Marker Previous\tShift+F4"), _("Moves to previous marker in selected file"))
|
||||
editMenu.Append(MarkerService.MARKERPREV_ID, _("Bookmark Previous\tShift+F4"), _("Moves to previous bookmark in selected file"))
|
||||
wx.EVT_MENU(frame, MarkerService.MARKERPREV_ID, frame.ProcessEvent)
|
||||
wx.EVT_UPDATE_UI(frame, MarkerService.MARKERPREV_ID, frame.ProcessUpdateUIEvent)
|
||||
|
||||
|
@@ -124,6 +124,7 @@ class MessageView(Service.ServiceView):
|
||||
|
||||
|
||||
def AddLines(self, text):
|
||||
self.GetControl().SetCurrentPos(self.GetControl().GetTextLength())
|
||||
self.GetControl().SetReadOnly(False)
|
||||
self.GetControl().AddText(text)
|
||||
self.GetControl().SetReadOnly(True)
|
||||
|
@@ -147,7 +147,11 @@ class OutlineView(Service.ServiceView):
|
||||
return
|
||||
|
||||
treeCtrl = self.GetControl()
|
||||
|
||||
parentItem = treeCtrl.GetRootItem()
|
||||
if not parentItem:
|
||||
return
|
||||
|
||||
if expanded[0] != treeCtrl.GetItemText(parentItem):
|
||||
return
|
||||
|
||||
@@ -157,7 +161,6 @@ class OutlineView(Service.ServiceView):
|
||||
treeCtrl.Expand(child)
|
||||
(child, cookie) = treeCtrl.GetNextChild(parentItem, cookie)
|
||||
|
||||
if parentItem:
|
||||
treeCtrl.EnsureVisible(parentItem)
|
||||
|
||||
|
||||
@@ -267,7 +270,7 @@ class OutlineTreeCtrl(wx.TreeCtrl):
|
||||
|
||||
if self.ItemHasChildren(item):
|
||||
child, cookie = self.GetFirstChild(item)
|
||||
while child and child.IsOk():
|
||||
while child.IsOk():
|
||||
self.FindDistanceToTreeItems(child, position, distances, items)
|
||||
child, cookie = self.GetNextChild(item, cookie)
|
||||
return False
|
||||
|
2105
wxPython/samples/ide/activegrid/tool/PHPDebugger.py
Normal file
2105
wxPython/samples/ide/activegrid/tool/PHPDebugger.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,10 @@ import CodeEditor
|
||||
import OutlineService
|
||||
import os
|
||||
import re
|
||||
import FindInDirService
|
||||
import activegrid.util.appdirs as appdirs
|
||||
import activegrid.util.sysutils as sysutils
|
||||
_ = wx.GetTranslation
|
||||
|
||||
|
||||
class PHPDocument(CodeEditor.CodeDocument):
|
||||
@@ -153,18 +157,52 @@ class PHPCtrl(CodeEditor.CodeCtrl):
|
||||
|
||||
def __init__(self, parent, id=-1, style=wx.NO_FULL_REPAINT_ON_RESIZE):
|
||||
CodeEditor.CodeCtrl.__init__(self, parent, id, style)
|
||||
self.SetLexer(wx.stc.STC_LEX_PHP)
|
||||
self.SetLexer(wx.stc.STC_LEX_HTML)
|
||||
self.SetStyleBits(7)
|
||||
self.SetKeyWords(4, string.join(PHPKEYWORDS))
|
||||
self.SetProperty("fold.html", "1")
|
||||
|
||||
|
||||
def CreatePopupMenu(self):
|
||||
FINDCLASS_ID = wx.NewId()
|
||||
FINDDEF_ID = wx.NewId()
|
||||
|
||||
menu = CodeEditor.CodeCtrl.CreatePopupMenu(self)
|
||||
|
||||
self.Bind(wx.EVT_MENU, self.OnPopFindDefinition, id=FINDDEF_ID)
|
||||
menu.Insert(1, FINDDEF_ID, _("Find 'function'"))
|
||||
|
||||
self.Bind(wx.EVT_MENU, self.OnPopFindClass, id=FINDCLASS_ID)
|
||||
menu.Insert(2, FINDCLASS_ID, _("Find 'class'"))
|
||||
|
||||
return menu
|
||||
|
||||
|
||||
def OnPopFindDefinition(self, event):
|
||||
view = wx.GetApp().GetDocumentManager().GetCurrentView()
|
||||
if hasattr(view, "GetCtrl") and view.GetCtrl() and hasattr(view.GetCtrl(), "GetSelectedText"):
|
||||
pattern = view.GetCtrl().GetSelectedText().strip()
|
||||
if pattern:
|
||||
searchPattern = "function\s+%s" % pattern
|
||||
wx.GetApp().GetService(FindInDirService.FindInDirService).FindInProject(searchPattern)
|
||||
|
||||
|
||||
def OnPopFindClass(self, event):
|
||||
view = wx.GetApp().GetDocumentManager().GetCurrentView()
|
||||
if hasattr(view, "GetCtrl") and view.GetCtrl() and hasattr(view.GetCtrl(), "GetSelectedText"):
|
||||
definition = "class\s+%s"
|
||||
pattern = view.GetCtrl().GetSelectedText().strip()
|
||||
if pattern:
|
||||
searchPattern = definition % pattern
|
||||
wx.GetApp().GetService(FindInDirService.FindInDirService).FindInProject(searchPattern)
|
||||
|
||||
|
||||
def CanWordWrap(self):
|
||||
return True
|
||||
|
||||
|
||||
def SetViewDefaults(self):
|
||||
CodeEditor.CodeCtrl.SetViewDefaults(self, configPrefix = "PHP", hasWordWrap = True, hasTabs = True)
|
||||
CodeEditor.CodeCtrl.SetViewDefaults(self, configPrefix = "PHP", hasWordWrap = True, hasTabs = True, hasFolding=True)
|
||||
|
||||
|
||||
def GetFontAndColorFromConfig(self):
|
||||
@@ -216,8 +254,110 @@ class PHPCtrl(CodeEditor.CodeCtrl):
|
||||
class PHPOptionsPanel(STCTextEditor.TextOptionsPanel):
|
||||
|
||||
def __init__(self, parent, id):
|
||||
STCTextEditor.TextOptionsPanel.__init__(self, parent, id, configPrefix = "PHP", label = "PHP", hasWordWrap = True, hasTabs = True)
|
||||
wx.Panel.__init__(self, parent, id)
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
config = wx.ConfigBase_Get()
|
||||
|
||||
pathLabel = wx.StaticText(self, -1, _("PHP Executable Path:"))
|
||||
path = config.Read("ActiveGridPHPLocation")
|
||||
self._pathTextCtrl = wx.TextCtrl(self, -1, path, size = (150, -1))
|
||||
self._pathTextCtrl.SetToolTipString(self._pathTextCtrl.GetValue())
|
||||
self._pathTextCtrl.SetInsertionPointEnd()
|
||||
choosePathButton = wx.Button(self, -1, _("Browse..."))
|
||||
pathSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
HALF_SPACE = 5
|
||||
SPACE = 10
|
||||
pathSizer.Add(pathLabel, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.TOP, HALF_SPACE)
|
||||
pathSizer.Add(self._pathTextCtrl, 1, wx.EXPAND|wx.LEFT|wx.TOP, HALF_SPACE)
|
||||
pathSizer.Add(choosePathButton, 0, wx.ALIGN_RIGHT|wx.LEFT|wx.RIGHT|wx.TOP, HALF_SPACE)
|
||||
wx.EVT_BUTTON(self, choosePathButton.GetId(), self.OnChoosePath)
|
||||
mainSizer.Add(pathSizer, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, SPACE)
|
||||
|
||||
iniLabel = wx.StaticText(self, -1, _("php.ini Path:"))
|
||||
ini = config.Read("ActiveGridPHPINILocation")
|
||||
if not ini:
|
||||
if sysutils.isRelease():
|
||||
ini = os.path.normpath(os.path.join(appdirs.getSystemDir(), "php.ini"))
|
||||
else:
|
||||
tmp = self._pathTextCtrl.GetValue().strip()
|
||||
if tmp and len(tmp) > 0:
|
||||
ini = os.path.normpath(os.path.join(os.path.dirname(tmp), "php.ini"))
|
||||
|
||||
self._iniTextCtrl = wx.TextCtrl(self, -1, ini, size = (150, -1))
|
||||
self._iniTextCtrl.SetToolTipString(self._iniTextCtrl.GetValue())
|
||||
self._iniTextCtrl.SetInsertionPointEnd()
|
||||
chooseIniButton = wx.Button(self, -1, _("Browse..."))
|
||||
iniSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
HALF_SPACE = 5
|
||||
SPACE = 10
|
||||
iniSizer.Add(iniLabel, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.TOP, HALF_SPACE)
|
||||
iniSizer.Add(self._iniTextCtrl, 1, wx.EXPAND|wx.LEFT|wx.TOP, HALF_SPACE)
|
||||
iniSizer.Add(chooseIniButton, 0, wx.ALIGN_RIGHT|wx.LEFT|wx.RIGHT|wx.TOP, HALF_SPACE)
|
||||
wx.EVT_BUTTON(self, chooseIniButton.GetId(), self.OnChooseIni)
|
||||
mainSizer.Add(iniSizer, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, SPACE)
|
||||
|
||||
self._otherOptions = STCTextEditor.TextOptionsPanel(self, -1, configPrefix = "PHP", label = "PHP", hasWordWrap = True, hasTabs = True, addPage=False, hasFolding=False)
|
||||
#STCTextEditor.TextOptionsPanel.__init__(self, parent, id, configPrefix = "PHP", label = "PHP", hasWordWrap = True, hasTabs = True)
|
||||
mainSizer.Add(self._otherOptions, 0, wx.EXPAND|wx.BOTTOM, SPACE)
|
||||
|
||||
self.SetSizer(mainSizer)
|
||||
parent.AddPage(self, _("PHP"))
|
||||
|
||||
def OnChoosePath(self, event):
|
||||
defaultDir = os.path.dirname(self._pathTextCtrl.GetValue().strip())
|
||||
defaultFile = os.path.basename(self._pathTextCtrl.GetValue().strip())
|
||||
if wx.Platform == '__WXMSW__':
|
||||
wildcard = _("Executable (*.exe)|*.exe|All|*.*")
|
||||
if not defaultFile:
|
||||
defaultFile = "php-cgi.exe"
|
||||
else:
|
||||
wildcard = _("*")
|
||||
dlg = wx.FileDialog(wx.GetApp().GetTopWindow(),
|
||||
_("Select a File"),
|
||||
defaultDir=defaultDir,
|
||||
defaultFile=defaultFile,
|
||||
wildcard=wildcard,
|
||||
style=wx.OPEN|wx.FILE_MUST_EXIST|wx.HIDE_READONLY)
|
||||
# dlg.CenterOnParent() # wxBug: caused crash with wx.FileDialog
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
path = dlg.GetPath()
|
||||
if path:
|
||||
self._pathTextCtrl.SetValue(path)
|
||||
self._pathTextCtrl.SetToolTipString(self._pathTextCtrl.GetValue())
|
||||
self._pathTextCtrl.SetInsertionPointEnd()
|
||||
dlg.Destroy()
|
||||
|
||||
def OnChooseIni(self, event):
|
||||
defaultDir = os.path.dirname(self._iniTextCtrl.GetValue().strip())
|
||||
defaultFile = os.path.basename(self._iniTextCtrl.GetValue().strip())
|
||||
if wx.Platform == '__WXMSW__':
|
||||
wildcard = _("Ini (*.ini)|*.ini|All|*.*")
|
||||
if not defaultFile:
|
||||
defaultFile = "php.ini"
|
||||
else:
|
||||
wildcard = _("*")
|
||||
dlg = wx.FileDialog(wx.GetApp().GetTopWindow(),
|
||||
_("Select a File"),
|
||||
defaultDir=defaultDir,
|
||||
defaultFile=defaultFile,
|
||||
wildcard=wildcard,
|
||||
style=wx.OPEN|wx.FILE_MUST_EXIST|wx.HIDE_READONLY)
|
||||
# dlg.CenterOnParent() # wxBug: caused crash with wx.FileDialog
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
ini = dlg.GetPath()
|
||||
if ini:
|
||||
self._iniTextCtrl.SetValue(ini)
|
||||
self._iniTextCtrl.SetToolTipString(self._iniTextCtrl.GetValue())
|
||||
self._iniTextCtrl.SetInsertionPointEnd()
|
||||
dlg.Destroy()
|
||||
|
||||
def OnOK(self, optionsDialog):
|
||||
config = wx.ConfigBase_Get()
|
||||
config.Write("ActiveGridPHPLocation", self._pathTextCtrl.GetValue().strip())
|
||||
config.Write("ActiveGridPHPINILocation", self._iniTextCtrl.GetValue().strip())
|
||||
|
||||
self._otherOptions.OnOK(optionsDialog)
|
||||
|
||||
def GetIcon(self):
|
||||
return getPHPIcon()
|
||||
|
@@ -73,7 +73,7 @@ class PerlCtrl(CodeEditor.CodeCtrl):
|
||||
|
||||
|
||||
def SetViewDefaults(self):
|
||||
CodeEditor.CodeCtrl.SetViewDefaults(self, configPrefix = "Perl", hasWordWrap = True, hasTabs = True)
|
||||
CodeEditor.CodeCtrl.SetViewDefaults(self, configPrefix = "Perl", hasWordWrap = True, hasTabs = True, hasFolding=True)
|
||||
|
||||
|
||||
def GetFontAndColorFromConfig(self):
|
||||
@@ -130,7 +130,7 @@ class PerlCtrl(CodeEditor.CodeCtrl):
|
||||
class PerlOptionsPanel(STCTextEditor.TextOptionsPanel):
|
||||
|
||||
def __init__(self, parent, id):
|
||||
STCTextEditor.TextOptionsPanel.__init__(self, parent, id, configPrefix = "Perl", label = "Perl", hasWordWrap = True, hasTabs = True)
|
||||
STCTextEditor.TextOptionsPanel.__init__(self, parent, id, configPrefix = "Perl", label = "Perl", hasWordWrap = True, hasTabs = True, hasFolding=True)
|
||||
|
||||
|
||||
def GetIcon(self):
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -25,6 +25,7 @@ import keyword # for GetAutoCompleteKeywordList
|
||||
import sys # for GetAutoCompleteKeywordList
|
||||
import MessageService # for OnCheckCode
|
||||
import OutlineService
|
||||
import FindInDirService
|
||||
from UICommon import CaseInsensitiveCompare
|
||||
try:
|
||||
import checker # for pychecker
|
||||
@@ -143,9 +144,11 @@ class PythonView(CodeEditor.CodeView):
|
||||
# Set cursor to Wait cursor
|
||||
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
|
||||
|
||||
try:
|
||||
# This takes a while for involved code
|
||||
checker.checkSyntax(self.GetDocument().GetFilename(), view)
|
||||
|
||||
finally:
|
||||
# Set cursor to Default cursor
|
||||
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
|
||||
|
||||
@@ -369,8 +372,42 @@ class PythonCtrl(CodeEditor.CodeCtrl):
|
||||
self.SetKeyWords(0, string.join(keyword.kwlist))
|
||||
|
||||
|
||||
def CreatePopupMenu(self):
|
||||
FINDCLASS_ID = wx.NewId()
|
||||
FINDDEF_ID = wx.NewId()
|
||||
|
||||
menu = CodeEditor.CodeCtrl.CreatePopupMenu(self)
|
||||
|
||||
self.Bind(wx.EVT_MENU, self.OnPopFindDefinition, id=FINDDEF_ID)
|
||||
menu.Insert(1, FINDDEF_ID, _("Find 'def'"))
|
||||
|
||||
self.Bind(wx.EVT_MENU, self.OnPopFindClass, id=FINDCLASS_ID)
|
||||
menu.Insert(2, FINDCLASS_ID, _("Find 'class'"))
|
||||
|
||||
return menu
|
||||
|
||||
|
||||
def OnPopFindDefinition(self, event):
|
||||
view = wx.GetApp().GetDocumentManager().GetCurrentView()
|
||||
if hasattr(view, "GetCtrl") and view.GetCtrl() and hasattr(view.GetCtrl(), "GetSelectedText"):
|
||||
pattern = view.GetCtrl().GetSelectedText().strip()
|
||||
if pattern:
|
||||
searchPattern = "def\s+%s" % pattern
|
||||
wx.GetApp().GetService(FindInDirService.FindInDirService).FindInProject(searchPattern)
|
||||
|
||||
|
||||
def OnPopFindClass(self, event):
|
||||
view = wx.GetApp().GetDocumentManager().GetCurrentView()
|
||||
if hasattr(view, "GetCtrl") and view.GetCtrl() and hasattr(view.GetCtrl(), "GetSelectedText"):
|
||||
definition = "class\s+%s"
|
||||
pattern = view.GetCtrl().GetSelectedText().strip()
|
||||
if pattern:
|
||||
searchPattern = definition % pattern
|
||||
wx.GetApp().GetService(FindInDirService.FindInDirService).FindInProject(searchPattern)
|
||||
|
||||
|
||||
def SetViewDefaults(self):
|
||||
CodeEditor.CodeCtrl.SetViewDefaults(self, configPrefix = "Python", hasWordWrap = True, hasTabs = True)
|
||||
CodeEditor.CodeCtrl.SetViewDefaults(self, configPrefix="Python", hasWordWrap=True, hasTabs=True, hasFolding=True)
|
||||
|
||||
|
||||
def GetFontAndColorFromConfig(self):
|
||||
@@ -567,7 +604,7 @@ class PythonOptionsPanel(wx.Panel):
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
mainSizer.Add(pathSizer, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, SPACE)
|
||||
|
||||
self._otherOptions = STCTextEditor.TextOptionsPanel(self, -1, configPrefix = "Python", label = "Python", hasWordWrap = True, hasTabs = True, addPage=False)
|
||||
self._otherOptions = STCTextEditor.TextOptionsPanel(self, -1, configPrefix = "Python", label = "Python", hasWordWrap = True, hasTabs = True, addPage=False, hasFolding=True)
|
||||
mainSizer.Add(self._otherOptions, 0, wx.EXPAND|wx.BOTTOM, SPACE)
|
||||
self.SetSizer(mainSizer)
|
||||
parent.AddPage(self, _("Python"))
|
||||
@@ -577,7 +614,7 @@ class PythonOptionsPanel(wx.Panel):
|
||||
defaultDir = os.path.dirname(self._pathTextCtrl.GetValue().strip())
|
||||
defaultFile = os.path.basename(self._pathTextCtrl.GetValue().strip())
|
||||
if _WINDOWS:
|
||||
wildcard = _("Executable (*.exe)|*.exe|All (*.*)|*.*")
|
||||
wildcard = _("Executable (*.exe)|*.exe|All|*.*")
|
||||
if not defaultFile:
|
||||
defaultFile = "python.exe"
|
||||
else:
|
||||
|
@@ -6,7 +6,7 @@
|
||||
#
|
||||
# Created: 8/10/03
|
||||
# CVS-ID: $Id$
|
||||
# Copyright: (c) 2003-2005 ActiveGrid, Inc.
|
||||
# Copyright: (c) 2003-2006 ActiveGrid, Inc.
|
||||
# License: wxWindows License
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
@@ -47,9 +47,15 @@ TEXT_STATUS_BAR_ID = wx.NewId()
|
||||
class TextDocument(wx.lib.docview.Document):
|
||||
|
||||
|
||||
def __init__(self):
|
||||
wx.lib.docview.Document .__init__(self)
|
||||
self._inModify = False
|
||||
|
||||
|
||||
def SaveObject(self, fileObject):
|
||||
view = self.GetFirstView()
|
||||
fileObject.write(view.GetValue())
|
||||
view.SetModifyFalse()
|
||||
return True
|
||||
|
||||
|
||||
@@ -57,23 +63,30 @@ class TextDocument(wx.lib.docview.Document):
|
||||
view = self.GetFirstView()
|
||||
data = fileObject.read()
|
||||
view.SetValue(data)
|
||||
view.SetModifyFalse()
|
||||
return True
|
||||
|
||||
|
||||
def IsModified(self):
|
||||
view = self.GetFirstView()
|
||||
if view:
|
||||
return wx.lib.docview.Document.IsModified(self) or view.IsModified()
|
||||
else:
|
||||
return wx.lib.docview.Document.IsModified(self)
|
||||
return view.IsModified()
|
||||
return False
|
||||
|
||||
|
||||
def Modify(self, mod):
|
||||
def Modify(self, modify):
|
||||
if self._inModify:
|
||||
return
|
||||
self._inModify = True
|
||||
|
||||
view = self.GetFirstView()
|
||||
wx.lib.docview.Document.Modify(self, mod)
|
||||
if not mod and view:
|
||||
if not modify and view:
|
||||
view.SetModifyFalse()
|
||||
|
||||
wx.lib.docview.Document.Modify(self, modify) # this must called be after the SetModifyFalse call above.
|
||||
|
||||
self._inModify = False
|
||||
|
||||
|
||||
def OnCreateCommandProcessor(self):
|
||||
# Don't create a command processor, it has its own
|
||||
@@ -142,6 +155,8 @@ class TextView(wx.lib.docview.View):
|
||||
self._dynSash._view = self
|
||||
self._textEditor = self.GetCtrlClass()(self._dynSash, -1, style=wx.NO_BORDER)
|
||||
wx.EVT_LEFT_DOWN(self._textEditor, self.OnLeftClick)
|
||||
self._textEditor.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModify)
|
||||
|
||||
self._CreateSizer(frame)
|
||||
self.Activate()
|
||||
frame.Show(True)
|
||||
@@ -149,6 +164,10 @@ class TextView(wx.lib.docview.View):
|
||||
return True
|
||||
|
||||
|
||||
def OnModify(self, event):
|
||||
self.GetDocument().Modify(self._textEditor.GetModify())
|
||||
|
||||
|
||||
def _CreateSizer(self, frame):
|
||||
sizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
sizer.Add(self._dynSash, 1, wx.EXPAND)
|
||||
@@ -161,6 +180,9 @@ class TextView(wx.lib.docview.View):
|
||||
|
||||
|
||||
def OnUpdate(self, sender = None, hint = None):
|
||||
if wx.lib.docview.View.OnUpdate(self, sender, hint):
|
||||
return
|
||||
|
||||
if hint == "ViewStuff":
|
||||
self.GetCtrl().SetViewDefaults()
|
||||
elif hint == "Font":
|
||||
@@ -571,9 +593,11 @@ class TextView(wx.lib.docview.View):
|
||||
def EnsureVisible(self, line):
|
||||
self.GetCtrl().EnsureVisible(line-1) # line numbering for editor is 0 based, we are 1 based.
|
||||
|
||||
|
||||
def EnsureVisibleEnforcePolicy(self, line):
|
||||
self.GetCtrl().EnsureVisibleEnforcePolicy(line-1) # line numbering for editor is 0 based, we are 1 based.
|
||||
|
||||
|
||||
def LineFromPosition(self, pos):
|
||||
return self.GetCtrl().LineFromPosition(pos)+1 # line numbering for editor is 0 based, we are 1 based.
|
||||
|
||||
@@ -813,11 +837,12 @@ class TextStatusBar(wx.StatusBar):
|
||||
class TextOptionsPanel(wx.Panel):
|
||||
|
||||
|
||||
def __init__(self, parent, id, configPrefix = "Text", label = "Text", hasWordWrap = True, hasTabs = False, addPage=True):
|
||||
def __init__(self, parent, id, configPrefix = "Text", label = "Text", hasWordWrap = True, hasTabs = False, addPage=True, hasFolding=False):
|
||||
wx.Panel.__init__(self, parent, id)
|
||||
self._configPrefix = configPrefix
|
||||
self._hasWordWrap = hasWordWrap
|
||||
self._hasTabs = hasTabs
|
||||
self._hasFolding = hasFolding
|
||||
SPACE = 10
|
||||
HALF_SPACE = 5
|
||||
config = wx.ConfigBase_Get()
|
||||
@@ -854,6 +879,9 @@ class TextOptionsPanel(wx.Panel):
|
||||
self._viewRightEdgeCheckBox.SetValue(config.ReadInt(self._configPrefix + "EditorViewRightEdge", False))
|
||||
self._viewLineNumbersCheckBox = wx.CheckBox(self, -1, _("Show line numbers"))
|
||||
self._viewLineNumbersCheckBox.SetValue(config.ReadInt(self._configPrefix + "EditorViewLineNumbers", True))
|
||||
if self._hasFolding:
|
||||
self._viewFoldingCheckBox = wx.CheckBox(self, -1, _("Show folding"))
|
||||
self._viewFoldingCheckBox.SetValue(config.ReadInt(self._configPrefix + "EditorViewFolding", True))
|
||||
if self._hasTabs:
|
||||
self._hasTabsCheckBox = wx.CheckBox(self, -1, _("Use spaces instead of tabs"))
|
||||
self._hasTabsCheckBox.SetValue(not wx.ConfigBase_Get().ReadInt(self._configPrefix + "EditorUseTabs", False))
|
||||
@@ -874,6 +902,8 @@ class TextOptionsPanel(wx.Panel):
|
||||
textPanelSizer.Add(self._viewIndentationGuideCheckBox, 0, wx.ALL, HALF_SPACE)
|
||||
textPanelSizer.Add(self._viewRightEdgeCheckBox, 0, wx.ALL, HALF_SPACE)
|
||||
textPanelSizer.Add(self._viewLineNumbersCheckBox, 0, wx.ALL, HALF_SPACE)
|
||||
if self._hasFolding:
|
||||
textPanelSizer.Add(self._viewFoldingCheckBox, 0, wx.ALL, HALF_SPACE)
|
||||
if self._hasTabs:
|
||||
textPanelSizer.Add(self._hasTabsCheckBox, 0, wx.ALL, HALF_SPACE)
|
||||
textIndentWidthSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
@@ -947,6 +977,9 @@ class TextOptionsPanel(wx.Panel):
|
||||
config.WriteInt(self._configPrefix + "EditorViewRightEdge", self._viewRightEdgeCheckBox.GetValue())
|
||||
doViewStuffUpdate = doViewStuffUpdate or config.ReadInt(self._configPrefix + "EditorViewLineNumbers", True) != self._viewLineNumbersCheckBox.GetValue()
|
||||
config.WriteInt(self._configPrefix + "EditorViewLineNumbers", self._viewLineNumbersCheckBox.GetValue())
|
||||
if self._hasFolding:
|
||||
doViewStuffUpdate = doViewStuffUpdate or config.ReadInt(self._configPrefix + "EditorViewFolding", True) != self._viewFoldingCheckBox.GetValue()
|
||||
config.WriteInt(self._configPrefix + "EditorViewFolding", self._viewFoldingCheckBox.GetValue())
|
||||
if self._hasWordWrap:
|
||||
doViewStuffUpdate = doViewStuffUpdate or config.ReadInt(self._configPrefix + "EditorWordWrap", False) != self._wordWrapCheckBox.GetValue()
|
||||
config.WriteInt(self._configPrefix + "EditorWordWrap", self._wordWrapCheckBox.GetValue())
|
||||
@@ -1062,13 +1095,15 @@ class TextCtrl(wx.stc.StyledTextCtrl):
|
||||
event.Skip()
|
||||
|
||||
|
||||
def SetViewDefaults(self, configPrefix = "Text", hasWordWrap = True, hasTabs = False):
|
||||
def SetViewDefaults(self, configPrefix="Text", hasWordWrap=True, hasTabs=False, hasFolding=False):
|
||||
config = wx.ConfigBase_Get()
|
||||
self.SetViewWhiteSpace(config.ReadInt(configPrefix + "EditorViewWhitespace", False))
|
||||
self.SetViewEOL(config.ReadInt(configPrefix + "EditorViewEOL", False))
|
||||
self.SetIndentationGuides(config.ReadInt(configPrefix + "EditorViewIndentationGuides", False))
|
||||
self.SetViewRightEdge(config.ReadInt(configPrefix + "EditorViewRightEdge", False))
|
||||
self.SetViewLineNumbers(config.ReadInt(configPrefix + "EditorViewLineNumbers", True))
|
||||
if hasFolding:
|
||||
self.SetViewFolding(config.ReadInt(configPrefix + "EditorViewFolding", True))
|
||||
if hasWordWrap:
|
||||
self.SetWordWrap(config.ReadInt(configPrefix + "EditorWordWrap", False))
|
||||
if hasTabs: # These methods do not exist in STCTextEditor and are meant for subclasses
|
||||
@@ -1237,6 +1272,17 @@ class TextCtrl(wx.stc.StyledTextCtrl):
|
||||
self.SetMarginWidth(1, 0)
|
||||
|
||||
|
||||
def GetViewFolding(self):
|
||||
return self.GetMarginWidth(2) > 0
|
||||
|
||||
|
||||
def SetViewFolding(self, viewFolding = True):
|
||||
if viewFolding:
|
||||
self.SetMarginWidth(2, 12)
|
||||
else:
|
||||
self.SetMarginWidth(2, 0)
|
||||
|
||||
|
||||
def CanWordWrap(self):
|
||||
return True
|
||||
|
||||
|
@@ -324,6 +324,7 @@ class SVNService(wx.lib.pydocview.DocService):
|
||||
return False
|
||||
|
||||
|
||||
try:
|
||||
if id == SVNService.SVN_UPDATE_ID:
|
||||
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
|
||||
|
||||
@@ -844,6 +845,8 @@ class SVNService(wx.lib.pydocview.DocService):
|
||||
return True
|
||||
|
||||
return False
|
||||
finally:
|
||||
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
|
||||
|
||||
|
||||
def ProcessUpdateUIEvent(self, event):
|
||||
|
@@ -6,7 +6,7 @@
|
||||
#
|
||||
# Created: 3/10/05
|
||||
# CVS-ID: $Id$
|
||||
# Copyright: (c) 2005 ActiveGrid, Inc.
|
||||
# Copyright: (c) 2005-2006 ActiveGrid, Inc.
|
||||
# License: wxWindows License
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
@@ -15,12 +15,14 @@ import os.path
|
||||
import wx
|
||||
import string
|
||||
import ProjectEditor
|
||||
import activegrid.util.sysutils as sysutils
|
||||
import activegrid.util.strutils as strutils
|
||||
import activegrid.util.appdirs as appdirs
|
||||
import activegrid.util.fileutils as fileutils
|
||||
import activegrid.util.strutils as strutils
|
||||
import activegrid.util.sysutils as sysutils
|
||||
import activegrid.util.xmlutils as xmlutils
|
||||
_ = wx.GetTranslation
|
||||
|
||||
def CreateDirectoryControl( parent, fileLabel=_("File Name:"), dirLabel=_("Directory"), fileExtension="*", startingName="", startingDirectory=None, choiceDirs=None, appDirDefaultStartDir=False, returnAll=False):
|
||||
def CreateDirectoryControl( parent, fileLabel=_("File Name:"), dirLabel=_("Directory:"), fileExtension="*", startingName="", startingDirectory=None, choiceDirs=None, appDirDefaultStartDir=False, returnAll=False, useDirDialog=False):
|
||||
|
||||
if not choiceDirs:
|
||||
choiceDirs = []
|
||||
@@ -61,8 +63,8 @@ def CreateDirectoryControl( parent, fileLabel=_("File Name:"), dirLabel=_("Direc
|
||||
|
||||
if os.getcwd() not in choiceDirs:
|
||||
choiceDirs.append(os.getcwd())
|
||||
if appdirs.documents_folder not in choiceDirs:
|
||||
choiceDirs.append(appdirs.documents_folder)
|
||||
if appdirs.getSystemDir() not in choiceDirs:
|
||||
choiceDirs.append(appdirs.getSystemDir())
|
||||
|
||||
if not startingDirectory:
|
||||
startingDirectory = os.getcwd()
|
||||
@@ -85,11 +87,17 @@ def CreateDirectoryControl( parent, fileLabel=_("File Name:"), dirLabel=_("Direc
|
||||
else:
|
||||
name = _("%s.%s") % (nameCtrlValue, fileExtension)
|
||||
|
||||
if not useDirDialog:
|
||||
dlg = wx.FileDialog(parent, _("Choose a filename and directory"),
|
||||
defaultDir = dirControl.GetValue().strip(),
|
||||
defaultFile = name,
|
||||
wildcard= "*.%s" % fileExtension,
|
||||
style=wx.SAVE|wx.CHANGE_DIR)
|
||||
else:
|
||||
dlg = wx.DirDialog(wx.GetApp().GetTopWindow(),
|
||||
_("Choose a directory:"),
|
||||
defaultPath=dirControl.GetValue().strip(),
|
||||
style=wx.DD_DEFAULT_STYLE|wx.DD_NEW_DIR_BUTTON)
|
||||
|
||||
if dlg.ShowModal() != wx.ID_OK:
|
||||
dlg.Destroy()
|
||||
@@ -98,31 +106,51 @@ def CreateDirectoryControl( parent, fileLabel=_("File Name:"), dirLabel=_("Direc
|
||||
dlg.Destroy()
|
||||
|
||||
if path:
|
||||
if not useDirDialog:
|
||||
dir, filename = os.path.split(path)
|
||||
if dirControl.FindString(dir) == wx.NOT_FOUND:
|
||||
dirControl.Insert(dir, 0)
|
||||
dirControl.SetValue(dir)
|
||||
dirControl.SetToolTipString(dir)
|
||||
nameControl.SetValue(filename)
|
||||
else:
|
||||
dirControl.SetValue(path)
|
||||
dirControl.SetToolTipString(path)
|
||||
|
||||
parent.Bind(wx.EVT_BUTTON, OnFindDirClick, button)
|
||||
|
||||
def Validate(allowOverwriteOnPrompt=False, infoString='', noFirstCharDigit=False):
|
||||
def Validate(allowOverwriteOnPrompt=False, infoString='', validClassName=False, ignoreFileConflicts=False):
|
||||
projName = nameControl.GetValue().strip()
|
||||
if projName == "":
|
||||
wx.MessageBox(_("Please provide a %sfile name.") % infoString, _("Provide a File Name"))
|
||||
return False
|
||||
if noFirstCharDigit and projName[0].isdigit():
|
||||
wx.MessageBox(_("File name cannot start with a number. Please enter a different name."), _("Invalid File Name"))
|
||||
return False
|
||||
if projName.find(' ') != -1:
|
||||
wx.MessageBox(_("Please provide a %sfile name that does not contains spaces.") % infoString, _("Spaces in File Name"))
|
||||
return False
|
||||
if not os.path.exists(dirControl.GetValue()):
|
||||
wx.MessageBox(_("That %sdirectory does not exist. Please choose an existing directory.") % infoString, _("Provide a Valid Directory"))
|
||||
if validClassName:
|
||||
if projName[0].isdigit():
|
||||
wx.MessageBox(_("File name cannot start with a number. Please enter a different name."), _("Invalid File Name"))
|
||||
return False
|
||||
if projName.endswith(".agp"):
|
||||
projName2 = projName[:-4]
|
||||
else:
|
||||
projName2 = projName
|
||||
if not projName2.replace("_", "a").isalnum(): # [a-zA-Z0-9_] note '_' is allowed and ending '.agp'.
|
||||
wx.MessageBox(_("Name must be alphanumeric ('_' allowed). Please enter a valid name."), _("Project Name"))
|
||||
return False
|
||||
|
||||
filePath = os.path.join(dirControl.GetValue(), MakeNameEndInExtension(projName, "." + fileExtension))
|
||||
dirName = dirControl.GetValue().strip()
|
||||
if dirName == "":
|
||||
wx.MessageBox(_("No directory. Please provide a directory."), _("Provide a Directory"))
|
||||
return False
|
||||
if os.sep == "\\" and dirName.find("/") != -1:
|
||||
wx.MessageBox(_("Wrong delimiter '/' found in directory path. Use '%s' as delimiter.") % os.sep, _("Provide a Valid Directory"))
|
||||
return False
|
||||
if not os.path.exists(dirName):
|
||||
wx.MessageBox(_("That %sdirectory does not exist. Please choose an existing directory.") % infoString, _("Provide a Valid Directory"))
|
||||
return False
|
||||
if not ignoreFileConflicts:
|
||||
filePath = os.path.join(dirName, MakeNameEndInExtension(projName, "." + fileExtension))
|
||||
if os.path.exists(filePath):
|
||||
if allowOverwriteOnPrompt:
|
||||
res = wx.MessageBox(_("That %sfile already exists. Would you like to overwrite it.") % infoString, "File Exists", style=wx.YES_NO|wx.NO_DEFAULT)
|
||||
@@ -130,17 +158,26 @@ def CreateDirectoryControl( parent, fileLabel=_("File Name:"), dirLabel=_("Direc
|
||||
else:
|
||||
wx.MessageBox(_("That %sfile already exists. Please choose a different name.") % infoString, "File Exists")
|
||||
return False
|
||||
|
||||
return True
|
||||
HALF_SPACE = 5
|
||||
flexGridSizer = wx.FlexGridSizer(cols = 3, vgap = HALF_SPACE, hgap = HALF_SPACE)
|
||||
flexGridSizer.AddGrowableCol(1,1)
|
||||
if not useDirDialog:
|
||||
flexGridSizer.Add(nameLabelText, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)
|
||||
flexGridSizer.Add(nameControl, 2, flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
|
||||
flexGridSizer.Add(button, flag=wx.ALIGN_RIGHT|wx.LEFT, border=HALF_SPACE)
|
||||
|
||||
flexGridSizer.Add(dirLabelText, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)
|
||||
flexGridSizer.Add(dirControl, 2, flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
|
||||
flexGridSizer.Add(wx.StaticText(parent, -1, ""), 0)
|
||||
else:
|
||||
flexGridSizer.Add(nameLabelText, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)
|
||||
flexGridSizer.Add(nameControl, 2, flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
|
||||
flexGridSizer.Add(wx.StaticText(parent, -1, ""), 0)
|
||||
flexGridSizer.Add(dirLabelText, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)
|
||||
flexGridSizer.Add(dirControl, 2, flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
|
||||
flexGridSizer.Add(button, flag=wx.ALIGN_RIGHT|wx.LEFT, border=HALF_SPACE)
|
||||
|
||||
if returnAll:
|
||||
return nameControl, dirControl, flexGridSizer, Validate, allControls
|
||||
else:
|
||||
@@ -188,8 +225,8 @@ def CreateDirectoryOnlyControl( parent, dirLabel=_("Location:"), startingDirecto
|
||||
|
||||
if os.getcwd() not in choiceDirs:
|
||||
choiceDirs.append(os.getcwd())
|
||||
if appdirs.documents_folder not in choiceDirs:
|
||||
choiceDirs.append(appdirs.documents_folder)
|
||||
if appdirs.getSystemDir() not in choiceDirs:
|
||||
choiceDirs.append(appdirs.getSystemDir())
|
||||
|
||||
|
||||
if not startingDirectory:
|
||||
@@ -221,6 +258,9 @@ def CreateDirectoryOnlyControl( parent, dirLabel=_("Location:"), startingDirecto
|
||||
if dirName == "":
|
||||
wx.MessageBox(_("Please provide a directory."), _("Provide a Directory"))
|
||||
return False
|
||||
if os.sep == "\\" and dirName.find("/") != -1:
|
||||
wx.MessageBox(_("Wrong delimiter '/' found in directory path. Use '%s' as delimiter.") % os.sep, _("Provide a Valid Directory"))
|
||||
return False
|
||||
if not os.path.exists(dirName):
|
||||
wx.MessageBox(_("That directory does not exist. Please choose an existing directory."), _("Provide a Valid Directory"))
|
||||
return False
|
||||
@@ -241,16 +281,24 @@ def CreateNameOnlyControl( parent, fileLabel, startingName="", startingDirectory
|
||||
fileLabelText = wx.StaticText(parent, -1, fileLabel)
|
||||
nameControl = wx.TextCtrl(parent, -1, startingName, size=(-1,-1))
|
||||
|
||||
def Validate(allowOverwriteOnPrompt=False, noFirstCharDigit=False):
|
||||
def Validate(allowOverwriteOnPrompt=False, validClassName=False):
|
||||
projName = nameControl.GetValue().strip()
|
||||
if projName == "":
|
||||
wx.MessageBox(_("Blank name. Please enter a valid name."), _("Project Name"))
|
||||
return False
|
||||
if noFirstCharDigit and projName[0].isdigit():
|
||||
if projName.find(' ') != -1:
|
||||
wx.MessageBox(_("Spaces in name. Name cannot have spaces."), _("Project Name"))
|
||||
return False
|
||||
if validClassName:
|
||||
if projName[0].isdigit():
|
||||
wx.MessageBox(_("Name cannot start with a number. Please enter a valid name."), _("Project Name"))
|
||||
return False
|
||||
if projName.find(' ') != -1:
|
||||
wx.MessageBox(_("Spaces in name. Name cannot have spaces.") % infoString, _("Project Name"))
|
||||
if projName.endswith(".agp"):
|
||||
projName2 = projName[:-4]
|
||||
else:
|
||||
projName2 = projName
|
||||
if not projName2.replace("_", "a").isalnum(): # [a-zA-Z0-9_] note '_' is allowed and ending '.agp'.
|
||||
wx.MessageBox(_("Name must be alphanumeric ('_' allowed). Please enter a valid name."), _("Project Name"))
|
||||
return False
|
||||
path = os.path.join(startingDirectoryControl.GetValue().strip(), projName)
|
||||
if os.path.exists(path):
|
||||
@@ -280,6 +328,29 @@ def CreateNameOnlyControl( parent, fileLabel, startingName="", startingDirectory
|
||||
return nameControl, flexGridSizer, Validate
|
||||
|
||||
|
||||
def ValidateName(name, ext=None, hint="name"):
|
||||
""" Returns an error string if there is something wrong with the name.
|
||||
Otherwise it returns None
|
||||
"""
|
||||
if name == "":
|
||||
return _("Blank %s. Please enter a valid %s.") % (hint, hint)
|
||||
|
||||
if name.find(' ') != -1:
|
||||
return _("Spaces in %s. %s cannot have spaces.") % (hint, hint.title())
|
||||
|
||||
if name[0].isdigit():
|
||||
return _("%s cannot start with a number. Please enter a valid %s.") % (hint.title(), hint)
|
||||
|
||||
if ext and name.endswith(ext): # strip extension if provided
|
||||
lenExt = len(ext)
|
||||
name = name[:-lenExt]
|
||||
|
||||
if not name.replace("_", "a").isalnum(): # [a-zA-Z0-9_] note '_' is allowed and ext ending.
|
||||
return _("%s must be alphanumeric ('_' allowed). Please enter a valid %s.") % (hint.title(), hint)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def GetCurrentProject():
|
||||
projectDocument = None
|
||||
projectService = wx.GetApp().GetService(ProjectEditor.ProjectService)
|
||||
@@ -330,6 +401,16 @@ def GetPythonExecPath():
|
||||
return pythonExecPath
|
||||
|
||||
|
||||
def GetPHPExecPath():
|
||||
PHPExecPath = wx.ConfigBase_Get().Read("ActiveGridPHPLocation")
|
||||
return PHPExecPath
|
||||
|
||||
|
||||
def GetPHPINIPath():
|
||||
PHPINIPath = wx.ConfigBase_Get().Read("ActiveGridPHPINILocation")
|
||||
return PHPINIPath
|
||||
|
||||
|
||||
def _DoRemoveRecursive(path, skipFile=None, skipped=False):
|
||||
if path == skipFile:
|
||||
skipped = True
|
||||
@@ -362,8 +443,13 @@ def CaseInsensitiveCompare(s1, s2):
|
||||
|
||||
def GetAnnotation(model, elementName):
|
||||
""" Get an object's annotation used for tooltips """
|
||||
if hasattr(model, "__xsdcomplextype__"):
|
||||
if hasattr(model, "_complexType"):
|
||||
ct = model._complexType
|
||||
elif hasattr(model, "__xsdcomplextype__"):
|
||||
ct = model.__xsdcomplextype__
|
||||
else:
|
||||
ct = None
|
||||
|
||||
if ct:
|
||||
el = ct.findElement(elementName)
|
||||
if el and el.annotation:
|
||||
@@ -372,6 +458,47 @@ def GetAnnotation(model, elementName):
|
||||
return ""
|
||||
|
||||
|
||||
def GetDisplayName(doc, name):
|
||||
if name:
|
||||
appDocMgr = doc.GetAppDocMgr()
|
||||
if appDocMgr:
|
||||
name = appDocMgr.toDisplayTypeName(name)
|
||||
else:
|
||||
namespace, name = xmlutils.splitType(name)
|
||||
if namespace and hasattr(doc.GetModel(), "getXmlNamespaces"):
|
||||
for xmlkey, xmlval in doc.GetModel().getXmlNamespaces().iteritems():
|
||||
if xmlval == namespace:
|
||||
name = "%s:%s" % (xmlkey, name)
|
||||
break
|
||||
|
||||
if name:
|
||||
import activegrid.model.schema as schemalib
|
||||
baseTypeName = schemalib.mapXsdType(name)
|
||||
if baseTypeName:
|
||||
name = baseTypeName
|
||||
|
||||
return name
|
||||
|
||||
|
||||
def GetInternalName(doc, name):
|
||||
if name:
|
||||
appDocMgr = doc.GetAppDocMgr()
|
||||
if appDocMgr:
|
||||
name = appDocMgr.toInternalTypeName(name)
|
||||
else:
|
||||
namespace, name = xmlutils.splitType(name)
|
||||
if namespace and hasattr(doc.GetModel(), "getXmlNamespaces"):
|
||||
for xmlkey, xmlval in doc.GetModel().getXmlNamespaces().iteritems():
|
||||
if xmlkey == namespace:
|
||||
name = "%s:%s" % (xmlval, name)
|
||||
break
|
||||
|
||||
import activegrid.model.schema as schemalib
|
||||
name = schemalib.mapAGType(name)
|
||||
|
||||
return name
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Methods for finding application level info
|
||||
#----------------------------------------------------------------------------
|
||||
@@ -435,7 +562,8 @@ def GetAppDocMgrForDoc(doc):
|
||||
|
||||
|
||||
def GetAppInfoLanguage(doc=None):
|
||||
from activegrid.server.deployment import LANGUAGE_DEFAULT
|
||||
from activegrid.server.projectmodel import LANGUAGE_DEFAULT
|
||||
|
||||
if doc:
|
||||
language = doc.GetAppInfo().language
|
||||
else:
|
||||
@@ -449,3 +577,159 @@ def GetAppInfoLanguage(doc=None):
|
||||
doc.GetAppInfo().language = language # once it is selected, it must be set.
|
||||
|
||||
return language
|
||||
|
||||
def AddWsdlAgToProjectFromWsdlRegistration(wsdlRegistration):
|
||||
"""Add wsdl ag for registry entry."""
|
||||
|
||||
wsdlPath = wsdlRegistration.path
|
||||
rootPath = None
|
||||
serviceRefName = wsdlRegistration.name
|
||||
|
||||
agwsDoc = _InitWsdlAg(wsdlPath, rootPath, serviceRefName)
|
||||
|
||||
if (agwsDoc == None):
|
||||
return
|
||||
|
||||
serviceRef = agwsDoc.GetModel()
|
||||
|
||||
serviceRef.serviceType = wsdlRegistration.type
|
||||
|
||||
import activegrid.server.deployment as deployment
|
||||
|
||||
if (serviceRef.serviceType == deployment.SERVICE_LOCAL):
|
||||
serviceRef.localService = deployment.LocalService(
|
||||
wsdlRegistration.codeFile)
|
||||
|
||||
elif (serviceRef.serviceType == deployment.SERVICE_DATABASE):
|
||||
serviceRef.databaseService = deployment.DatabaseService(
|
||||
wsdlRegistration.datasourceName)
|
||||
|
||||
elif (serviceRef.serviceType == deployment.SERVICE_SOAP):
|
||||
pass
|
||||
|
||||
elif (serviceRef.serviceType == deployment.SERVICE_RSS):
|
||||
serviceRef.rssService = deployment.RssService(wsdlRegistration.feedUrl)
|
||||
|
||||
elif (serviceRef.serviceType == deployment.SERVICE_REST):
|
||||
serviceRef.restService = deployment.RestService(
|
||||
wsdlRegistration.baseUrl)
|
||||
else:
|
||||
raise AssertionError("Unknown service type")
|
||||
|
||||
_AddToProject(agwsDoc, addWsdl=True)
|
||||
|
||||
|
||||
def AddWsdlAgToProject(wsdlPath, rootPath=fileutils.AG_SYSTEM_STATIC_VAR_REF,
|
||||
serviceRefName=None, className=None, serviceType=None,
|
||||
dataSourceName=None):
|
||||
"""
|
||||
wsdlPath: path to wsdl from rootPath. If wsdlPath is absolute, rootPath
|
||||
is ignored. rootPath is also ignored when rootPath is set to None.
|
||||
rootPath: defaults to ${AG_SYSTEM_STATIC}.
|
||||
serviceRefName: If None, it will be set to the wsdl file name without
|
||||
the .wsdl file extension.
|
||||
className: if not None, will be used for the the wsdlag's ClassName.
|
||||
serviceType: defaults to local.
|
||||
dataSourceName: if serviceType is deployment.DATABASE, the ds must be
|
||||
provided.
|
||||
"""
|
||||
import WsdlAgEditor
|
||||
import XFormWizard
|
||||
import activegrid.model.basedocmgr as basedocmgr
|
||||
import activegrid.server.deployment as deployment
|
||||
|
||||
if (serviceType == None):
|
||||
serviceType = deployment.SERVICE_LOCAL
|
||||
|
||||
|
||||
agwsDoc = _InitWsdlAg(wsdlPath, rootPath, serviceRefName)
|
||||
|
||||
if (agwsDoc == None):
|
||||
return
|
||||
|
||||
serviceRef = agwsDoc.GetModel()
|
||||
|
||||
serviceRef.serviceType = serviceType
|
||||
|
||||
if (serviceType == deployment.SERVICE_DATABASE and dataSourceName != None):
|
||||
serviceRef.databaseService = deployment.DatabaseService(dataSourceName)
|
||||
else:
|
||||
serviceRef.localService = deployment.LocalService(className=className)
|
||||
|
||||
_AddToProject(agwsDoc)
|
||||
|
||||
|
||||
def _AddToProject(agwsDoc, addWsdl=False):
|
||||
import activegrid.model.basedocmgr as basedocmgr
|
||||
projectDoc = GetCurrentProject()
|
||||
agwsDoc.OnSaveDocument(agwsDoc.GetFilename())
|
||||
|
||||
files = [agwsDoc.fileName]
|
||||
types = [basedocmgr.FILE_TYPE_SERVICE]
|
||||
names = [agwsDoc.GetModel().name]
|
||||
if (addWsdl):
|
||||
m = agwsDoc.GetModel()
|
||||
wsdlName = os.path.splitext(os.path.basename(m.filePath))[0]
|
||||
appDocMgr = projectDoc.GetAppDocMgr()
|
||||
if (appDocMgr.findService(wsdlName) == None):
|
||||
m = agwsDoc.GetModel()
|
||||
files.append(m.filePath)
|
||||
types.append(None)
|
||||
names.append(wsdlName)
|
||||
|
||||
ProjectEditor.ProjectAddFilesCommand(projectDoc, files, types=types,
|
||||
names=names).Do()
|
||||
|
||||
|
||||
def _InitWsdlAg(wsdlPath, rootPath=fileutils.AG_SYSTEM_STATIC_VAR_REF,
|
||||
serviceRefName=None):
|
||||
|
||||
projectDoc = GetCurrentProject()
|
||||
appDocMgr = projectDoc.GetAppDocMgr()
|
||||
|
||||
if (serviceRefName == None):
|
||||
serviceRefName = os.path.splitext(os.path.basename(wsdlPath))[0]
|
||||
|
||||
if (appDocMgr.findServiceRef(serviceRefName) != None):
|
||||
return None
|
||||
|
||||
import WsdlAgEditor
|
||||
import XFormWizard
|
||||
import activegrid.server.deployment as deployment
|
||||
|
||||
template = XFormWizard.GetTemplate(WsdlAgEditor.WsdlAgDocument)
|
||||
ext = template.GetDefaultExtension()
|
||||
fullPath = os.path.join(appDocMgr.homeDir, serviceRefName + ext)
|
||||
|
||||
agwsDoc = template.CreateDocument(
|
||||
fullPath, flags=(wx.lib.docview.DOC_NO_VIEW|wx.lib.docview.DOC_NEW|
|
||||
wx.lib.docview.DOC_OPEN_ONCE))
|
||||
|
||||
serviceRef = agwsDoc.GetModel()
|
||||
serviceRef.name = serviceRefName
|
||||
|
||||
if (rootPath == None or os.path.isabs(wsdlPath)):
|
||||
serviceRef.filePath = wsdlPath
|
||||
else:
|
||||
# make sure to use forward slashes for the path to the .wsdl
|
||||
wsdlPath = wsdlPath.replace("\\", "/")
|
||||
|
||||
if not wsdlPath.startswith("/"):
|
||||
wsdlPath = "/%s" % wsdlPath
|
||||
serviceRef.filePath = "%s%s" % (rootPath, wsdlPath)
|
||||
|
||||
agwsDoc.fileName = fullPath
|
||||
|
||||
return agwsDoc
|
||||
|
||||
|
||||
def GetSchemaName(schema):
|
||||
return os.path.basename(schema.fileName)
|
||||
|
||||
|
||||
class AGChoice(wx.Choice):
|
||||
"""Extension to wx.Choice that fixes linux bug where first item of choices
|
||||
passed into ctor would be visible, but not selected."""
|
||||
def __init__(self, parent, id, choices=[]):
|
||||
super(AGChoice, self).__init__(parent=parent, id=id)
|
||||
self.AppendItems(choices)
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -78,7 +78,7 @@ class XmlCtrl(CodeEditor.CodeCtrl):
|
||||
|
||||
|
||||
def SetViewDefaults(self):
|
||||
CodeEditor.CodeCtrl.SetViewDefaults(self, configPrefix = "Xml", hasWordWrap = True, hasTabs = True)
|
||||
CodeEditor.CodeCtrl.SetViewDefaults(self, configPrefix = "Xml", hasWordWrap = True, hasTabs = True, hasFolding=True)
|
||||
|
||||
|
||||
def GetFontAndColorFromConfig(self):
|
||||
@@ -115,7 +115,7 @@ class XmlCtrl(CodeEditor.CodeCtrl):
|
||||
class XmlOptionsPanel(STCTextEditor.TextOptionsPanel):
|
||||
|
||||
def __init__(self, parent, id):
|
||||
STCTextEditor.TextOptionsPanel.__init__(self, parent, id, configPrefix = "Xml", label = "XML", hasWordWrap = True, hasTabs = True)
|
||||
STCTextEditor.TextOptionsPanel.__init__(self, parent, id, configPrefix = "Xml", label = "XML", hasWordWrap = True, hasTabs = True, hasFolding=True)
|
||||
|
||||
|
||||
def GetIcon(self):
|
||||
|
BIN
wxPython/samples/ide/activegrid/tool/bmp_source/activegrid.ico
Normal file
BIN
wxPython/samples/ide/activegrid/tool/bmp_source/activegrid.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 170 KiB |
@@ -1,7 +1,7 @@
|
||||
Middle-Mouse-Click on the tab for an open file will close the file.
|
||||
Ctrl-Space in any editor does code completion.
|
||||
Right-clicking on something in the 'Thing' column of the debugger's frame tab may allow you to introspect it for more information.
|
||||
Right-Mouse-Click in Outline window allows you to change display sorting.
|
||||
In an editor, you can add line markers via Ctrl-M and jump to the next marker with F4 or previous marker with Shift-F4.
|
||||
In an editor. you can use the numpad + and - keys to toggle folding.
|
||||
In 'Find in Directory', if you specify a file, it will display all matches in the Message Window.
|
||||
Breakpoints for the debugger can be set while the process is running
|
||||
Breakpoints for the debugger can be set while the process is running.
|
||||
A split window can be closed by dragging the sash to one of its borders.
|
@@ -407,7 +407,13 @@ _SaferCreateProcess(appName=%r,
|
||||
elif env:
|
||||
uenv = {}
|
||||
for key, val in env.items():
|
||||
uenv[unicode(key)] = unicode(val)
|
||||
try:
|
||||
uenv[unicode(key)] = unicode(val) # default encoding
|
||||
except UnicodeError:
|
||||
try:
|
||||
uenv[unicode(key, 'iso-8859-1')] = unicode(val, 'iso-8859-1') # backup encoding
|
||||
except UnicodeError:
|
||||
log.warn('Skipping environment variable "%s" in execution process: unable to convert to unicode using either the default encoding or ISO-8859-1' % (key))
|
||||
env = uenv
|
||||
hProcess, hThread, processId, threadId\
|
||||
= win32process.CreateProcess(appName, cmd, processSA,
|
||||
|
@@ -14,7 +14,16 @@ import copy
|
||||
import os
|
||||
import os.path
|
||||
import activegrid.util.xmlutils as xmlutils
|
||||
import activegrid.util.aglogging as aglogging
|
||||
|
||||
# REVIEW 07-Mar-06 stoens@activegrid.com -- Ideally move the pieces required
|
||||
# to generate the .dpl file out of this module so there's no dependency on wx,
|
||||
# instead of doing this try/catch (IDE drags in wx).
|
||||
try:
|
||||
from IDE import ACTIVEGRID_BASE_IDE
|
||||
except:
|
||||
ACTIVEGRID_BASE_IDE = False
|
||||
|
||||
if not ACTIVEGRID_BASE_IDE:
|
||||
import activegrid.model.basedocmgr as basedocmgr
|
||||
import AppInfo
|
||||
@@ -28,64 +37,6 @@ PROJECT_VERSION_050730 = '10'
|
||||
PROJECT_VERSION_050826 = '11'
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# XML Marshalling Methods
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
def load(fileObject):
|
||||
version = xmlutils.getAgVersion(fileObject.name)
|
||||
# most current versions on top
|
||||
if version == PROJECT_VERSION_050826:
|
||||
fileObject.seek(0)
|
||||
if ACTIVEGRID_BASE_IDE:
|
||||
KNOWNTYPES = {"ag:project" : Project, "ag:file" : ProjectFile}
|
||||
else:
|
||||
KNOWNTYPES = {"ag:project" : Project, "ag:file" : ProjectFile, "ag:appInfo" : AppInfo.AppInfo}
|
||||
project = xmlutils.load(fileObject.name, knownTypes=KNOWNTYPES, knownNamespaces=xmlutils.KNOWN_NAMESPACES)
|
||||
elif version == PROJECT_VERSION_050730:
|
||||
fileObject.seek(0)
|
||||
project = xmlutils.load(fileObject.name, knownTypes={"project" : Project_10})
|
||||
project = project.upgradeVersion()
|
||||
else:
|
||||
# assume it is old version without version number
|
||||
fileObject.seek(0)
|
||||
project = xmlutils.load(fileObject.name, knownTypes={"project" : Project_10})
|
||||
if project:
|
||||
project = project.upgradeVersion()
|
||||
else:
|
||||
print "Project, unknown version:", version
|
||||
return None
|
||||
|
||||
if project:
|
||||
project._projectDir = os.path.dirname(fileObject.name)
|
||||
project.RelativeToAbsPath()
|
||||
|
||||
return project
|
||||
|
||||
|
||||
def save(fileObject, project, productionDeployment=False):
|
||||
if not project._projectDir:
|
||||
project._projectDir = os.path.dirname(fileObject.name)
|
||||
project.AbsToRelativePath() # temporarily change it to relative paths for saving
|
||||
if ACTIVEGRID_BASE_IDE:
|
||||
KNOWNTYPES = {"ag:project" : Project, "ag:file" : ProjectFile}
|
||||
else:
|
||||
KNOWNTYPES = {"ag:project" : Project, "ag:file" : ProjectFile, "ag:appInfo" : AppInfo.AppInfo}
|
||||
|
||||
savedHomeDir = project.homeDir
|
||||
if productionDeployment:
|
||||
# for deployments, we don't want an abs path in homeDir since that
|
||||
# would tie the app to the current filesystem. So unset it.
|
||||
project.homeDir = None
|
||||
|
||||
xmlutils.save(fileObject.name, project, prettyPrint=True, knownTypes=KNOWNTYPES, knownNamespaces=xmlutils.KNOWN_NAMESPACES)
|
||||
|
||||
if productionDeployment:
|
||||
project.homeDir = savedHomeDir
|
||||
|
||||
project.RelativeToAbsPath() # swap it back to absolute path
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Classes
|
||||
#----------------------------------------------------------------------------
|
||||
@@ -93,7 +44,7 @@ def save(fileObject, project, productionDeployment=False):
|
||||
class BaseProject(object):
|
||||
|
||||
__xmlname__ = "project"
|
||||
__xmlexclude__ = ('fileName', '_projectDir', '_getDocCallback')
|
||||
__xmlexclude__ = ('fileName', '_projectDir', '_getDocCallback', '_cacheEnabled')
|
||||
__xmlattributes__ = ("_homeDir", "version")
|
||||
__xmlrename__ = { "_homeDir":"homeDir", "_appInfo":"appInfo" }
|
||||
__xmlflattensequence__ = { "_files":("file",) }
|
||||
@@ -107,25 +58,26 @@ class BaseProject(object):
|
||||
self._files = []
|
||||
self._projectDir = None # default for homeDir, set on load
|
||||
self._homeDir = None # user set homeDir for use in calculating relative path
|
||||
self._cacheEnabled = 0
|
||||
if not ACTIVEGRID_BASE_IDE:
|
||||
self._appInfo = AppInfo.AppInfo()
|
||||
|
||||
|
||||
def initialize(self):
|
||||
for file in self._files:
|
||||
file._parentProj = self
|
||||
|
||||
|
||||
def __copy__(self):
|
||||
clone = Project()
|
||||
clone._files = [copy.copy(file) for file in self._files]
|
||||
clone._projectDir = self._projectDir
|
||||
clone._homeDir = self._homeDir
|
||||
if not ACTIVEGRID_BASE_IDE:
|
||||
clone._appInfo = self._appInfo
|
||||
clone._appInfo = copy.copy(self._appInfo)
|
||||
return clone
|
||||
|
||||
|
||||
def initialize(self):
|
||||
""" Required method for xmlmarshaller """
|
||||
pass
|
||||
|
||||
|
||||
def GetAppInfo(self):
|
||||
return self._appInfo
|
||||
|
||||
@@ -138,7 +90,7 @@ class BaseProject(object):
|
||||
if file:
|
||||
self._files.append(file)
|
||||
else:
|
||||
self._files.append(ProjectFile(filePath, logicalFolder, type, name, getDocCallback=self._getDocCallback))
|
||||
self._files.append(ProjectFile(self, filePath, logicalFolder, type, name, getDocCallback=self._getDocCallback))
|
||||
|
||||
|
||||
def RemoveFile(self, file):
|
||||
@@ -160,6 +112,10 @@ class BaseProject(object):
|
||||
|
||||
filePaths = property(_GetFilePaths)
|
||||
|
||||
def _GetProjectFiles(self):
|
||||
return self._files
|
||||
projectFiles = property(_GetProjectFiles)
|
||||
|
||||
|
||||
def _GetLogicalFolders(self):
|
||||
folders = []
|
||||
@@ -224,6 +180,33 @@ class BaseProject(object):
|
||||
file.RelativeToAbsPath(self.homeDir)
|
||||
|
||||
|
||||
def _SetCache(self, enable):
|
||||
"""
|
||||
Only turn this on if your operation assumes files on disk won't change.
|
||||
Once your operation is done, turn this back off.
|
||||
Nested enables are allowed, only the last disable will disable the cache.
|
||||
|
||||
This bypasses the IsDocumentModificationDateCorrect call because the modification date check is too costly, it hits the disk and takes too long.
|
||||
"""
|
||||
if enable:
|
||||
if self._cacheEnabled == 0:
|
||||
# clear old cache, don't want to accidentally return stale value
|
||||
for file in self._files:
|
||||
file.ClearCache()
|
||||
|
||||
self._cacheEnabled += 1
|
||||
else:
|
||||
self._cacheEnabled -= 1
|
||||
|
||||
|
||||
|
||||
def _GetCache(self):
|
||||
return (self._cacheEnabled > 0)
|
||||
|
||||
|
||||
cacheEnabled = property(_GetCache, _SetCache)
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# BaseDocumentMgr methods
|
||||
#----------------------------------------------------------------------------
|
||||
@@ -242,7 +225,7 @@ class BaseProject(object):
|
||||
|
||||
|
||||
def documentRefFactory(self, name, fileType, filePath):
|
||||
return ProjectFile(filePath=self.fullPath(filePath), type=fileType, name=name, getDocCallback=self._getDocCallback)
|
||||
return ProjectFile(self, filePath=self.fullPath(filePath), type=fileType, name=name, getDocCallback=self._getDocCallback)
|
||||
|
||||
|
||||
def findAllRefs(self):
|
||||
@@ -299,12 +282,13 @@ else:
|
||||
|
||||
class ProjectFile(object):
|
||||
__xmlname__ = "file"
|
||||
__xmlexclude__ = ('_getDocCallback', '_docCallbackCacheReturnValue', '_docModelCallbackCacheReturnValue', '_doc',)
|
||||
__xmlexclude__ = ('_parentProj', '_getDocCallback', '_docCallbackCacheReturnValue', '_docModelCallbackCacheReturnValue', '_doc',)
|
||||
__xmlattributes__ = ["filePath", "logicalFolder", "type", "name"]
|
||||
__xmldefaultnamespace__ = xmlutils.AG_NS_URL
|
||||
|
||||
|
||||
def __init__(self, filePath=None, logicalFolder=None, type=None, name=None, getDocCallback=None):
|
||||
def __init__(self, parent=None, filePath=None, logicalFolder=None, type=None, name=None, getDocCallback=None):
|
||||
self._parentProj = parent
|
||||
self.filePath = filePath
|
||||
self.logicalFolder = logicalFolder
|
||||
self.type = type
|
||||
@@ -316,9 +300,8 @@ class ProjectFile(object):
|
||||
|
||||
|
||||
def _GetDocumentModel(self):
|
||||
# possible bug is if document gets replaced outside of IDE, where we'll return previous doc.
|
||||
# originally added a timestamp check but that increased the time again to 4x
|
||||
if self._docModelCallbackCacheReturnValue: # accelerator for caching document, got 4x speed up.
|
||||
if (self._docCallbackCacheReturnValue
|
||||
and (self._parentProj.cacheEnabled or self._docCallbackCacheReturnValue.IsDocumentModificationDateCorrect())):
|
||||
return self._docModelCallbackCacheReturnValue
|
||||
|
||||
if self._getDocCallback:
|
||||
@@ -332,16 +315,26 @@ class ProjectFile(object):
|
||||
|
||||
|
||||
def _GetDocument(self):
|
||||
# Hack, just return the IDE document wrapper that corresponds to the runtime document model
|
||||
# callers should have called ".document" before calling ".ideDocument"
|
||||
if self._docCallbackCacheReturnValue: # accelerator for caching document, got 4x speed up.
|
||||
# Return the IDE document wrapper that corresponds to the runtime document model
|
||||
if (self._docCallbackCacheReturnValue
|
||||
and (self._parentProj.cacheEnabled or self._docCallbackCacheReturnValue.IsDocumentModificationDateCorrect())):
|
||||
return self._docCallbackCacheReturnValue
|
||||
|
||||
if self._getDocCallback:
|
||||
self._docCallbackCacheReturnValue, self._docModelCallbackCacheReturnValue = self._getDocCallback(self.filePath)
|
||||
return self._docCallbackCacheReturnValue
|
||||
|
||||
return None
|
||||
|
||||
|
||||
ideDocument = property(_GetDocument)
|
||||
|
||||
|
||||
def ClearCache(self):
|
||||
self._docCallbackCacheReturnValue = None
|
||||
self._docModelCallbackCacheReturnValue = None
|
||||
|
||||
|
||||
def _typeEnumeration(self):
|
||||
return basedocmgr.FILE_TYPE_LIST
|
||||
|
||||
@@ -364,7 +357,7 @@ class ProjectFile(object):
|
||||
dir = None
|
||||
if self.filePath:
|
||||
dir = os.path.dirname(self.filePath)
|
||||
if dir.startswith(parentPath):
|
||||
if dir.startswith(parentPath + os.sep):
|
||||
dir = "." + dir[parentPathLen:] # convert to relative path
|
||||
if os.sep != '/':
|
||||
dir = dir.replace(os.sep, '/') # always save out with '/' as path separator for cross-platform compatibility.
|
||||
@@ -375,7 +368,7 @@ class ProjectFile(object):
|
||||
""" Used to convert path to relative path for saving (disk format) """
|
||||
parentPathLen = len(parentPath)
|
||||
|
||||
if self.filePath.startswith(parentPath):
|
||||
if self.filePath.startswith(parentPath + os.sep):
|
||||
self.filePath = "." + self.filePath[parentPathLen:] # convert to relative path
|
||||
if os.sep != '/':
|
||||
self.filePath = self.filePath.replace(os.sep, '/') # always save out with '/' as path separator for cross-platform compatibility.
|
||||
@@ -385,8 +378,8 @@ class ProjectFile(object):
|
||||
|
||||
def RelativeToAbsPath(self, parentPath):
|
||||
""" Used to convert path to absolute path (for any necessary disk access) """
|
||||
if self.filePath.startswith("."): # relative to project file
|
||||
self.filePath = os.path.normpath(os.path.join(parentPath, self.filePath))
|
||||
if self.filePath.startswith("./"): # relative to project file
|
||||
self.filePath = os.path.normpath(os.path.join(parentPath, self.filePath)) # also converts '/' to os.sep
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
@@ -400,6 +393,7 @@ class ProjectFile(object):
|
||||
if not self._doc:
|
||||
docMgr = wx.GetApp().GetDocumentManager()
|
||||
|
||||
try:
|
||||
doc = docMgr.CreateDocument(self.filePath, docMgr.GetFlags()|wx.lib.docview.DOC_SILENT|wx.lib.docview.DOC_OPEN_ONCE|wx.lib.docview.DOC_NO_VIEW)
|
||||
if (doc == None): # already open
|
||||
docs = docMgr.GetDocuments()
|
||||
@@ -408,12 +402,19 @@ class ProjectFile(object):
|
||||
doc = d
|
||||
break
|
||||
self._doc = doc
|
||||
except Exception,e:
|
||||
aglogging.reportException(e, stacktrace=True)
|
||||
|
||||
return self._doc
|
||||
|
||||
|
||||
def _GetLocalServiceProcessName(self):
|
||||
# HACK: temporary solution to getting process name from wsdlag file.
|
||||
return self._GetDoc().GetModel().processName
|
||||
doc = self._GetDoc()
|
||||
if doc:
|
||||
return doc.GetModel().processName
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
processName = property(_GetLocalServiceProcessName)
|
||||
@@ -458,6 +459,9 @@ class ProjectFile(object):
|
||||
localServiceClassName = property(_GetLocalServiceClassName, _SetLocalServiceClassName)
|
||||
|
||||
|
||||
def getServiceParameter(self, message, part):
|
||||
return self._GetDoc().GetModel().getServiceParameter(message, part)
|
||||
|
||||
|
||||
# only activate this code if we programatically need to access these values
|
||||
## def _GetRssServiceBaseURL(self):
|
||||
@@ -484,7 +488,10 @@ class ProjectFile(object):
|
||||
|
||||
def _GetServiceRefServiceType(self):
|
||||
# HACK: temporary solution to getting service type from wsdlag file.
|
||||
model = self._GetDoc().GetModel()
|
||||
doc = self._GetDoc()
|
||||
if not doc:
|
||||
return None
|
||||
model = doc.GetModel()
|
||||
if hasattr(model, 'serviceType'):
|
||||
return model.serviceType
|
||||
else:
|
||||
@@ -501,18 +508,20 @@ class ProjectFile(object):
|
||||
|
||||
def getExternalPackage(self):
|
||||
# HACK: temporary solution to getting custom code filename from wsdlag file.
|
||||
import activegrid.server.deployment as deploymentlib
|
||||
import activegrid.model.projectmodel as projectmodel
|
||||
import wx
|
||||
import ProjectEditor
|
||||
|
||||
appInfo = self._GetDoc().GetAppInfo()
|
||||
|
||||
if appInfo.language == None:
|
||||
language = deploymentlib.LANGUAGE_DEFAULT
|
||||
language = wx.ConfigBase_Get().Read(ProjectEditor.APP_LAST_LANGUAGE, projectmodel.LANGUAGE_DEFAULT)
|
||||
else:
|
||||
language = appInfo.language
|
||||
|
||||
if language == deploymentlib.LANGUAGE_PYTHON:
|
||||
if language == projectmodel.LANGUAGE_PYTHON:
|
||||
suffix = ".py"
|
||||
elif language == deploymentlib.LANGUAGE_PHP:
|
||||
elif language == projectmodel.LANGUAGE_PHP:
|
||||
suffix = ".php"
|
||||
pyFilename = self.name + suffix
|
||||
return self._GetDoc().GetAppDocMgr().fullPath(pyFilename)
|
||||
@@ -543,7 +552,63 @@ class Project_10:
|
||||
def upgradeVersion(self):
|
||||
currModel = Project()
|
||||
for file in self._files:
|
||||
currModel._files.append(ProjectFile(file))
|
||||
currModel._files.append(ProjectFile(currModel, file))
|
||||
return currModel
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# XML Marshalling Methods
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
if ACTIVEGRID_BASE_IDE:
|
||||
KNOWNTYPES = {"ag:project" : Project, "ag:file" : ProjectFile}
|
||||
else:
|
||||
KNOWNTYPES = {"ag:project" : Project, "ag:file" : ProjectFile,
|
||||
"ag:appInfo" : AppInfo.AppInfo,
|
||||
"ag:deploymentDataSource" : AppInfo.DeploymentDataSource,
|
||||
"ag:dataSourceBinding" : AppInfo.DataSourceBinding}
|
||||
|
||||
def load(fileObject):
|
||||
version = xmlutils.getAgVersion(fileObject.name)
|
||||
# most current versions on top
|
||||
if version == PROJECT_VERSION_050826:
|
||||
fileObject.seek(0)
|
||||
project = xmlutils.load(fileObject.name, knownTypes=KNOWNTYPES, knownNamespaces=xmlutils.KNOWN_NAMESPACES, createGenerics=True)
|
||||
elif version == PROJECT_VERSION_050730:
|
||||
fileObject.seek(0)
|
||||
project = xmlutils.load(fileObject.name, knownTypes={"project" : Project_10}, createGenerics=True)
|
||||
project = project.upgradeVersion()
|
||||
else:
|
||||
# assume it is old version without version number
|
||||
fileObject.seek(0)
|
||||
project = xmlutils.load(fileObject.name, knownTypes={"project" : Project_10}, createGenerics=True)
|
||||
if project:
|
||||
project = project.upgradeVersion()
|
||||
else:
|
||||
print "Project, unknown version:", version
|
||||
return None
|
||||
|
||||
if project:
|
||||
project._projectDir = os.path.dirname(fileObject.name)
|
||||
project.RelativeToAbsPath()
|
||||
|
||||
return project
|
||||
|
||||
|
||||
def save(fileObject, project, productionDeployment=False):
|
||||
if not project._projectDir:
|
||||
project._projectDir = os.path.dirname(fileObject.name)
|
||||
project.AbsToRelativePath() # temporarily change it to relative paths for saving
|
||||
savedHomeDir = project.homeDir
|
||||
if productionDeployment:
|
||||
# for deployments, we don't want an abs path in homeDir since that
|
||||
# would tie the app to the current filesystem. So unset it.
|
||||
project.homeDir = None
|
||||
|
||||
xmlutils.save(fileObject.name, project, prettyPrint=True, knownTypes=KNOWNTYPES, knownNamespaces=xmlutils.KNOWN_NAMESPACES)
|
||||
|
||||
if productionDeployment:
|
||||
project.homeDir = savedHomeDir
|
||||
|
||||
project.RelativeToAbsPath() # swap it back to absolute path
|
||||
|
||||
|
@@ -19,6 +19,7 @@ import logging.config
|
||||
from activegrid.util.lang import *
|
||||
import activegrid.util.objutils as objutils
|
||||
import activegrid.util.sysutils as sysutils
|
||||
import activegrid.util.appdirs as appdirs
|
||||
|
||||
LEVEL_FATAL = logging.FATAL
|
||||
LEVEL_ERROR = logging.ERROR
|
||||
@@ -27,16 +28,20 @@ LEVEL_INFO = logging.INFO
|
||||
LEVEL_DEBUG = logging.DEBUG
|
||||
|
||||
EXCEPTION_INFO = 'exceptionInfo'
|
||||
loggingInitialized = False
|
||||
|
||||
LOG_MODE_IDE = 1
|
||||
LOG_MODE_TESTRUN = 2
|
||||
LOG_MODE_RUN = 3
|
||||
def initLogging(mode):
|
||||
def initLogging(mode, force=False):
|
||||
global ag_debugLogger, loggingInitialized
|
||||
if (force or not loggingInitialized):
|
||||
loggingInitialized = True
|
||||
configFile = None
|
||||
if (mode == LOG_MODE_IDE):
|
||||
configFile = os.getenv("AG_LOGCONFIG_IDE")
|
||||
elif (mode == LOG_MODE_TESTRUN):
|
||||
configFile = os.getenv("AG_LOGCONFIG_TESTRUN")
|
||||
configFile = os.getenv("AG_LOGCONFIG_PYTESTRUN")
|
||||
else:
|
||||
configFile = os.getenv("AG_LOGCONFIG_RUN")
|
||||
if ((configFile == None) or not os.path.exists(configFile)):
|
||||
@@ -46,17 +51,22 @@ def initLogging(mode):
|
||||
configFile = "TestRunLog"
|
||||
else:
|
||||
configFile = "RunLog"
|
||||
configFile = sysutils.mainModuleDir + "/py" + configFile + ".ini"
|
||||
configFile = os.path.join(appdirs.getSystemDir(appdirs.AG_LOGS_DIR), "py" + configFile + ".ini")
|
||||
if (os.path.exists(configFile)):
|
||||
print "Using logging configuration file: %s" % configFile
|
||||
fileConfig(configFile)
|
||||
else:
|
||||
print "*** Cannot find logging configuration file (%s) -- setting default logging level to WARN ***" % (configFile)
|
||||
defaultStream = sys.stderr
|
||||
if (mode == LOG_MODE_RUN):
|
||||
defaultStream = sys.stdout
|
||||
handler = logging.StreamHandler(defaultStream)
|
||||
handler.setLevel(logging.INFO)
|
||||
handler.setLevel(logging.DEBUG)
|
||||
handler.setFormatter(logging.Formatter("%(asctime)s %(name)s %(levelname)s: %(message)s"))
|
||||
logging.getLogger().addHandler(handler)
|
||||
logging.getLogger().setLevel(logging.WARN)
|
||||
ag_debugLogger = logging.getLogger("activegrid.debug")
|
||||
ag_debugLogger.setLevel(logging.DEBUG)
|
||||
return configFile
|
||||
|
||||
ag_debugLogger = logging.getLogger("activegrid.debug")
|
||||
@@ -181,17 +191,14 @@ def addExceptionInfo(e, key, value):
|
||||
if not e.exceptionInfo.has_key(key): # Never overwrite exception info since we assume earlier info is more specific
|
||||
e.exceptionInfo[key] = value
|
||||
|
||||
def reportException(out=None, stacktrace=False, diffable=False, exception=None):
|
||||
def reportException(exception, out=None, stacktrace=False, diffable=False):
|
||||
exstr = exceptionToString(exception, stacktrace, diffable)
|
||||
if (out == None):
|
||||
print exstr
|
||||
else:
|
||||
print >> out, exstr
|
||||
|
||||
def exceptionToString(exception=None, stacktrace=False, diffable=False):
|
||||
if (exception == None):
|
||||
extype, val, t = sys.exc_info()
|
||||
else:
|
||||
def exceptionToString(exception, stacktrace=False, diffable=False):
|
||||
extype = objutils.typeToString(exception)
|
||||
val = exception
|
||||
if (stacktrace):
|
||||
|
@@ -2,7 +2,7 @@
|
||||
# Name: appdirs.py
|
||||
# Purpose: Utilities for retrieving special application dirs
|
||||
#
|
||||
# Author: Kevin Ollivier
|
||||
# Author: Kevin Ollivier, Jeff Norton
|
||||
#
|
||||
# Created: 8/27/05
|
||||
# CVS-ID: $Id$
|
||||
@@ -10,50 +10,117 @@
|
||||
# License: wxWindows License
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
# NOTE: This was made a separate file because it depends upon the
|
||||
# wx.StandardPaths module, and thus, on wxWidgets, unlike other
|
||||
# utils modules. I wanted to ensure this module is never loaded
|
||||
# from the web server, etc.
|
||||
|
||||
from activegrid.util.lang import *
|
||||
import sys
|
||||
import os
|
||||
import string
|
||||
import wx
|
||||
import activegrid.util.sysutils as sysutils
|
||||
|
||||
def isWindows():
|
||||
return os.name == 'nt'
|
||||
|
||||
def _generateDocumentsDir():
|
||||
def _getSystemDir(kind):
|
||||
if (kind == AG_LOGS_DIR):
|
||||
return os.path.join(getSystemDir(AG_SYSTEM_DIR) , "logs")
|
||||
elif (kind == AG_DEMOS_DIR):
|
||||
return os.path.join(getSystemDir(AG_SYSTEM_DIR), "demos")
|
||||
else:
|
||||
path = ""
|
||||
if sys.platform == "win32":
|
||||
if (sysutils.isServer()):
|
||||
path = os.getenv("ACTIVEGRID_SERVER_HOME")
|
||||
if ((path is None) or (len(path) < 1)):
|
||||
path = sysutils.mainModuleDir
|
||||
else:
|
||||
path = os.getenv("AG_DOCUMENTS_DIR")
|
||||
if ((path is None) or (len(path) < 1)):
|
||||
if sysutils.isWindows():
|
||||
ifDefPy()
|
||||
try:
|
||||
from win32com.shell import shell, shellcon
|
||||
path = shell.SHGetFolderPath(0, shellcon.CSIDL_PERSONAL, None, 0)
|
||||
elif sys.platform == "darwin":
|
||||
import macfs, MACFS
|
||||
except:
|
||||
pass
|
||||
endIfDef()
|
||||
if ((path is None) or (len(path) < 1)):
|
||||
homedrive = asString(os.getenv("HOMEDRIVE"))
|
||||
homepath = os.getenv("HOMEPATH")
|
||||
## if ((homedrive is not None) and (len(homedrive) > 0) and (homepath is not None) and (len(homepath) > 0)):
|
||||
path = os.path.join(homedrive, homepath, "MYDOCU~1")
|
||||
else:
|
||||
ifDefPy()
|
||||
if sys.platform == "darwin":
|
||||
try:
|
||||
import macfs
|
||||
import MACFS
|
||||
fsspec_disk, fsspec_desktop = macfs.FindFolder(MACFS.kOnSystemDisk, MACFS.kDocumentsFolderType, 0)
|
||||
path = macfs.FSSpec((fsspec_disk, fsspec_desktop, '')).as_pathname()
|
||||
except:
|
||||
pass
|
||||
endIfDef()
|
||||
|
||||
if path == "":
|
||||
ifDefPy()
|
||||
if ((path is None) or (len(path) < 1)):
|
||||
path = os.path.expanduser("~")
|
||||
endIfDef()
|
||||
if ((path is None) or (len(path) < 1)):
|
||||
path = "/"
|
||||
path = os.path.join(path, "ActiveGrid")
|
||||
|
||||
return path
|
||||
|
||||
documents_folder = _generateDocumentsDir()
|
||||
|
||||
AG_SYSTEM_DIR = 0
|
||||
AG_LOGS_DIR = 1
|
||||
AG_DEMOS_DIR = 2
|
||||
|
||||
__systemDir = None
|
||||
__logsDir = None
|
||||
__demosDir = None
|
||||
|
||||
def getSystemDir(kind=0):
|
||||
if (kind == AG_SYSTEM_DIR):
|
||||
global __systemDir
|
||||
if (__systemDir is None):
|
||||
__systemDir = _getSystemDir(kind)
|
||||
return __systemDir
|
||||
elif (kind == AG_LOGS_DIR):
|
||||
global __logsDir
|
||||
if (__logsDir is None):
|
||||
__logsDir = _getSystemDir(kind)
|
||||
return __logsDir
|
||||
elif (kind == AG_DEMOS_DIR):
|
||||
global __demosDir
|
||||
if (__demosDir is None):
|
||||
__demosDir = _getSystemDir(kind)
|
||||
return __demosDir
|
||||
return None
|
||||
|
||||
|
||||
# NOTE: We don't set this at startup because wxStandardPaths needs a running
|
||||
# application object. This makes sure the wxApp will always be created when
|
||||
# we get the folder.
|
||||
ifDefPy()
|
||||
def getAppDataFolder():
|
||||
try:
|
||||
# NOTE: cannot import wx from the server
|
||||
import wx
|
||||
# wxStandardPaths requires a running app
|
||||
if wx.GetApp() and wx.Platform != "__WXGTK__":
|
||||
data_folder = wx.StandardPaths.Get().GetUserDataDir()
|
||||
if not os.path.exists(data_folder):
|
||||
os.mkdir(data_folder)
|
||||
return data_folder
|
||||
else:
|
||||
except:
|
||||
pass
|
||||
# wxBug: on *nix, it wants to point to ~/.appname, but
|
||||
# so does wxConfig... For now, redirect this to ~/.appbuilder
|
||||
# when this is fixed, we'll migrate settings to the correct place
|
||||
return os.path.join(os.path.expanduser("~"), ".appbuilder")
|
||||
endIfDef()
|
||||
|
||||
return ""
|
||||
ifDefPy()
|
||||
def createSystemDirs():
|
||||
if (not os.path.exists(getSystemDir())):
|
||||
os.mkdir(getSystemDir())
|
||||
if (not os.path.exists(getSystemDir(AG_LOGS_DIR))):
|
||||
os.mkdir(getSystemDir(AG_LOGS_DIR))
|
||||
if (not os.path.exists(getSystemDir(AG_DEMOS_DIR))):
|
||||
os.mkdir(getSystemDir(AG_DEMOS_DIR))
|
||||
endIfDef()
|
||||
|
118
wxPython/samples/ide/activegrid/util/datetimeparser.py
Normal file
118
wxPython/samples/ide/activegrid/util/datetimeparser.py
Normal file
@@ -0,0 +1,118 @@
|
||||
#----------------------------------------------------------------------------
|
||||
# Name: datetimeparser.py
|
||||
#
|
||||
# Purpose: - Instantiate datetime.datetime/date instance from a string
|
||||
# date representation.
|
||||
# Uses dateutil from http://labix.org/python-dateutil.
|
||||
#
|
||||
# - Creates string representation of datetime/date instance.
|
||||
#
|
||||
#
|
||||
# Author: Simon Toens
|
||||
#
|
||||
# Created: 28-Feb-06
|
||||
# CVS-ID:
|
||||
# Copyright: (c) 2005 ActiveGrid, Inc.
|
||||
# License: wxWindows License
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
import datetime
|
||||
|
||||
try:
|
||||
import dateutil.parser
|
||||
DATEUTIL_INSTALLED = True
|
||||
except ImportError:
|
||||
DATEUTIL_INSTALLED = False
|
||||
|
||||
ISO_8601_DATE_FORMAT = "%Y-%m-%d"
|
||||
ISO_8601_TIME_FORMAT = "%H:%M:%S"
|
||||
ISO_8601_DATETIME_FORMAT = "%s %s" %(ISO_8601_DATE_FORMAT,
|
||||
ISO_8601_TIME_FORMAT)
|
||||
|
||||
DEFAULT_DATETIME = datetime.datetime(1, 1, 1, 0, 0, 0, 0)
|
||||
|
||||
|
||||
def format(dateobj, formatstr=None):
|
||||
if (formatstr != None and _isDateTimeObject(dateobj)):
|
||||
return dateobj.strftime(str(formatstr))
|
||||
return str(dateobj)
|
||||
|
||||
|
||||
def parse(datestr, formatstr=None, asdate=False, astime=False):
|
||||
"""Instantiates and returns a datetime instance from the datestr datetime
|
||||
representation.
|
||||
|
||||
Optionally, a format string may be used. The format is only loosely
|
||||
interpreted, its only purpose beeing to determine if the year is first
|
||||
or last in datestr, and whether the day is in front or follows the
|
||||
month. If no formatstr is passed in, dateutil tries its best to parse
|
||||
the datestr. The default date format is YYYY-mm-dd HH:SS.
|
||||
|
||||
If asdate is True, returns a date instance instead of a datetime
|
||||
instance, if astime is True, returns a time instance instead of a
|
||||
datetime instance."""
|
||||
|
||||
|
||||
dayfirst, yearfirst = _getDayFirstAndYearFirst(formatstr)
|
||||
|
||||
rtn = None
|
||||
|
||||
try:
|
||||
if DATEUTIL_INSTALLED:
|
||||
rtn = dateutil.parser.parse(str(datestr), fuzzy=True,
|
||||
dayfirst=dayfirst, yearfirst=yearfirst,
|
||||
default=DEFAULT_DATETIME)
|
||||
else:
|
||||
rtn = DEFAULT_DATETIME
|
||||
except:
|
||||
rtn = DEFAULT_DATETIME
|
||||
|
||||
if (asdate and isinstance(rtn, datetime.datetime)):
|
||||
rtn = datetime.date(rtn.year, rtn.month, rtn.day)
|
||||
elif (astime and isinstance(rtn, datetime.datetime)):
|
||||
rtn = datetime.time(rtn.hour, rtn.minute, rtn.second, rtn.microsecond)
|
||||
|
||||
return rtn
|
||||
|
||||
|
||||
def _isDateTimeObject(obj):
|
||||
return (isinstance(obj, datetime.datetime) or
|
||||
isinstance(obj, datetime.date) or
|
||||
isinstance(obj, datetime.time))
|
||||
|
||||
|
||||
def _getDayFirstAndYearFirst(formatstr):
|
||||
dayFirst = False
|
||||
yearFirst = False
|
||||
|
||||
gotYear = False
|
||||
gotMonth = False
|
||||
gotDay = False
|
||||
|
||||
if (formatstr == None):
|
||||
formatstr = ""
|
||||
|
||||
for c in formatstr:
|
||||
if (c.lower() == "y"):
|
||||
if (gotYear):
|
||||
continue
|
||||
if (not gotDay and not gotMonth):
|
||||
yearFirst = True
|
||||
gotYear = True
|
||||
|
||||
elif (c.lower() == "m"):
|
||||
if (gotMonth):
|
||||
continue
|
||||
if (not gotDay):
|
||||
dayFirst = False
|
||||
gotMonth = True
|
||||
|
||||
elif (c.lower() == "d"):
|
||||
if (gotDay):
|
||||
continue
|
||||
if (not gotMonth):
|
||||
dayFirst = True
|
||||
gotDay = True
|
||||
|
||||
|
||||
return dayFirst, yearFirst
|
@@ -19,6 +19,7 @@ import zipfile
|
||||
|
||||
import activegrid.util.aglogging as aglogging
|
||||
import activegrid.util.sysutils as sysutils
|
||||
import activegrid.util.utillang as utillang
|
||||
from activegrid.util.lang import *
|
||||
|
||||
global fileutilsLogger
|
||||
@@ -31,6 +32,65 @@ fileutilsLogger = logging.getLogger("activegrid.util.fileutils")
|
||||
aglogging.setLevelFatal(fileutilsLogger)
|
||||
#logging.getLogger().addHandler(logging.StreamHandler(sys.stderr))
|
||||
|
||||
def addRef(varname):
|
||||
return "${%s}" % varname
|
||||
|
||||
AG_SYSTEM_VAR_NAMES = [] # all AG System vars, with ${} syntax
|
||||
|
||||
AG_SYSTEM_VAR = "AG_SYSTEM"
|
||||
AG_SYSTEM_VAR_REF = addRef(AG_SYSTEM_VAR)
|
||||
AG_SYSTEM_VAR_NAMES.append(AG_SYSTEM_VAR_REF)
|
||||
|
||||
AG_SYSTEM_STATIC_VAR = "AG_SYSTEM_STATIC"
|
||||
AG_SYSTEM_STATIC_VAR_REF = addRef(AG_SYSTEM_STATIC_VAR)
|
||||
AG_SYSTEM_VAR_NAMES.append(AG_SYSTEM_STATIC_VAR_REF)
|
||||
|
||||
AG_APP_VAR = "AG_APP"
|
||||
AG_APP_STATIC_VAR = "AG_APP_STATIC"
|
||||
|
||||
# _initAGSystemVars needs to be called to initialize the following two
|
||||
# containers:
|
||||
EXPANDED_AG_SYSTEM_VARS = {} # ${varname} -> value (path)
|
||||
# ${varname}, ordered from longest to shortest path value
|
||||
AG_SYSTEM_VARS_LENGTH_ORDER = []
|
||||
|
||||
def _initAGSystemVars():
|
||||
if (len(EXPANDED_AG_SYSTEM_VARS) > 0):
|
||||
return
|
||||
|
||||
for v in AG_SYSTEM_VAR_NAMES:
|
||||
EXPANDED_AG_SYSTEM_VARS[v] = os.path.abspath(expandVars(v))
|
||||
AG_SYSTEM_VARS_LENGTH_ORDER.append(v)
|
||||
|
||||
AG_SYSTEM_VARS_LENGTH_ORDER.sort(_sortByValLength)
|
||||
|
||||
|
||||
def parameterizePathWithAGSystemVar(inpath):
|
||||
"""Returns parameterized path if path starts with a known AG directory. Otherwise returns path as it was passed in."""
|
||||
_initAGSystemVars()
|
||||
path = inpath
|
||||
if not sysutils.isWindows():
|
||||
# ensure we have forward slashes
|
||||
path = path.replace("\\", "/")
|
||||
|
||||
path = os.path.abspath(path)
|
||||
|
||||
for varname in AG_SYSTEM_VARS_LENGTH_ORDER:
|
||||
varval = EXPANDED_AG_SYSTEM_VARS[varname]
|
||||
if path.startswith(varval):
|
||||
return path.replace(varval, varname)
|
||||
|
||||
return inpath
|
||||
|
||||
def startsWithAgSystemVar(path):
|
||||
"""Returns True if path starts with a known AG system env var, False otherwise."""
|
||||
for varname in AG_SYSTEM_VAR_NAMES:
|
||||
if path.startswith(varname):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _sortByValLength(v1, v2):
|
||||
return len(EXPANDED_AG_SYSTEM_VARS[v2]) - len(EXPANDED_AG_SYSTEM_VARS[v1])
|
||||
|
||||
def makeDirsForFile(filename):
|
||||
d = os.path.dirname(filename)
|
||||
@@ -44,7 +104,7 @@ def createFile(filename, mode='w'):
|
||||
f = file(filename, mode)
|
||||
return f
|
||||
|
||||
def compareFiles(file1, file2):
|
||||
def compareFiles(file1, file2, ignore=None):
|
||||
## result = filecmp.cmp(file1, file2)
|
||||
## if result:
|
||||
## return 0
|
||||
@@ -62,6 +122,9 @@ def compareFiles(file1, file2):
|
||||
elif (len(line2) == 0):
|
||||
return -1
|
||||
elif (line1 != line2):
|
||||
if (ignore != None):
|
||||
if (line1.startswith(ignore) or line2.startswith(ignore)):
|
||||
continue
|
||||
line1 = line1.replace(" ", "")
|
||||
line2 = line2.replace(" ", "")
|
||||
if (line1 != line2):
|
||||
@@ -81,7 +144,10 @@ def compareFiles(file1, file2):
|
||||
continue
|
||||
return -1
|
||||
|
||||
def expandVars(value):
|
||||
def expandKnownAGVars(value):
|
||||
return expandVars(value, includeEnv=False)
|
||||
|
||||
def expandVars(value, includeEnv=True):
|
||||
"""Syntax: ${myvar,default="default value"}"""
|
||||
import activegrid.runtime as runtime
|
||||
sx = value.find("${")
|
||||
@@ -97,16 +163,19 @@ def expandVars(value):
|
||||
defaultValue = value[defsx+10:endx-1]
|
||||
if (defaultValue == None):
|
||||
varname = value[sx+2:endx]
|
||||
if (varname == "AG_SYSTEM"):
|
||||
if (varname == AG_SYSTEM_VAR):
|
||||
varval = runtime.appInfo.getSystemDir()
|
||||
elif (varname == "AG_SYSTEM_STATIC"):
|
||||
elif (varname == AG_SYSTEM_STATIC_VAR):
|
||||
varval = runtime.appInfo.getSystemStaticDir()
|
||||
elif (varname == "AG_APP"):
|
||||
elif (varname == AG_APP_VAR):
|
||||
varval = runtime.appInfo.getAppDir()
|
||||
elif (varname == "AG_APP_STATIC"):
|
||||
elif (varname == AG_APP_STATIC_VAR):
|
||||
varval = runtime.appInfo.getAppStaticDir()
|
||||
else:
|
||||
if (includeEnv):
|
||||
varval = os.getenv(varname)
|
||||
else:
|
||||
varval = None
|
||||
if ((varval == None) and (defaultValue != None)):
|
||||
varval = defaultValue
|
||||
if (varval == None):
|
||||
@@ -148,22 +217,21 @@ def convertSourcePath(path, to, otherdir=None):
|
||||
return otherdir + path[ix+7:]
|
||||
|
||||
|
||||
def visit(directory, files, extension):
|
||||
def visit(directory, files, extension, maxLevel=None, level=1):
|
||||
testdirs = os.listdir(directory)
|
||||
for thing in testdirs:
|
||||
fullpath = os.path.join(directory, thing)
|
||||
if (os.path.isdir(fullpath)):
|
||||
visit(fullpath, files, extension)
|
||||
if (os.path.isdir(fullpath) and (maxLevel == None or level < maxLevel)):
|
||||
visit(fullpath, files, extension, maxLevel, level+1)
|
||||
elif thing.endswith(extension):
|
||||
fullname = os.path.normpath(os.path.join(directory, thing))
|
||||
if not fullname in files:
|
||||
files.append(fullname)
|
||||
|
||||
def listFilesByExtensionInPath(path=[], extension='.lyt'):
|
||||
#Collect input and output arguments into one bunch
|
||||
def listFilesByExtensionInPath(path=[], extension='.lyt', maxLevel=None):
|
||||
retval = []
|
||||
for directory in path:
|
||||
visit(directory, retval, extension)
|
||||
visit(directory, retval, extension, maxLevel)
|
||||
return retval
|
||||
|
||||
def getFileLastModificationTime(fileName):
|
||||
@@ -311,6 +379,21 @@ def remove(file):
|
||||
shutil.rmtree(file)
|
||||
endIfDef()
|
||||
|
||||
def getUserTempDir():
|
||||
systemTempDir = utillang.getSystemTempDir()
|
||||
userName = sysutils.getUserName()
|
||||
userNameNoSpace = userName.replace('_','__').replace(' ','_')
|
||||
userTempDir = systemTempDir + os.sep + "activegrid_" + userNameNoSpace
|
||||
return userTempDir
|
||||
|
||||
def createUserTempDir():
|
||||
userTempDir = getUserTempDir()
|
||||
if not os.path.exists(userTempDir):
|
||||
os.makedirs(userTempDir)
|
||||
os.chmod(userTempDir, 0700)
|
||||
|
||||
createUserTempDir()
|
||||
|
||||
ifDefPy()
|
||||
import warnings
|
||||
warnings.filterwarnings("ignore", message="tmpnam is a potential security risk to your program")
|
||||
|
@@ -16,7 +16,8 @@ import sys
|
||||
import os
|
||||
import __builtin__
|
||||
import types
|
||||
import xml.sax.saxutils as saxutils
|
||||
import activegrid.util.utillang as utillang
|
||||
import activegrid.util.datetimeparser as datetimeparser
|
||||
from types import *
|
||||
from activegrid.util.lang import *
|
||||
|
||||
@@ -65,6 +66,18 @@ def setStaticAttr(obj, attr, value):
|
||||
classDesc = obj.__class__
|
||||
setattr(classDesc, attr, value)
|
||||
|
||||
def hasAttrFast(obj, name):
|
||||
if hasRawAttr(obj, name):
|
||||
return True
|
||||
if hasattr(obj, '_complexType'):
|
||||
complexType=obj._complexType
|
||||
element=complexType.findElement(name)
|
||||
if element:
|
||||
return True
|
||||
if hasattr(obj, name):
|
||||
return True
|
||||
return False
|
||||
|
||||
def moduleForName(moduleName):
|
||||
module = None
|
||||
pathList = moduleName.split('.')
|
||||
@@ -114,15 +127,22 @@ def newInstance(className, objargs=None):
|
||||
if ((len(objargs) < 1) or (objargs[0].lower() == "false") or (not objargs[0])):
|
||||
return False
|
||||
return True
|
||||
if className == "str" or className == "unicode": # don"t strip: blanks are significant
|
||||
if className == "str" or className == "unicode": # don't strip: blanks are significant
|
||||
if len(objargs) > 0:
|
||||
try:
|
||||
return saxutils.unescape(objargs[0]).encode()
|
||||
return utillang.unescape(objargs[0]).encode()
|
||||
except:
|
||||
return "?"
|
||||
else:
|
||||
return ""
|
||||
|
||||
if className == "date":
|
||||
return datetimeparser.parse(objargs[0], asdate=True)
|
||||
if className == "datetime":
|
||||
return datetimeparser.parse(objargs[0])
|
||||
if className == "time":
|
||||
return datetimeparser.parse(objargs[0], astime=True)
|
||||
|
||||
classtype = classForName(className)
|
||||
if (classtype == None):
|
||||
raise Exception("Could not find class %s" % className)
|
||||
@@ -135,23 +155,35 @@ def newInstance(className, objargs=None):
|
||||
def getClassProperty(classType, propertyName):
|
||||
return getattr(classType, propertyName)
|
||||
|
||||
def toDiffableRepr(value, exclude=None):
|
||||
def toDiffableRepr(value, maxLevel=None):
|
||||
if (value == None):
|
||||
return "None"
|
||||
if (maxLevel == None):
|
||||
maxLevel = 8
|
||||
maxLevel -= 1
|
||||
if (maxLevel < 0):
|
||||
return typeToString(value, PRINT_OBJ_DIFFABLE)
|
||||
## if ((exclude != None) and not isinstance(value, (basestring, int))):
|
||||
## for v in exclude:
|
||||
## if (v is value):
|
||||
## return "<recursive reference>"
|
||||
## exclude.append(value)
|
||||
## elif (isinstance(value, ObjectType) and hasattr(value, "__dict__")):
|
||||
## if (exclude == None):
|
||||
## exclude = []
|
||||
## s = "%s(%s)" % (type(value), toDiffableString(value.__dict__, exclude))
|
||||
elif (not isinstance(value, (BooleanType, ClassType, ComplexType, DictType, DictionaryType,
|
||||
if (not isinstance(value, (BooleanType, ClassType, ComplexType, DictType, DictionaryType,
|
||||
FloatType, IntType, ListType, LongType, StringType, TupleType,
|
||||
UnicodeType, BufferType, BuiltinFunctionType, BuiltinMethodType,
|
||||
CodeType, FrameType, FunctionType, GeneratorType, InstanceType,
|
||||
LambdaType, MethodType, ModuleType, SliceType, TracebackType,
|
||||
TypeType, XRangeType))):
|
||||
if (hasattr(value, "__str__")):
|
||||
if (hasattr(value, "_toDiffableString")):
|
||||
s = value._toDiffableString(maxLevel)
|
||||
elif (hasattr(value, "__str__")):
|
||||
s = str(value)
|
||||
elif (hasattr(value, "__dict__")):
|
||||
s = "%s(%s)" % (type(value), toDiffableString(value.__dict__, exclude))
|
||||
s = "%s(%s)" % (type(value), toDiffableString(value.__dict__, maxLevel))
|
||||
else:
|
||||
s = str(type(value))
|
||||
ix2 = s.find(" object at 0x")
|
||||
@@ -173,33 +205,31 @@ def toDiffableRepr(value, exclude=None):
|
||||
else:
|
||||
items.append("'%s'" % v)
|
||||
else:
|
||||
items.append(toDiffableString(v, exclude))
|
||||
items.append(toDiffableString(v, maxLevel))
|
||||
s = "[" + ", ".join(items) + "]"
|
||||
elif (isinstance(value, dict)):
|
||||
if (exclude == None):
|
||||
exclude = []
|
||||
items = []
|
||||
for key, val in value.iteritems():
|
||||
if (isinstance(val, UnicodeType)):
|
||||
items.append("'%s': u'%s'" % (key, toDiffableString(val, exclude)))
|
||||
items.append("'%s': u'%s'" % (key, toDiffableString(val, maxLevel)))
|
||||
elif (isinstance(val, basestring)):
|
||||
items.append("'%s': '%s'" % (key, toDiffableString(val, exclude)))
|
||||
items.append("'%s': '%s'" % (key, toDiffableString(val, maxLevel)))
|
||||
else:
|
||||
items.append("'%s': %s" % (key, toDiffableString(val, exclude)))
|
||||
items.append("'%s': %s" % (key, toDiffableString(val, maxLevel)))
|
||||
s = "{" + ", ".join(items) + "}"
|
||||
else:
|
||||
s = str(value)
|
||||
return s
|
||||
|
||||
def toDiffableString(value, exclude=None):
|
||||
if (value == None):
|
||||
return "None"
|
||||
if ((exclude != None) and not isinstance(value, (basestring, int))):
|
||||
for v in exclude:
|
||||
if (v is value):
|
||||
return "<recursive reference>"
|
||||
exclude.append(value)
|
||||
s = toDiffableRepr(value)
|
||||
def toDiffableString(value, maxLevel=None):
|
||||
## if (value == None):
|
||||
## return "None"
|
||||
## if ((exclude != None) and not isinstance(value, (basestring, int))):
|
||||
## for v in exclude:
|
||||
## if (v is value):
|
||||
## return "<recursive reference>"
|
||||
## exclude.append(value)
|
||||
s = toDiffableRepr(value, maxLevel)
|
||||
ds = ""
|
||||
i = s.find(" at 0x")
|
||||
start = 0
|
||||
|
380
wxPython/samples/ide/activegrid/util/parser.py
Normal file
380
wxPython/samples/ide/activegrid/util/parser.py
Normal file
@@ -0,0 +1,380 @@
|
||||
#----------------------------------------------------------------------------
|
||||
# Name: parser.py
|
||||
# Purpose: parsing utilities
|
||||
#
|
||||
# Author: Jeff Norton
|
||||
#
|
||||
# Created: 8/9/05
|
||||
# CVS-ID: $Id$
|
||||
# Copyright: (c) 2004-2005 ActiveGrid, Inc.
|
||||
# License: wxWindows License
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
import re
|
||||
from activegrid.util.lang import *
|
||||
ifDefPy()
|
||||
import string
|
||||
import array
|
||||
endIfDef()
|
||||
|
||||
XPATH_ROOT_VAR = '__rootObj__'
|
||||
GETOBJECTPARTNAMES = ["primaryRef", "ref", "orderings", "limit"]
|
||||
|
||||
class Tokenizer(object):
|
||||
|
||||
TOKEN_IDENT = 1
|
||||
TOKEN_STRING = 2
|
||||
TOKEN_OP = 3
|
||||
TOKEN_WS = 4
|
||||
## TOKEN_PLACEHOLDER = 5
|
||||
|
||||
def __init__(self, text, identStart=None, tokenSep=None, ignoreWhitespace=True):
|
||||
"""
|
||||
Turn a string into individual tokens. Three types of tokens are recognized:
|
||||
TOKEN_IDENT: identifiers (those that start with the identStart pattern)
|
||||
TOKEN_STRING: quoted string
|
||||
TOKEN_OP: everything else
|
||||
Tokens are separated by white space or the tokenSep pattern.
|
||||
Constructor parameters:
|
||||
text: The string to tokenize
|
||||
identStart: A regular expression describing characters which start an identifier
|
||||
The default expression accepts letters, "_", and "/".
|
||||
tokenSep: A regular expression describing the characters which end a token
|
||||
(in addition to whitespace). The default expression accepts
|
||||
anything except alpha-numerics, "_", "/", and ":".
|
||||
Usage:
|
||||
Invoke getNextToken (or next) to get the next token. The instance variables
|
||||
token, and tokenVal will be populated with the current token type (TOKEN_IDENT,
|
||||
TOKEN_STRING, or TOEKN_OP) and value respectively. nextToken and nextTokenVal
|
||||
will also be available for lookahead. The next method is similar to
|
||||
getNextToken but also returns the token value. A value of None signals end
|
||||
of stream.
|
||||
"""
|
||||
self.ignoreWhitespace=ignoreWhitespace
|
||||
ifDefPy()
|
||||
if (isinstance(text, array.array)):
|
||||
text = text.tostring()
|
||||
endIfDef()
|
||||
self.text = asString(text)
|
||||
self.textIndex = 0
|
||||
self.textLen = len(self.text)
|
||||
self.token = None
|
||||
self.tokenVal = None
|
||||
self.nextToken = None
|
||||
self.nextTokenVal = None
|
||||
if (identStart == None):
|
||||
identStart = "[a-zA-Z_/]"
|
||||
if (tokenSep == None):
|
||||
tokenSep = "[^a-zA-Z0-9_/:]"
|
||||
self.identStart = re.compile(identStart)
|
||||
self.tokenSep = re.compile(tokenSep)
|
||||
self.getNextToken() # Prime the pump
|
||||
|
||||
def isEscaped(text, index):
|
||||
if ((index > 0) and (text[index-1] == '\\') and ((index < 2) or (text[index-2] != '\\'))):
|
||||
return True
|
||||
return False
|
||||
isEscaped = staticmethod(isEscaped)
|
||||
|
||||
def findClosingQuote(text, index, char):
|
||||
index = index + 1
|
||||
while True:
|
||||
endIndex = text.find(char, index)
|
||||
if (endIndex < 1):
|
||||
return -1
|
||||
if (Tokenizer.isEscaped(text, endIndex)):
|
||||
index = endIndex+1
|
||||
else:
|
||||
break
|
||||
return endIndex + 1
|
||||
findClosingQuote = staticmethod(findClosingQuote)
|
||||
|
||||
def _findClosing(self, char):
|
||||
if (self.textIndex >= self.textLen):
|
||||
raise Exception("The text \"%s\" has an unmatched string starting at %d" % (self.text, self.textIndex))
|
||||
index = Tokenizer.findClosingQuote(self.text, self.textIndex, char)
|
||||
if (index < 0):
|
||||
raise Exception("The text \"%s\" has an unmatched string starting at %d" % (self.text, self.textIndex-1))
|
||||
return index
|
||||
|
||||
def next(self):
|
||||
self.getNextToken()
|
||||
if (self.token == None):
|
||||
raise StopIteration()
|
||||
return self.tokenVal
|
||||
|
||||
def getNextToken(self):
|
||||
self.token = self.nextToken
|
||||
self.tokenVal = self.nextTokenVal
|
||||
while (self.textIndex < self.textLen):
|
||||
c = self.text[self.textIndex]
|
||||
if (c not in string.whitespace):
|
||||
if (c == '"' or c == "'" or c == '`'):
|
||||
endIndex = self._findClosing(c)
|
||||
self.nextToken = self.TOKEN_STRING
|
||||
self.nextTokenVal = self.text[self.textIndex:endIndex]
|
||||
self.textIndex = endIndex
|
||||
return
|
||||
elif (self.identStart.search(c)):
|
||||
endMatch = self.tokenSep.search(self.text, self.textIndex+1)
|
||||
if (endMatch):
|
||||
endIndex = endMatch.start()
|
||||
else:
|
||||
endIndex = self.textLen
|
||||
self.nextToken = self.TOKEN_IDENT
|
||||
self.nextTokenVal = self.text[self.textIndex:endIndex]
|
||||
self.textIndex = endIndex
|
||||
return
|
||||
else:
|
||||
self.nextToken = self.TOKEN_OP
|
||||
endIndex = self.textIndex + 1
|
||||
if (c == '<' or c == '>' or c == '!' or c == '='):
|
||||
if ((endIndex < self.textLen) and (self.text[endIndex] == '=')):
|
||||
endIndex += 1
|
||||
elif ((c == '%') and (endIndex < self.textLen)):
|
||||
c = self.text[endIndex]
|
||||
if (c in ['d', 'i', 'o', 'u', 'x', 'X', 'e', 'E', 'f', 'F', 'g', 'G', 'c', 'r', 's', '%']):
|
||||
endIndex += 1
|
||||
## self.nextToken = self.TOKEN_PLACEHOLDER # Should really be this but no one can handle it yet
|
||||
self.nextTokenVal = self.text[self.textIndex:endIndex]
|
||||
self.textIndex = endIndex
|
||||
return
|
||||
elif not self.ignoreWhitespace:
|
||||
self.nextToken=self.TOKEN_WS
|
||||
self.nextTokenVal=""
|
||||
while c in string.whitespace:
|
||||
self.nextTokenVal+=c
|
||||
self.textIndex+=1
|
||||
if self.textIndex==len(self.text):
|
||||
break
|
||||
c=self.text[self.textIndex]
|
||||
return
|
||||
self.textIndex += 1
|
||||
self.nextToken = None
|
||||
self.nextTokenVal = None
|
||||
|
||||
def isXPathNonVar(var):
|
||||
"""Returns true iff var is a string ("foo" or 'foo') or a number."""
|
||||
if (var.startswith("'") and var.endswith("'")) or \
|
||||
(var.startswith('"') and var.endswith('"')):
|
||||
return True
|
||||
|
||||
# list from XPathToCode, below
|
||||
if var.lower() in ["count", "empty", "true", "false", "null", "and", "or", \
|
||||
"like", "not"]:
|
||||
return True
|
||||
|
||||
try:
|
||||
t=int(var)
|
||||
return True
|
||||
except TypeError, e:
|
||||
pass
|
||||
except ValueError, e:
|
||||
pass
|
||||
|
||||
return False
|
||||
|
||||
def xpathToCode(xpaths, convertBracket=True):
|
||||
if ((xpaths == None) or (len(xpaths) < 1)):
|
||||
return "True"
|
||||
if (not isinstance(xpaths, (list, tuple))):
|
||||
xpaths = [xpaths]
|
||||
result = []
|
||||
for xpath in xpaths:
|
||||
t = Tokenizer(xpath, "[a-zA-Z0-9_/:\.]", "[^a-zA-Z0-9_/:\.]", ignoreWhitespace=False)
|
||||
expr = []
|
||||
lastToken=None
|
||||
while t.nextToken != None:
|
||||
t.getNextToken()
|
||||
if (t.token == Tokenizer.TOKEN_WS):
|
||||
expr.append(" ")
|
||||
elif (t.token == Tokenizer.TOKEN_OP):
|
||||
if (t.tokenVal == "="):
|
||||
expr.append("==")
|
||||
elif (t.tokenVal == "[" and convertBracket):
|
||||
expr.append("(")
|
||||
elif (t.tokenVal == "]" and convertBracket):
|
||||
expr.append(")")
|
||||
else:
|
||||
expr.append(t.tokenVal)
|
||||
elif (t.token == Tokenizer.TOKEN_IDENT):
|
||||
if (t.tokenVal == "and"):
|
||||
expr.append(" and ")
|
||||
elif (t.tokenVal == "or"):
|
||||
expr.append(" or ")
|
||||
elif (t.tokenVal == "not"):
|
||||
expr.append(" not ")
|
||||
elif (t.tokenVal == "like"):
|
||||
# REVIEW stoens@activegrid.com 02-Nov-05 --
|
||||
# This is very limited support for like:
|
||||
# typically like queries look like this: "foo like 'blah%'".
|
||||
# So translate this into "foo.startswith(blah)".
|
||||
# We should use a regular expression to support '%'s in
|
||||
# arbitrary places in the string. After 1.1.
|
||||
if t.nextToken and t.nextTokenVal.endswith("%'"):
|
||||
t.getNextToken() # throw away the "like" token
|
||||
last = len(expr) - 1
|
||||
expr[last] = "%s.startswith(%s')"\
|
||||
% (expr[last], t.tokenVal[:-2])
|
||||
else:
|
||||
# old behavior
|
||||
expr.append(t.tokenVal)
|
||||
|
||||
elif (t.tokenVal == "count"):
|
||||
expr.append("len")
|
||||
elif (t.tokenVal == 'empty'):
|
||||
expr.append('ctx.isEmptyPath')
|
||||
elif (t.tokenVal == 'true'):
|
||||
expr.append(_parseConstantFunction(t, 'True'))
|
||||
elif (t.tokenVal == 'false'):
|
||||
expr.append(_parseConstantFunction(t, 'False'))
|
||||
elif (t.tokenVal == 'null'):
|
||||
expr.append(_parseConstantFunction(t, 'None'))
|
||||
elif (-1!=t.tokenVal.find(':')):
|
||||
serviceDef, args=_parseServiceFunction(t)
|
||||
|
||||
# XXX handle serviceDef, args being None
|
||||
|
||||
for i in range(len(args)):
|
||||
args[i]=xpathToCode(args[i], False)
|
||||
jargs="[%s]" % (",".join(args))
|
||||
|
||||
# XXX should be processmodel.DATASERVICE_PROCESS_NAME, not "dataservice"
|
||||
if serviceDef[0]=='dataservice':
|
||||
expr.append("runtimesupport.invokeDataServiceWrapper(%s, %s, ctx, locals())" % \
|
||||
(serviceDef, jargs))
|
||||
else:
|
||||
expr.append("runtimesupport.invokeServiceWrapper(%s, %s, ctx)" % \
|
||||
(serviceDef, jargs))
|
||||
else:
|
||||
if (lastToken==')' or lastToken==']'):
|
||||
wasFunc=True
|
||||
else:
|
||||
wasFunc=False
|
||||
if (t.tokenVal.startswith('/')) and not wasFunc:
|
||||
expr.append(XPATH_ROOT_VAR)
|
||||
expr.append(t.tokenVal.replace('/','.'))
|
||||
lastToken=t.tokenVal
|
||||
else:
|
||||
expr.append(t.tokenVal)
|
||||
|
||||
|
||||
if (len(expr) == 2 and expr[0]==" "):
|
||||
expr = "".join(expr)
|
||||
result.append(expr)
|
||||
elif (len(expr) > 1):
|
||||
expr = "".join(expr)
|
||||
result.append("(%s)" % expr)
|
||||
elif (len(expr) > 0):
|
||||
result.append(expr[0])
|
||||
|
||||
return " and ".join(result)
|
||||
|
||||
def _parseArgs(t):
|
||||
args=[]
|
||||
argcon=""
|
||||
|
||||
if t.tokenVal!='(':
|
||||
return []
|
||||
if t.nextTokenVal==')':
|
||||
t.getNextToken()
|
||||
return []
|
||||
|
||||
depth=1
|
||||
|
||||
while(depth!=0):
|
||||
if not t.nextToken:
|
||||
raise Exception("parameters list with no closing ) after token: %s" % t.tokenVal)
|
||||
t.getNextToken()
|
||||
|
||||
if t.tokenVal=='(':
|
||||
depth+=1
|
||||
if t.tokenVal==')':
|
||||
depth-=1
|
||||
|
||||
if depth==0 or (depth==1 and t.tokenVal==','):
|
||||
args.append(argcon)
|
||||
argcon=""
|
||||
else:
|
||||
argcon+=t.tokenVal
|
||||
return args
|
||||
|
||||
def _parseServiceFunction(t):
|
||||
"""Parses what appears to be a service function call into serviceDefs and args lists.
|
||||
|
||||
Returns None, None if the serviceFunction appears to be invalid.
|
||||
"""
|
||||
if t.nextTokenVal!='(':
|
||||
return t.tokenVal, None
|
||||
|
||||
serviceDef=t.tokenVal.split(':')
|
||||
t.getNextToken()
|
||||
args=_parseArgs(t)
|
||||
|
||||
return serviceDef, args
|
||||
|
||||
def _parseConstantFunction(t, outputValue):
|
||||
firstVal = t.tokenVal
|
||||
if t.nextTokenVal != '(':
|
||||
return firstVal
|
||||
t.getNextToken()
|
||||
if t.nextTokenVal != ')':
|
||||
return "%s%s" % (firstVal, '(')
|
||||
t.getNextToken()
|
||||
return outputValue
|
||||
|
||||
def parseDSPredicate(ctx, str, vars, valueList=None):
|
||||
from activegrid.util.utillang import evalCode
|
||||
from activegrid.util.utillang import ObjAsDict
|
||||
|
||||
if valueList == None:
|
||||
valueList = []
|
||||
indexVar=0
|
||||
oldIndexVar=0
|
||||
sourceStr=str
|
||||
inlinedPredicate=[]
|
||||
qualifications=[]
|
||||
while True:
|
||||
oldIndexVar = indexVar
|
||||
dollarCurlForm = False
|
||||
quoted = False
|
||||
indexVar = sourceStr.find("bpws:getVariableData", indexVar)
|
||||
if indexVar == -1:
|
||||
indexVar = sourceStr.find("${", oldIndexVar)
|
||||
if indexVar == -1:
|
||||
break
|
||||
dollarCurlForm = True
|
||||
if indexVar > 0 and sourceStr[indexVar-1] in ('"',"'"):
|
||||
quoted = True
|
||||
if not dollarCurlForm:
|
||||
openParen = sourceStr.find("(", indexVar)
|
||||
if openParen == -1:
|
||||
break
|
||||
closeParen = sourceStr.find(")", openParen)
|
||||
if closeParen == -1:
|
||||
break
|
||||
else:
|
||||
openParen = indexVar+1
|
||||
closeParen = sourceStr.find("}", openParen)
|
||||
if closeParen == -1:
|
||||
break
|
||||
varRef = sourceStr[openParen+1: closeParen]
|
||||
if varRef.startswith('"') or varRef.startswith("'"):
|
||||
varRef = varRef[1:]
|
||||
if varRef.endswith('"') or varRef.endswith("'"):
|
||||
varRef = varRef[:-1]
|
||||
if isinstance(vars, dict) or isinstance(vars, ObjAsDict):
|
||||
varRefCode = xpathToCode(varRef)
|
||||
value = evalCode(varRefCode, vars)
|
||||
else:
|
||||
value = ctx.evalPath(vars, varRef)
|
||||
inlinedPredicate.append(sourceStr[oldIndexVar:indexVar])
|
||||
if quoted:
|
||||
inlinedPredicate.append("%s" % value)
|
||||
else:
|
||||
inlinedPredicate.append('%s')
|
||||
valueList.append(value)
|
||||
indexVar = closeParen+1
|
||||
inlinedPredicate.append(sourceStr[oldIndexVar:])
|
||||
qualifications.append(''.join(inlinedPredicate))
|
||||
return qualifications, valueList
|
@@ -21,3 +21,91 @@ def caseInsensitiveCompare(s1, s2):
|
||||
return -1
|
||||
else:
|
||||
return 1
|
||||
|
||||
def multiSplit(stringList, tokenList=[" "]):
|
||||
"""Splits strings in stringList by tokens, returns list of string."""
|
||||
if not stringList: return []
|
||||
if isinstance(tokenList, basestring):
|
||||
tokenList = [tokenList]
|
||||
if isinstance(stringList, basestring):
|
||||
stringList = [stringList]
|
||||
rtnList = stringList
|
||||
for token in tokenList:
|
||||
rtnList = rtnList[:]
|
||||
for string in rtnList:
|
||||
if string.find(token) > -1:
|
||||
rtnList.remove(string)
|
||||
names = string.split(token)
|
||||
for name in names:
|
||||
name = name.strip()
|
||||
if name:
|
||||
rtnList.append(name)
|
||||
return rtnList
|
||||
|
||||
QUOTES = ("\"", "'")
|
||||
|
||||
def _findArgStart(argStr):
|
||||
i = -1
|
||||
for c in argStr:
|
||||
i += 1
|
||||
if (c == " "):
|
||||
continue
|
||||
elif (c == ","):
|
||||
continue
|
||||
return i
|
||||
return None
|
||||
|
||||
def _findArgEnd(argStr):
|
||||
quotedArg = True
|
||||
argEndChar = argStr[0]
|
||||
if (not argEndChar in QUOTES):
|
||||
argEndChar = ","
|
||||
quotedArg = False
|
||||
i = -1
|
||||
firstChar = True
|
||||
for c in argStr:
|
||||
i+= 1
|
||||
if (firstChar):
|
||||
firstChar = False
|
||||
if (quotedArg):
|
||||
continue
|
||||
if (c == argEndChar):
|
||||
if (quotedArg):
|
||||
return min(i+1, len(argStr))
|
||||
else:
|
||||
return i
|
||||
return i
|
||||
|
||||
def parseArgs(argStr, stripQuotes=False):
|
||||
"""
|
||||
Given a str representation of method arguments, returns list arguments (as
|
||||
strings).
|
||||
|
||||
Input: "('[a,b]', 'c', 1)" -> Output: ["'[a,b]'", "'c'", "1"].
|
||||
|
||||
If stripQuotes, removes quotes from quoted arg.
|
||||
"""
|
||||
if (argStr.startswith("(")):
|
||||
argStr = argStr[1:]
|
||||
if (argStr.endswith(")")):
|
||||
argStr = argStr[:-1]
|
||||
else:
|
||||
raise AssertionError("Expected argStr to end with ')'")
|
||||
|
||||
rtn = []
|
||||
argsStr = argStr.strip()
|
||||
while (True):
|
||||
startIndex = _findArgStart(argStr)
|
||||
if (startIndex == None):
|
||||
break
|
||||
argStr = argStr[startIndex:]
|
||||
endIndex = _findArgEnd(argStr)
|
||||
if (endIndex == len(argStr) - 1):
|
||||
rtn.append(argStr.strip())
|
||||
break
|
||||
t = argStr[:endIndex].strip()
|
||||
if (stripQuotes and t[0] in QUOTES and t[-1] in QUOTES):
|
||||
t = t[1:-1]
|
||||
rtn.append(t)
|
||||
argStr = argStr[endIndex:]
|
||||
return rtn
|
||||
|
@@ -12,6 +12,7 @@
|
||||
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
|
||||
# this will be set to true in IDE.py when we are running release builds.
|
||||
isRelease = False
|
||||
@@ -26,6 +27,12 @@ isRelease = False
|
||||
|
||||
MAINMODULE_DIR = "AG_MAINMODULE_DIR"
|
||||
IS_RELEASE = "AG_IS_RELEASE"
|
||||
IS_COMMERCIAL = "AG_IS_COMMERCIAL"
|
||||
AG_SYSTEM_START_TIME_ENV_NAME = "AG_SYSTEM_START_TIME"
|
||||
|
||||
def isCommercial():
|
||||
|
||||
return os.path.exists(os.path.join(mainModuleDir,"commercial.txt")) or 'true' == (str(os.getenv(IS_COMMERCIAL)).lower())
|
||||
|
||||
def isRelease():
|
||||
return 'true' == (str(os.getenv(IS_RELEASE)).lower())
|
||||
@@ -39,6 +46,15 @@ def setRelease(value):
|
||||
def isWindows():
|
||||
return os.name == 'nt'
|
||||
|
||||
__isServer = False
|
||||
|
||||
def setServerMode(isServer):
|
||||
global __isServer
|
||||
__isServer = isServer
|
||||
|
||||
def isServer():
|
||||
global __isServer
|
||||
return __isServer
|
||||
|
||||
def _generateMainModuleDir():
|
||||
mainModuleDir = os.getenv(MAINMODULE_DIR)
|
||||
@@ -85,3 +101,16 @@ def getCommandNameForExecPath(execPath):
|
||||
return '"%s"' % execPath
|
||||
return execPath
|
||||
|
||||
def getUserName():
|
||||
if isWindows():
|
||||
return os.getenv('USERNAME')
|
||||
else:
|
||||
# 06-Feb-06 stoens@activegrid.com --
|
||||
# this blows up the linux cc runs with "Inappropriate ioctl for device"
|
||||
#return os.getlogin()
|
||||
return os.getenv('USER')
|
||||
|
||||
def getCurrentTimeAsFloat():
|
||||
return time.time()
|
||||
|
||||
systemStartTime = getCurrentTimeAsFloat()
|
||||
|
146
wxPython/samples/ide/activegrid/util/utillang.py
Normal file
146
wxPython/samples/ide/activegrid/util/utillang.py
Normal file
@@ -0,0 +1,146 @@
|
||||
#----------------------------------------------------------------------------
|
||||
# Name: utillang.py
|
||||
# Purpose: Provide language specific utilities
|
||||
#
|
||||
# Author: Joel Hare
|
||||
#
|
||||
# Created: 8/23/05
|
||||
# CVS-ID: $Id$
|
||||
# Copyright: (c) 2004-2005 ActiveGrid, Inc.
|
||||
# License: wxWindows License
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
import os
|
||||
import sys
|
||||
import UserDict
|
||||
import tempfile
|
||||
import xml.sax.saxutils as saxutils
|
||||
|
||||
import activegrid.util.parser as parser
|
||||
|
||||
PY2WEB_codepages = {
|
||||
'cp1251' : 'CP-1251',
|
||||
'koi8_r' : 'KOI8-R',
|
||||
}
|
||||
|
||||
def evalXPath(xpath, data, specialEntries=None):
|
||||
codeStr = parser.xpathToCode(xpath)
|
||||
return evalCode(codeStr, data, specialEntries)
|
||||
|
||||
def evalCode(codeStr, data, specialEntries=None):
|
||||
if isinstance(data, ObjAsDict):
|
||||
namespace = data
|
||||
elif isinstance(data, dict):
|
||||
namespace = dict(data)
|
||||
else:
|
||||
namespace = ObjAsDict(data)
|
||||
if specialEntries:
|
||||
for key, value in specialEntries.items():
|
||||
namespace.addSpecialEntry(key, value)
|
||||
return eval(codeStr, {}, namespace)
|
||||
|
||||
def deriveCharset():
|
||||
charset = None
|
||||
encodingString = sys.getdefaultencoding()
|
||||
if encodingString != 'ascii':
|
||||
charset = PY2WEB_codepages.get(encodingString.lower())
|
||||
if charset == None:
|
||||
charset = encodingString
|
||||
return charset
|
||||
|
||||
def toUTF8(value):
|
||||
"""
|
||||
Converts all unicode and non-string values to utf-8.
|
||||
This assumes string instances are already encoded in utf-8.
|
||||
Note that us-ascii is a subset of utf-8.
|
||||
"""
|
||||
if isinstance(value, unicode):
|
||||
return value.encode('utf-8')
|
||||
return str(value)
|
||||
|
||||
def toUnicode(value):
|
||||
"""
|
||||
Converts all strings non-string values to unicode.
|
||||
This assumes string instances are encoded in utf-8.
|
||||
Note that us-ascii is a subset of utf-8.
|
||||
"""
|
||||
if not isinstance(value, unicode):
|
||||
if not isinstance(value, str):
|
||||
return unicode(value)
|
||||
return unicode(value, 'utf-8')
|
||||
return value
|
||||
|
||||
|
||||
def getSystemTempDir():
|
||||
return tempfile.gettempdir()
|
||||
|
||||
def getEnvVar(name, defaultVal=None):
|
||||
if os.environ.has_key(name):
|
||||
return os.environ[name]
|
||||
return defaultVal
|
||||
|
||||
class ObjAsDict(UserDict.DictMixin):
|
||||
"""
|
||||
Passing this to eval as the local variables dictionary allows the
|
||||
evaluated code to access properties in the wrapped object
|
||||
"""
|
||||
def __init__(self, obj):
|
||||
self.obj = obj
|
||||
self.specialEntries = {}
|
||||
|
||||
def __getitem__(self, key):
|
||||
try:
|
||||
return getattr(self.obj, key)
|
||||
except AttributeError, e:
|
||||
if self.specialEntries.has_key(key):
|
||||
return self.specialEntries[key]
|
||||
raise KeyError(e.args)
|
||||
def __setitem__(self, key, item): setattr(self.obj, key, item)
|
||||
def __delitem__(self, key): delattr(self.obj, key)
|
||||
def keys(self):
|
||||
ret=[]
|
||||
for i in list(dir(self.obj)+self.specialEntries.keys()):
|
||||
if i=="__doc__" or i=="__module__":
|
||||
pass
|
||||
elif i not in ret:
|
||||
ret.append(i)
|
||||
return ret
|
||||
|
||||
def addSpecialEntry(self, key, value):
|
||||
self.specialEntries[key] = value
|
||||
|
||||
global saxXMLescapeDoubleQuote
|
||||
saxXMLescapeDoubleQuote = {'"':'"'}
|
||||
|
||||
global saxXMLescapesAllQuotes
|
||||
# IE doesn't support ' but it doesn't seem like we should need this escaped at all so I took it out.
|
||||
saxXMLescapesAllQuotes = {'"':'"', "'":"'"}
|
||||
|
||||
global saxXMLunescapes
|
||||
saxXMLunescapes = {'"':'"', "'":"'"}
|
||||
|
||||
def escape(data, extraEscapes=None):
|
||||
"""Escape ', ", &, <, and > in a string of data.
|
||||
|
||||
Basically, everything that saxutils.escape does (and this calls that, at
|
||||
least for now), but with " and ' added as well.
|
||||
|
||||
TODO: make this faster; saxutils.escape() is really slow
|
||||
"""
|
||||
|
||||
global saxXMLescapeDoubleQuote
|
||||
if (extraEscapes == None):
|
||||
extraEscapes = saxXMLescapeDoubleQuote
|
||||
return saxutils.escape(data, extraEscapes)
|
||||
|
||||
def unescape(data):
|
||||
"""Unescape ', ", &, <, and > in a string of data.
|
||||
|
||||
Basically, everything that saxutils.unescape does (and this calls that, at
|
||||
least for now), but with " and ' added as well.
|
||||
|
||||
TODO: make this faster; saxutils.unescape() is really slow
|
||||
"""
|
||||
|
||||
global saxXMLunescapes
|
||||
return saxutils.unescape(data, saxXMLunescapes)
|
@@ -2,7 +2,7 @@
|
||||
# Name: xmlmarshaller.py
|
||||
# Purpose:
|
||||
#
|
||||
# Authors: John Spurling, Joel Hare, Alan Mullendore
|
||||
# Authors: John Spurling, Joel Hare, Jeff Norton, Alan Mullendore
|
||||
#
|
||||
# Created: 7/28/04
|
||||
# CVS-ID: $Id$
|
||||
@@ -16,14 +16,18 @@ import logging
|
||||
ifDefPy()
|
||||
import xml.sax
|
||||
import xml.sax.handler
|
||||
import xml.sax.saxutils
|
||||
import datetime
|
||||
endIfDef()
|
||||
import xml.sax.saxutils as saxutils
|
||||
import activegrid.util.utillang as utillang
|
||||
import activegrid.util.objutils as objutils
|
||||
import activegrid.util.sysutils as sysutils
|
||||
import activegrid.util.aglogging as aglogging
|
||||
|
||||
MODULE_PATH = "__main__"
|
||||
|
||||
## ToDO remove maxOccurs "unbounded" resolves to -1 hacks after bug 177 is fixed
|
||||
##unboundedVal = 2147483647 # value used for maxOccurs == "unbounded"
|
||||
|
||||
"""
|
||||
Special attributes that we recognize:
|
||||
@@ -109,7 +113,6 @@ __xmlcdatacontent__ = "messyContent"
|
||||
|
||||
global xmlMarshallerLogger
|
||||
xmlMarshallerLogger = logging.getLogger("activegrid.util.xmlmarshaller.marshal")
|
||||
xmlMarshallerLogger.setLevel(aglogging.LEVEL_WARN)
|
||||
# INFO : low-level info
|
||||
# DEBUG : debugging info
|
||||
|
||||
@@ -184,6 +187,7 @@ DICT_ITEM_VALUE_NAME = "value"
|
||||
################################################################################
|
||||
|
||||
def setattrignorecase(object, name, value):
|
||||
## print "[setattrignorecase] name = %s, value = %s" % (name, value)
|
||||
if (name not in object.__dict__):
|
||||
namelow = name.lower()
|
||||
for attr in object.__dict__:
|
||||
@@ -193,26 +197,94 @@ def setattrignorecase(object, name, value):
|
||||
object.__dict__[name] = value
|
||||
|
||||
def getComplexType(obj):
|
||||
if (hasattr(obj, "_instancexsdcomplextype")):
|
||||
return obj._instancexsdcomplextype
|
||||
if (hasattr(obj, "__xsdcomplextype__")):
|
||||
return obj.__xsdcomplextype__
|
||||
return None
|
||||
|
||||
def _objectfactory(objname, objargs=None, objclass=None):
|
||||
"dynamically create an object based on the objname and return it."
|
||||
## print "[objectfactory] objname [%s]" % (objname)
|
||||
def _objectfactory(objtype, objargs=None, objclass=None):
|
||||
"dynamically create an object based on the objtype and return it."
|
||||
if not isinstance(objargs, list):
|
||||
objargs = [objargs]
|
||||
if (objclass != None):
|
||||
obj = None
|
||||
if (len(objargs) > 0):
|
||||
if (hasattr(objclass, "__xmlcdatacontent__")):
|
||||
obj = objclass()
|
||||
contentAttr = obj.__xmlcdatacontent__
|
||||
obj.__dict__[contentAttr] = str(objargs[0])
|
||||
return obj
|
||||
return objclass(*objargs)
|
||||
else:
|
||||
return objclass()
|
||||
return objutils.newInstance(objname, objargs)
|
||||
obj = objclass(*objargs)
|
||||
else:
|
||||
obj = objclass()
|
||||
if ((obj != None) and (hasattr(obj, 'postUnmarshal'))):
|
||||
obj.postUnmarshal()
|
||||
return obj
|
||||
return objutils.newInstance(objtype, objargs)
|
||||
|
||||
class GenericXMLObject(object):
|
||||
def __init__(self, content=None):
|
||||
if content != None:
|
||||
self._content = content
|
||||
self.__xmlcontent__ = '_content'
|
||||
|
||||
def __str__(self):
|
||||
return "GenericXMLObject(%s)" % objutils.toDiffableString(self.__dict__)
|
||||
|
||||
def setXMLAttributes(self, xmlName, attrs=None, children=None, nsMap=None, defaultNS=None):
|
||||
if xmlName != None:
|
||||
i = xmlName.rfind(':')
|
||||
if i < 0:
|
||||
self.__xmlname__ = xmlName
|
||||
if defaultNS != None:
|
||||
self.__xmldefaultnamespace__ = str(defaultNS)
|
||||
else:
|
||||
self.__xmlname__ = xmlName[i+1:]
|
||||
prefix = xmlName[:i]
|
||||
if nsMap.has_key(prefix):
|
||||
self.__xmldefaultnamespace__ = str(nsMap[prefix])
|
||||
if attrs != None:
|
||||
for attrname, attr in attrs.items():
|
||||
attrname = str(attrname)
|
||||
if attrname == XMLNS or attrname.startswith(XMLNS_PREFIX):
|
||||
pass
|
||||
elif attrname == "objtype":
|
||||
pass
|
||||
else:
|
||||
if not hasattr(self, '__xmlattributes__'):
|
||||
self.__xmlattributes__ = []
|
||||
i = attrname.rfind(':')
|
||||
if i >= 0:
|
||||
prefix = attrname[:i]
|
||||
attrname = attrname[i+1:]
|
||||
if not hasattr(self, '__xmlattrnamespaces__'):
|
||||
self.__xmlattrnamespaces__ = {}
|
||||
if self.__xmlattrnamespaces__.has_key(prefix):
|
||||
alist = self.__xmlattrnamespaces__[prefix]
|
||||
else:
|
||||
alist = []
|
||||
alist.append(attrname)
|
||||
self.__xmlattrnamespaces__[prefix] = alist
|
||||
self.__xmlattributes__.append(attrname)
|
||||
if hasattr(self, '__xmlattributes__'):
|
||||
self.__xmlattributes__.sort()
|
||||
if children != None and len(children) > 0:
|
||||
childList = []
|
||||
flattenList = {}
|
||||
for childname, child in children:
|
||||
childstr = str(childname)
|
||||
if childstr in childList:
|
||||
if not flattenList.has_key(childstr):
|
||||
flattenList[childstr] = (childstr,)
|
||||
else:
|
||||
childList.append(childstr)
|
||||
if len(flattenList) > 0:
|
||||
self.__xmlflattensequence__ = flattenList
|
||||
|
||||
def initialize(self, arg1=None):
|
||||
pass
|
||||
|
||||
|
||||
class Element:
|
||||
def __init__(self, name, attrs=None, xsname=None):
|
||||
@@ -222,9 +294,11 @@ class Element:
|
||||
self.children = []
|
||||
self.objclass = None
|
||||
self.xsname = xsname
|
||||
self.objtype = None
|
||||
|
||||
def getobjtype(self):
|
||||
objtype = self.attrs.get("objtype")
|
||||
# objtype = self.attrs.get("objtype")
|
||||
objtype = self.objtype
|
||||
if (objtype == None):
|
||||
if (len(self.children) > 0):
|
||||
objtype = "dict"
|
||||
@@ -239,15 +313,34 @@ class NsElement(object):
|
||||
self.defaultNS = None
|
||||
self.prefix = None
|
||||
|
||||
def isEmpty(self):
|
||||
return ((self.nsMap == {}) and (self.targetNS == None) and (self.defaultNS == None))
|
||||
def __str__(self):
|
||||
if self.prefix == None:
|
||||
strVal = 'prefix = None; '
|
||||
else:
|
||||
strVal = 'prefix = "%s"; ' % (self.prefix)
|
||||
if self.targetNS == None:
|
||||
strVal += 'targetNS = None; '
|
||||
else:
|
||||
strVal += 'targetNS = "%s"; ' % (self.targetNS)
|
||||
if self.defaultNS == None:
|
||||
strVal += 'defaultNS = None; '
|
||||
else:
|
||||
strVal += 'defaultNS = "%s"; ' % (self.defaultNS)
|
||||
if len(self.nsMap) == 0:
|
||||
strVal += 'nsMap = None; '
|
||||
else:
|
||||
strVal += 'nsMap = {'
|
||||
for ik, iv in self.nsMap.iteritems():
|
||||
strVal += '%s=%s; ' % (ik,iv)
|
||||
strVal += '}'
|
||||
return strVal
|
||||
|
||||
def setKnownTypes(self, masterKnownTypes, masterKnownNamespaces, parentNSE):
|
||||
# if we're a nested element, extend our parent element's mapping
|
||||
if parentNSE != None:
|
||||
self.knownTypes = parentNSE.knownTypes.copy()
|
||||
# but if we have a different default namespace, replace the parent's default mappings
|
||||
if parentNSE.defaultNS != self.defaultNS:
|
||||
if (self.defaultNS != None) and (parentNSE.defaultNS != self.defaultNS):
|
||||
newKT = self.knownTypes.copy()
|
||||
for tag in newKT:
|
||||
if tag.find(':') < 0:
|
||||
@@ -283,7 +376,6 @@ class NsElement(object):
|
||||
self.knownTypes[knownTagName] = mapClass
|
||||
else: # e.g. "ItemSearchRequest"
|
||||
self.knownTypes[tag] = mapClass
|
||||
## print 'mapping <%s> to class "%s"' % (tag, mapClass.__name__)
|
||||
|
||||
def expandQName(self, eName, attrName, attrValue):
|
||||
bigValue = attrValue
|
||||
@@ -298,38 +390,57 @@ class NsElement(object):
|
||||
if shortNs == attrNS:
|
||||
bigValue = '%s:%s' % (longNs, attrNCName)
|
||||
break
|
||||
## print '[expandQName] input attrName = "%s" and attrValue "%s"; output = "%s"' % (attrName, attrValue, bigValue)
|
||||
return bigValue
|
||||
|
||||
class XMLObjectFactory(xml.sax.ContentHandler):
|
||||
def __init__(self, knownTypes=None, knownNamespaces=None):
|
||||
def __init__(self, knownTypes=None, knownNamespaces=None, xmlSource=None, createGenerics=False):
|
||||
self.rootelement = None
|
||||
if (knownTypes == None):
|
||||
self.knownTypes = {}
|
||||
if xmlSource == None:
|
||||
self.xmlSource = "unknown"
|
||||
else:
|
||||
self.knownTypes = knownTypes
|
||||
if (knownNamespaces == None):
|
||||
self.knownNamespaces = {}
|
||||
else:
|
||||
self.knownNamespaces = knownNamespaces
|
||||
self.xmlSource = xmlSource
|
||||
self.createGenerics = createGenerics
|
||||
self.skipper = False
|
||||
self.elementstack = []
|
||||
self.nsstack = []
|
||||
self.collectContent = None
|
||||
if (knownNamespaces == None):
|
||||
self.knownNamespaces = {}
|
||||
else:
|
||||
self.knownNamespaces = knownNamespaces
|
||||
self.reversedNamespaces = {}
|
||||
for longns, shortns in self.knownNamespaces.iteritems():
|
||||
self.reversedNamespaces[shortns] = longns
|
||||
self.knownTypes = {}
|
||||
if (knownTypes != None):
|
||||
for tag, cls in knownTypes.iteritems():
|
||||
i = tag.rfind(':')
|
||||
if i >= 0:
|
||||
shortns = tag[:i]
|
||||
tag = tag[i+1:]
|
||||
if not self.reversedNamespaces.has_key(shortns):
|
||||
errorString = 'Error unmarshalling XML document from source "%s": knownTypes specifies an unmapped short namespace "%s" for element "%s"' % (self.xmlSource, shortns, tag)
|
||||
raise UnmarshallerException(errorString)
|
||||
longns = self.reversedNamespaces[shortns]
|
||||
tag = '%s:%s' % (longns, tag)
|
||||
self.knownTypes[tag] = cls
|
||||
#printKnownTypes(self.knownTypes, 'Unmarshaller.XMLObjectFactory.__init__')
|
||||
xml.sax.handler.ContentHandler.__init__(self)
|
||||
|
||||
def appendElementStack(self, newElement, newNS):
|
||||
self.elementstack.append(newElement)
|
||||
if (newNS.isEmpty()):
|
||||
if (len(self.nsstack) > 0):
|
||||
newNS = self.nsstack[-1]
|
||||
else:
|
||||
newNS.knownTypes = self.knownTypes.copy()
|
||||
else:
|
||||
if (len(self.nsstack) > 0):
|
||||
newNS.setKnownTypes(self.knownTypes, self.knownNamespaces, self.nsstack[-1])
|
||||
else:
|
||||
newNS.setKnownTypes(self.knownTypes, self.knownNamespaces, None)
|
||||
oldNS = self.nsstack[-1]
|
||||
if newNS.defaultNS == None:
|
||||
newNS.defaultNS = oldNS.defaultNS
|
||||
if newNS.targetNS == None:
|
||||
newNS.targetNS = oldNS.targetNS
|
||||
if len(newNS.nsMap) == 0:
|
||||
newNS.nsMap = oldNS.nsMap
|
||||
elif len(oldNS.nsMap) > 0:
|
||||
map = oldNS.nsMap.copy()
|
||||
map.update(newNS.nsMap)
|
||||
newNS.nsMap = map
|
||||
self.nsstack.append(newNS)
|
||||
return newNS
|
||||
|
||||
@@ -353,11 +464,16 @@ class XMLObjectFactory(xml.sax.ContentHandler):
|
||||
strVal += '>'
|
||||
self.collectContent.content += strVal
|
||||
xsname = name
|
||||
if name.find(':') > -1: # Strip namespace prefixes for now until actually looking them up in xsd
|
||||
name = name[name.rfind(":") + 1:]
|
||||
i = name.rfind(':')
|
||||
if i >= 0:
|
||||
nsname = name[:i]
|
||||
name = name[i+1:]
|
||||
else:
|
||||
nsname = None
|
||||
element = Element(name, attrs.copy(), xsname=xsname)
|
||||
# if the element has namespace attributes, process them and add them to our stack
|
||||
nse = NsElement()
|
||||
objtype = None
|
||||
for k in attrs.getNames():
|
||||
if k.startswith('xmlns'):
|
||||
longNs = attrs[k]
|
||||
@@ -371,8 +487,28 @@ class XMLObjectFactory(xml.sax.ContentHandler):
|
||||
nse.nsMap[shortNs] = longNs
|
||||
elif k == 'targetNamespace':
|
||||
nse.targetNS = attrs.getValue(k)
|
||||
elif k == 'objtype':
|
||||
objtype = attrs.getValue(k)
|
||||
nse = self.appendElementStack(element, nse)
|
||||
element.objclass = nse.knownTypes.get(xsname)
|
||||
if nsname != None:
|
||||
if nse.nsMap.has_key(nsname):
|
||||
longname = '%s:%s' % (nse.nsMap[nsname], name)
|
||||
## elif objtype == None:
|
||||
## errorString = 'Error unmarshalling XML document from source "%s": tag "%s" at line "%d", column "%d" has an undefined namespace' % (self.xmlSource, xsname, self._locator.getLineNumber(), self._locator.getColumnNumber())
|
||||
## raise UnmarshallerException(errorString)
|
||||
elif self.reversedNamespaces.has_key(nsname):
|
||||
longname = '%s:%s' % (self.reversedNamespaces[nsname], name)
|
||||
else:
|
||||
longname = xsname
|
||||
elif nse.defaultNS != None:
|
||||
longname = '%s:%s' % (nse.defaultNS, name)
|
||||
else:
|
||||
longname = name
|
||||
element.objtype = objtype
|
||||
element.objclass = self.knownTypes.get(longname)
|
||||
if element.objclass == None and len(self.knownNamespaces) == 0:
|
||||
# handles common case where tags are unqualified and knownTypes are too, but there's a defaultNS
|
||||
element.objclass = self.knownTypes.get(name)
|
||||
if (hasattr(element.objclass, "__xmlcontent__")):
|
||||
self.collectContent = element
|
||||
|
||||
@@ -387,8 +523,9 @@ class XMLObjectFactory(xml.sax.ContentHandler):
|
||||
def endElement(self, name):
|
||||
## print "[endElement] </%s>" % name
|
||||
xsname = name
|
||||
if name.find(":") > -1: # Strip namespace prefixes for now until actually looking them up in xsd
|
||||
name = name[name.find(":") + 1:]
|
||||
i = name.rfind(':')
|
||||
if i >= 0: # Strip namespace prefixes for now until actually looking them up in xsd
|
||||
name = name[i+1:]
|
||||
if self.skipper:
|
||||
if xsname == "xs:annotation" or xsname == "xsd:annotation": # here too
|
||||
self.skipper = False
|
||||
@@ -405,34 +542,36 @@ class XMLObjectFactory(xml.sax.ContentHandler):
|
||||
element, nse = self.popElementStack()
|
||||
if ((len(self.elementstack) > 1) and (self.elementstack[-1].getobjtype() == "None")):
|
||||
parentElement = self.elementstack[-2]
|
||||
## print "[endElement] %s: found parent with objtype==None: using its grandparent" % name
|
||||
elif (len(self.elementstack) > 0):
|
||||
parentElement = self.elementstack[-1]
|
||||
objtype = element.getobjtype()
|
||||
## print "element objtype is: ", objtype
|
||||
if (objtype == "None"):
|
||||
## print "[endElement] %s: skipping a (objtype==None) end tag" % name
|
||||
return
|
||||
constructorarglist = []
|
||||
if (len(element.content) > 0):
|
||||
strippedElementContent = element.content.strip()
|
||||
if (len(strippedElementContent) > 0):
|
||||
constructorarglist.append(element.content)
|
||||
# If the element requires an object, but none is known, use the GenericXMLObject class
|
||||
if ((element.objclass == None) and (element.attrs.get("objtype") == None) and ((len(element.attrs) > 0) or (len(element.children) > 0))):
|
||||
if self.createGenerics:
|
||||
element.objclass = GenericXMLObject
|
||||
obj = _objectfactory(objtype, constructorarglist, element.objclass)
|
||||
if element.objclass == GenericXMLObject:
|
||||
obj.setXMLAttributes(str(xsname), element.attrs, element.children, nse.nsMap, nse.defaultNS)
|
||||
complexType = getComplexType(obj)
|
||||
if (obj != None):
|
||||
if (hasattr(obj, "__xmlname__") and getattr(obj, "__xmlname__") == "sequence"):
|
||||
self.elementstack[-1].children = oldChildren
|
||||
return
|
||||
if (len(element.attrs) > 0) and not isinstance(obj, list):
|
||||
## print "[endElement] %s: element has attrs and the obj is not a list" % name
|
||||
for attrname, attr in element.attrs.items():
|
||||
if attrname == XMLNS or attrname.startswith(XMLNS_PREFIX):
|
||||
if attrname.startswith(XMLNS_PREFIX):
|
||||
ns = attrname[XMLNS_PREFIX_LENGTH:]
|
||||
else:
|
||||
ns = ""
|
||||
if complexType != None:
|
||||
if complexType != None or element.objclass == GenericXMLObject:
|
||||
if not hasattr(obj, "__xmlnamespaces__"):
|
||||
obj.__xmlnamespaces__ = {ns:attr}
|
||||
elif ns not in obj.__xmlnamespaces__:
|
||||
@@ -447,7 +586,6 @@ class XMLObjectFactory(xml.sax.ContentHandler):
|
||||
xsdElement = complexType.findElement(attrname)
|
||||
if (xsdElement != None):
|
||||
type = xsdElement.type
|
||||
## print 'Unmarshalling element "%s", attribute "%s" with type "%s"' % (name, xsdElement.name, type)
|
||||
if (type != None):
|
||||
if (type == TYPE_QNAME):
|
||||
attr = nse.expandQName(name, attrname, attr)
|
||||
@@ -455,11 +593,15 @@ class XMLObjectFactory(xml.sax.ContentHandler):
|
||||
### ToDO remove maxOccurs hack after bug 177 is fixed
|
||||
if attrname == "maxOccurs" and attr == "unbounded":
|
||||
attr = "-1"
|
||||
try:
|
||||
attr = _objectfactory(type, attr)
|
||||
except Exception, exceptData:
|
||||
errorString = 'Error unmarshalling attribute "%s" at line %d, column %d in XML document from source "%s": %s' % (attrname, self._locator.getLineNumber(), self._locator.getColumnNumber(), self.xmlSource, str(exceptData))
|
||||
raise UnmarshallerException(errorString)
|
||||
try:
|
||||
setattrignorecase(obj, _toAttrName(obj, attrname), attr)
|
||||
except AttributeError:
|
||||
errorString = 'Error unmarshalling XML document at line %i, column %i: The object type of attribute "%s" of XML element "%s": not specified or known' % (self._locator.getLineNumber(), self._locator.getColumnNumber(), attrname, name)
|
||||
errorString = 'Error setting value of attribute "%s" at line %d, column %d in XML document from source "%s": object type of XML element "%s" is not specified or known' % (attrname, self._locator.getLineNumber(), self._locator.getColumnNumber(), self.xmlSource, name)
|
||||
raise UnmarshallerException(errorString)
|
||||
## obj.__dict__[_toAttrName(obj, attrname)] = attr
|
||||
# stuff any child attributes meant to be in a sequence via the __xmlflattensequence__
|
||||
@@ -474,14 +616,12 @@ class XMLObjectFactory(xml.sax.ContentHandler):
|
||||
flattenDict[str(xmlnametuple)] = sequencename
|
||||
else:
|
||||
for xmlname in xmlnametuple:
|
||||
## print "[endElement]: adding flattenDict[%s] = %s" % (xmlname, sequencename)
|
||||
flattenDict[xmlname] = sequencename
|
||||
else:
|
||||
raise Exception("Invalid type for __xmlflattensequence___ : it must be a dict")
|
||||
|
||||
# reattach an object"s attributes to it
|
||||
for childname, child in element.children:
|
||||
## print "[endElement] childname is: ", childname, "; child is: ", child
|
||||
if (childname in flattenDict):
|
||||
sequencename = _toAttrName(obj, flattenDict[childname])
|
||||
if (not hasattr(obj, sequencename)):
|
||||
@@ -499,12 +639,13 @@ class XMLObjectFactory(xml.sax.ContentHandler):
|
||||
else:
|
||||
obj[childname] = child
|
||||
else:
|
||||
## print "childname = %s, obj = %s, child = %s" % (childname, repr(obj), repr(child))
|
||||
# don't replace a good attribute value with a bad one
|
||||
childAttrName = _toAttrName(obj, childname)
|
||||
if (not hasattr(obj, childAttrName)) or (getattr(obj, childAttrName) == None) or (getattr(obj, childAttrName) == []) or (not isinstance(child, GenericXMLObject)):
|
||||
try:
|
||||
setattrignorecase(obj, _toAttrName(obj, childname), child)
|
||||
setattrignorecase(obj, childAttrName, child)
|
||||
except AttributeError:
|
||||
raise MarshallerException("Error unmarshalling child element \"%s\" of XML element \"%s\": object type not specified or known" % (childname, name))
|
||||
## obj.__dict__[_toAttrName(obj, childname)] = child
|
||||
|
||||
if (complexType != None):
|
||||
for element in complexType.elements:
|
||||
@@ -524,7 +665,6 @@ class XMLObjectFactory(xml.sax.ContentHandler):
|
||||
if (len(self.elementstack) > 0):
|
||||
## print "[endElement] appending child with name: ", name, "; objtype: ", objtype
|
||||
parentElement.children.append((name, obj))
|
||||
## print "parentElement now has ", len(parentElement.children), " children"
|
||||
else:
|
||||
self.rootelement = obj
|
||||
|
||||
@@ -539,7 +679,12 @@ def _toAttrName(obj, name):
|
||||
break
|
||||
## if (name.startswith("__") and not name.endswith("__")):
|
||||
## name = "_%s%s" % (obj.__class__.__name__, name)
|
||||
return name
|
||||
return str(name)
|
||||
|
||||
def printKnownTypes(kt, where):
|
||||
print 'KnownTypes from %s' % (where)
|
||||
for tag, cls in kt.iteritems():
|
||||
print '%s => %s' % (tag, str(cls))
|
||||
|
||||
__typeMappingXsdToLang = {
|
||||
"string": "str",
|
||||
@@ -588,8 +733,11 @@ def _getXmlValue(langValue):
|
||||
else:
|
||||
return str(langValue)
|
||||
|
||||
def unmarshal(xmlstr, knownTypes=None, knownNamespaces=None, xmlSource=None):
|
||||
objectfactory = XMLObjectFactory(knownTypes, knownNamespaces)
|
||||
def unmarshal(xmlstr, knownTypes=None, knownNamespaces=None, xmlSource=None, createGenerics=False):
|
||||
objectfactory = XMLObjectFactory(knownTypes, knownNamespaces, xmlSource, createGenerics)
|
||||
# on Linux, pyXML's sax.parseString fails when passed unicode
|
||||
if (not sysutils.isWindows()):
|
||||
xmlstr = str(xmlstr)
|
||||
try:
|
||||
xml.sax.parseString(xmlstr, objectfactory)
|
||||
except xml.sax.SAXParseException, errorData:
|
||||
@@ -600,17 +748,19 @@ def unmarshal(xmlstr, knownTypes=None, knownNamespaces=None, xmlSource=None):
|
||||
return objectfactory.getRootObject()
|
||||
|
||||
def marshal(obj, elementName=None, prettyPrint=False, marshalType=True, indent=0, knownTypes=None, knownNamespaces=None, encoding=-1):
|
||||
## print '[marshal] entered with elementName = "%s"' % (elementName)
|
||||
worker = XMLMarshalWorker(prettyPrint=prettyPrint, marshalType=marshalType, knownTypes=knownTypes, knownNamespaces=knownNamespaces)
|
||||
if obj != None and hasattr(obj, '__xmldeepexclude__'):
|
||||
worker.xmldeepexclude = obj.__xmldeepexclude__
|
||||
xmlstr = "".join(worker._marshal(obj, elementName, indent=indent))
|
||||
if (isinstance(encoding, basestring)):
|
||||
return '<?xml version="1.0" encoding="%s"?>\n%s' % (encoding, xmlstr.encode(encoding))
|
||||
elif (encoding == None):
|
||||
aglogging.info(xmlMarshallerLogger, "marshal produced string of type %s", type(xmlstr))
|
||||
if (encoding == None):
|
||||
return xmlstr
|
||||
else:
|
||||
return '<?xml version="1.0" encoding="%s"?>\n%s' % (sys.getdefaultencoding(), xmlstr)
|
||||
if (not isinstance(encoding, basestring)):
|
||||
encoding = sys.getdefaultencoding()
|
||||
if (not isinstance(xmlstr, unicode)):
|
||||
xmlstr = xmlstr.decode()
|
||||
xmlstr = u'<?xml version="1.0" encoding="%s"?>\n%s' % (encoding, xmlstr)
|
||||
return xmlstr.encode(encoding)
|
||||
|
||||
class XMLMarshalWorker(object):
|
||||
def __init__(self, marshalType=True, prettyPrint=False, knownTypes=None, knownNamespaces=None):
|
||||
@@ -695,7 +845,7 @@ class XMLMarshalWorker(object):
|
||||
newNS.prefix = self.nsstack[-1].prefix
|
||||
else:
|
||||
newNS.prefix = ''
|
||||
if hasattr(obj, "__xmldefaultnamespace__"):
|
||||
if obj != None and hasattr(obj, "__xmldefaultnamespace__"):
|
||||
longPrefixNS = getattr(obj, "__xmldefaultnamespace__")
|
||||
if longPrefixNS == defaultLongNS:
|
||||
newNS.prefix = ''
|
||||
@@ -705,13 +855,12 @@ class XMLMarshalWorker(object):
|
||||
if v == longPrefixNS:
|
||||
newNS.prefix = k + ':'
|
||||
break;
|
||||
## print '[appendNSStack] found longPrefixNS in nameSpaces = "%s"' % (newNS.prefix)
|
||||
except:
|
||||
if (longPrefixNS in asDict(self.knownNamespaces)):
|
||||
newNS.prefix = self.knownNamespaces[longPrefixNS] + ':'
|
||||
else:
|
||||
raise MarshallerException('Error marshalling __xmldefaultnamespace__ ("%s") not defined in namespace stack' % (longPrefixNS))
|
||||
if hasattr(obj, "targetNamespace"):
|
||||
if obj != None and hasattr(obj, "targetNamespace"):
|
||||
newNS.targetNS = obj.targetNamespace
|
||||
elif len(self.nsstack) > 0:
|
||||
newNS.targetNS = self.nsstack[-1].targetNS
|
||||
@@ -749,9 +898,11 @@ class XMLMarshalWorker(object):
|
||||
|
||||
def _marshal(self, obj, elementName=None, nameSpacePrefix="", indent=0):
|
||||
if (obj != None):
|
||||
xmlMarshallerLogger.debug("--> _marshal: elementName=%s%s, type=%s, obj=%s, indent=%d" % (nameSpacePrefix, elementName, type(obj), str(obj), indent))
|
||||
aglogging.debug(xmlMarshallerLogger, "--> _marshal: elementName=%s%s, type=%s, obj=%s, indent=%d", nameSpacePrefix, elementName, type(obj), str(obj), indent)
|
||||
else:
|
||||
xmlMarshallerLogger.debug("--> _marshal: elementName=%s%s, obj is None, indent=%d" % (nameSpacePrefix, elementName, indent))
|
||||
aglogging.debug(xmlMarshallerLogger, "--> _marshal: elementName=%s%s, obj is None, indent=%d", nameSpacePrefix, elementName, indent)
|
||||
if ((obj != None) and (hasattr(obj, 'preMarshal'))):
|
||||
obj.preMarshal()
|
||||
excludeAttrs = []
|
||||
excludeAttrs.extend(self.xmldeepexclude)
|
||||
if hasattr(obj, "__xmlexclude__"):
|
||||
@@ -768,8 +919,8 @@ class XMLMarshalWorker(object):
|
||||
newline = ""
|
||||
increment = 0
|
||||
## Determine the XML element name. If it isn"t specified in the
|
||||
## parameter list, look for it in the __xmlname__ Lang
|
||||
## attribute, else use the default generic BASETYPE_ELEMENT_NAME.
|
||||
## parameter list, look for it in the __xmlname__ attribute,
|
||||
## else use the default generic BASETYPE_ELEMENT_NAME.
|
||||
nameSpaceAttrs = self.appendNSStack(obj)
|
||||
nameSpacePrefix = self.getNSPrefix()
|
||||
if not elementName:
|
||||
@@ -779,13 +930,15 @@ class XMLMarshalWorker(object):
|
||||
elementName = nameSpacePrefix + BASETYPE_ELEMENT_NAME
|
||||
else:
|
||||
elementName = nameSpacePrefix + elementName
|
||||
## print '[XMLMarshalWorker._marshal] elementName "%s"; nameSpaceAttrs is "%s"' % (elementName, nameSpaceAttrs)
|
||||
|
||||
if (hasattr(obj, "__xmlsequencer__")) and (obj.__xmlsequencer__ != None):
|
||||
if (XMLSCHEMA_XSD_URL in self.nsstack[-1].nameSpaces.values()):
|
||||
for kShort, vLong in self.nsstack[-1].nameSpaces.iteritems():
|
||||
if vLong == XMLSCHEMA_XSD_URL:
|
||||
if kShort != DEFAULT_NAMESPACE_KEY:
|
||||
xsdPrefix = kShort + ':'
|
||||
else:
|
||||
xsdPrefix = ''
|
||||
break
|
||||
else:
|
||||
xsdPrefix = 'xs:'
|
||||
@@ -793,7 +946,6 @@ class XMLMarshalWorker(object):
|
||||
else:
|
||||
elementAdd = None
|
||||
|
||||
## print "marshal: entered with elementName: ", elementName
|
||||
members_to_skip = []
|
||||
## Add more members_to_skip based on ones the user has selected
|
||||
## via the __xmlexclude__ and __xmldeepexclude__ attributes.
|
||||
@@ -806,7 +958,6 @@ class XMLMarshalWorker(object):
|
||||
xmlattributes = obj.__xmlattributes__
|
||||
members_to_skip.extend(xmlattributes)
|
||||
for attr in xmlattributes:
|
||||
## print 'Processing element "%s"; attribute "%s"' % (elementName, attr)
|
||||
internalAttrName = attr
|
||||
ifDefPy()
|
||||
if (attr.startswith("__") and not attr.endswith("__")):
|
||||
@@ -814,7 +965,6 @@ class XMLMarshalWorker(object):
|
||||
endIfDef()
|
||||
# Fail silently if a python attribute is specified to be
|
||||
# an XML attribute but is missing.
|
||||
## print "marshal: processing attribute ", internalAttrName
|
||||
attrNameSpacePrefix = ""
|
||||
if hasattr(obj, "__xmlattrnamespaces__"):
|
||||
for nameSpaceKey, nameSpaceAttributes in getattr(obj, "__xmlattrnamespaces__").iteritems():
|
||||
@@ -856,8 +1006,7 @@ class XMLMarshalWorker(object):
|
||||
else:
|
||||
value = objutils.toDiffableRepr(value)
|
||||
|
||||
objattrs += ' %s%s="%s"' % (attrNameSpacePrefix, attr, saxutils.escape(value))
|
||||
## print "marshal: new objattrs is: ", objattrs
|
||||
objattrs += ' %s%s="%s"' % (attrNameSpacePrefix, attr, utillang.escape(value))
|
||||
if (obj == None):
|
||||
xmlString = [""]
|
||||
elif isinstance(obj, bool):
|
||||
@@ -873,9 +1022,18 @@ class XMLMarshalWorker(object):
|
||||
objTypeStr = self._genObjTypeStr("float")
|
||||
xmlString = ['%s<%s%s>%s</%s>%s' % (prefix, elementName, objTypeStr, str(obj), elementName, newline)]
|
||||
elif isinstance(obj, unicode): # have to check before basestring - unicode is instance of base string
|
||||
xmlString = ['%s<%s>%s</%s>%s' % (prefix, elementName, saxutils.escape(obj.encode()), elementName, newline)]
|
||||
xmlString = ['%s<%s>%s</%s>%s' % (prefix, elementName, utillang.escape(obj.encode()), elementName, newline)]
|
||||
elif isinstance(obj, basestring):
|
||||
xmlString = ['%s<%s>%s</%s>%s' % (prefix, elementName, saxutils.escape(obj), elementName, newline)]
|
||||
xmlString = ['%s<%s>%s</%s>%s' % (prefix, elementName, utillang.escape(obj), elementName, newline)]
|
||||
elif isinstance(obj, datetime.datetime):
|
||||
objTypeStr = self._genObjTypeStr("datetime")
|
||||
xmlString = ['%s<%s%s>%s</%s>%s' % (prefix, elementName, objTypeStr, str(obj), elementName, newline)]
|
||||
elif isinstance(obj, datetime.date):
|
||||
objTypeStr = self._genObjTypeStr("date")
|
||||
xmlString = ['%s<%s%s>%s</%s>%s' % (prefix, elementName, objTypeStr, str(obj), elementName, newline)]
|
||||
elif isinstance(obj, datetime.time):
|
||||
objTypeStr = self._genObjTypeStr("time")
|
||||
xmlString = ['%s<%s%s>%s</%s>%s' % (prefix, elementName, objTypeStr, str(obj), elementName, newline)]
|
||||
elif isinstance(obj, list):
|
||||
if len(obj) < 1:
|
||||
xmlString = ""
|
||||
@@ -910,13 +1068,15 @@ class XMLMarshalWorker(object):
|
||||
elif hasattr(obj, "__xmlcontent__"):
|
||||
contentValue = getattr(obj, obj.__xmlcontent__)
|
||||
if contentValue == None:
|
||||
contentValue = ''
|
||||
xmlString = ["%s<%s%s%s/>%s" % (prefix, elementName, nameSpaceAttrs, objattrs, newline)]
|
||||
else:
|
||||
contentValue = saxutils.escape(contentValue)
|
||||
contentValue = utillang.escape(contentValue)
|
||||
xmlString = ["%s<%s%s%s>%s</%s>%s" % (prefix, elementName, nameSpaceAttrs, objattrs, contentValue, elementName, newline)]
|
||||
else:
|
||||
# Only add the objtype if the element tag is unknown to us.
|
||||
if (self.isKnownType(elementName) == True):
|
||||
if (isinstance(obj, GenericXMLObject)):
|
||||
objTypeStr = ""
|
||||
elif (self.isKnownType(elementName) == True):
|
||||
objTypeStr = ""
|
||||
else:
|
||||
objTypeStr = self._genObjTypeStr("%s.%s" % (obj.__class__.__module__, className))
|
||||
@@ -929,7 +1089,7 @@ class XMLMarshalWorker(object):
|
||||
if hasattr(obj, "__xmlbody__"):
|
||||
xmlbody = getattr(obj, obj.__xmlbody__)
|
||||
if xmlbody != None:
|
||||
xmlMemberString.append(xmlbody)
|
||||
xmlMemberString.append(utillang.escape(xmlbody))
|
||||
else:
|
||||
if hasattr(obj, "__xmlattrgroups__"):
|
||||
attrGroups = obj.__xmlattrgroups__.copy()
|
||||
@@ -975,20 +1135,16 @@ class XMLMarshalWorker(object):
|
||||
xmlname = None
|
||||
if (len(xmlnametuple) == 1):
|
||||
xmlname = xmlnametuple[0]
|
||||
## ix = 0
|
||||
if not isinstance(value, (list, tuple)):
|
||||
value = [value]
|
||||
for seqitem in value:
|
||||
## xmlname = xmlnametuple[ix]
|
||||
## ix += 1
|
||||
## if (ix >= len(xmlnametuple)):
|
||||
## ix = 0
|
||||
xmlMemberString.extend(self._marshal(seqitem, xmlname, subElementNameSpacePrefix, indent=indent+increment))
|
||||
else:
|
||||
if (hasattr(obj, "__xmlrename__") and name in asDict(obj.__xmlrename__)):
|
||||
xmlname = obj.__xmlrename__[name]
|
||||
else:
|
||||
xmlname = name
|
||||
if (value != None):
|
||||
xmlMemberString.extend(self._marshal(value, xmlname, subElementNameSpacePrefix, indent=indent+increment))
|
||||
if (eName != "__nogroup__"):
|
||||
xmlMemberString.append("%s</%s>%s" % (prefix, eName, newline))
|
||||
@@ -1022,8 +1178,8 @@ class XMLMarshalWorker(object):
|
||||
xmlString.append("><![CDATA[%s]]></%s>%s" % (cdataContent, elementName, newline))
|
||||
else:
|
||||
xmlString.append("/>%s" % newline)
|
||||
## return xmlString
|
||||
xmlMarshallerLogger.debug("<-- _marshal: %s" % str(xmlString))
|
||||
if aglogging.isEnabledForDebug(xmlMarshallerLogger):
|
||||
aglogging.debug(xmlMarshallerLogger, "<-- _marshal: %s", objutils.toDiffableString(xmlString))
|
||||
#print "<-- _marshal: %s" % str(xmlString)
|
||||
self.popNSStack()
|
||||
return xmlString
|
||||
|
@@ -22,35 +22,44 @@ import activegrid.util.aglogging as aglogging
|
||||
|
||||
xmlLogger = logging.getLogger("activegrid.util.xml")
|
||||
|
||||
def load(fileName, knownTypes=None, knownNamespaces=None):
|
||||
def load(fileName, knownTypes=None, knownNamespaces=None, createGenerics=False):
|
||||
loadedObject = None
|
||||
fileObject = file(fileName)
|
||||
timeStart = time.time()
|
||||
xml = ""
|
||||
try:
|
||||
xml = fileObject.read()
|
||||
loadedObject = unmarshal(xml, knownTypes=knownTypes, knownNamespaces=knownNamespaces, xmlSource=fileName)
|
||||
loadedObject = unmarshal(xml, knownTypes=knownTypes, knownNamespaces=knownNamespaces, xmlSource=fileName, createGenerics=createGenerics)
|
||||
loadedObject.fileName = os.path.abspath(fileName)
|
||||
if hasattr(loadedObject, 'initialize'):
|
||||
loadedObject.initialize()
|
||||
finally:
|
||||
fileObject.close()
|
||||
if xmlLogger.isEnabledFor(aglogging.LEVEL_INFO):
|
||||
timeDone = time.time()
|
||||
aglogging.info(xmlLogger, ('Load statistics for file %s: elapsed time = %f secs' % (fileName, timeDone-timeStart)))
|
||||
aglogging.info(xmlLogger, ('Load statistics for file %s (%d bytes): elapsed time = %f secs' % (fileName, len(xml), timeDone-timeStart)))
|
||||
return loadedObject
|
||||
|
||||
def loadURI(uri, knownTypes=None, knownNamespaces=None, xmlSource=None):
|
||||
def loadURI(uri, knownTypes=None, knownNamespaces=None, xmlSource=None, createGenerics=False):
|
||||
loadedObject = None
|
||||
timeStart = time.time()
|
||||
xml = ""
|
||||
try:
|
||||
xml = urllib.urlopen(uri).read()
|
||||
loadedObject = unmarshal(xml, knownTypes=knownTypes, knownNamespaces=knownNamespaces, xmlSource=xmlSource)
|
||||
loadedObject = unmarshal(xml, knownTypes=knownTypes, knownNamespaces=knownNamespaces, xmlSource=xmlSource, createGenerics=createGenerics)
|
||||
loadedObject.fileName = uri
|
||||
if hasattr(loadedObject, 'initialize'):
|
||||
loadedObject.initialize()
|
||||
finally:
|
||||
if xmlLogger.isEnabledFor(aglogging.LEVEL_INFO):
|
||||
timeDone = time.time()
|
||||
aglogging.info(xmlLogger, ('Load statistics for URI %s (%d bytes): elapsed time = %f secs' % (uri, len(xml), timeDone-timeStart)))
|
||||
return loadedObject
|
||||
|
||||
def unmarshal(xml, knownTypes=None, knownNamespaces=None, xmlSource=None):
|
||||
def unmarshal(xml, knownTypes=None, knownNamespaces=None, xmlSource=None, createGenerics=False):
|
||||
if (knownTypes == None):
|
||||
knownTypes, knownNamespaces = getAgKnownTypes()
|
||||
return xmlmarshaller.unmarshal(xml, knownTypes=knownTypes, knownNamespaces=knownNamespaces, xmlSource=xmlSource)
|
||||
return xmlmarshaller.unmarshal(xml, knownTypes=knownTypes, knownNamespaces=knownNamespaces, xmlSource=xmlSource, createGenerics=createGenerics)
|
||||
|
||||
def save(fileName, objectToSave, prettyPrint=True, marshalType=True, knownTypes=None, knownNamespaces=None, encoding='utf-8'):
|
||||
if hasattr(objectToSave, '_xmlReadOnly') and objectToSave._xmlReadOnly == True:
|
||||
@@ -155,41 +164,6 @@ def getAgVersion(fileName):
|
||||
version = xml[i+1:j]
|
||||
return version
|
||||
|
||||
def escape(data):
|
||||
"""Escape ', ", &, <, and > in a string of data.
|
||||
|
||||
Basically, everything that saxutils.escape does (and this calls that, at
|
||||
least for now), but with " added as well.
|
||||
|
||||
XXX TODO make this faster; saxutils.escape() is really slow
|
||||
"""
|
||||
|
||||
import xml.sax.saxutils as saxutils
|
||||
|
||||
data=saxutils.escape(data)
|
||||
data=data.replace("\"", """)
|
||||
|
||||
# IE doesn't support '
|
||||
# data=data.replace("\'", "'")
|
||||
data=data.replace("\'", "'")
|
||||
|
||||
return data
|
||||
|
||||
def unescape(data):
|
||||
"""Unescape ', ", &, <, and > in a string of data.
|
||||
|
||||
Basically, everything that saxutils.unescape does (and this calls that, at
|
||||
least for now), but with " added as well.
|
||||
|
||||
XXX TODO make this faster; saxutils.unescape() is really slow
|
||||
"""
|
||||
|
||||
import xml.sax.saxutils as saxutils
|
||||
|
||||
data=data.replace(""", "\"")
|
||||
data=data.replace("'", "\'")
|
||||
return saxutils.unescape(data)
|
||||
|
||||
|
||||
AG_NS_URL = "http://www.activegrid.com/ag.xsd"
|
||||
BPEL_NS_URL = "http://schemas.xmlsoap.org/ws/2003/03/business-process"
|
||||
@@ -197,7 +171,9 @@ HTTP_WSDL_NS_URL = "http://schemas.xmlsoap.org/wsdl/http/"
|
||||
MIME_WSDL_NS_URL = "http://schemas.xmlsoap.org/wsdl/mime/"
|
||||
SOAP_NS_URL = "http://schemas.xmlsoap.org/wsdl/soap/"
|
||||
SOAP12_NS_URL = "http://schemas.xmlsoap.org/wsdl/soap12/"
|
||||
SOAP_NS_ENCODING = "http://schemas.xmlsoap.org/soap/encoding/"
|
||||
WSDL_NS_URL = "http://schemas.xmlsoap.org/wsdl/"
|
||||
WSSE_NS_URL = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
|
||||
XFORMS_NS_URL = "http://www.w3c.org/xform.xsd"
|
||||
XMLSCHEMA_NS_URL = "http://www.w3.org/2001/XMLSchema"
|
||||
XSI_NS_URL = "http://www.w3.org/2001/XMLSchema-instance"
|
||||
@@ -210,6 +186,7 @@ KNOWN_NAMESPACES = { AG_NS_URL : "ag",
|
||||
SOAP_NS_URL : "soap",
|
||||
SOAP12_NS_URL : "soap12",
|
||||
WSDL_NS_URL : "wsdl",
|
||||
WSSE_NS_URL : "wsse",
|
||||
XFORMS_NS_URL : "xforms",
|
||||
XMLSCHEMA_NS_URL : "xs",
|
||||
XACML_NS_URL : "xacml",
|
||||
@@ -226,19 +203,23 @@ def getAgXsdToClassName():
|
||||
"ag:body" : "activegrid.model.processmodel.Body",
|
||||
"ag:category_substitutions" : "activegrid.server.layoutrenderer.CategorySubstitutions",
|
||||
"ag:command" : "activegrid.model.wsdl.Command",
|
||||
"ag:setElement" : "activegrid.model.processmodel.SetElementOperation",
|
||||
"ag:css" : "activegrid.server.layoutrenderer.CSS",
|
||||
"ag:cssRule" : "activegrid.model.processmodel.CssRule",
|
||||
"ag:databaseService" : "activegrid.server.deployment.DatabaseService",
|
||||
"ag:datasource" : "activegrid.data.dataservice.DataSource",
|
||||
"ag:dataObjectList" : "activegrid.data.datalang.DataObjectList",
|
||||
"ag:debug" : "activegrid.model.processmodel.DebugOperation",
|
||||
"ag:deployment" : "activegrid.server.deployment.Deployment",
|
||||
"ag:formData" : "activegrid.model.processmodel.FormData",
|
||||
"ag:formVar" : "activegrid.model.processmodel.FormVar",
|
||||
"ag:generator" : "activegrid.server.layoutrenderer.SerializableGenerator",
|
||||
"ag:head" : "activegrid.server.layoutrenderer.Head",
|
||||
"ag:hr" : "activegrid.model.processmodel.HorizontalRow",
|
||||
"ag:identity" : "activegrid.model.identitymodel.Identity",
|
||||
"ag:identityref" : "activegrid.server.deployment.IdentityRef",
|
||||
"ag:image" : "activegrid.model.processmodel.Image",
|
||||
"ag:inputPart" : "activegrid.model.processmodel.InputPart",
|
||||
"ag:keystore" : "activegrid.model.identitymodel.KeyStore",
|
||||
"ag:label" : "activegrid.model.processmodel.Label",
|
||||
"ag:layout" : "activegrid.server.layoutrenderer.Layout",
|
||||
"ag:layouts" : "activegrid.server.layoutrenderer.Layouts",
|
||||
@@ -246,9 +227,11 @@ def getAgXsdToClassName():
|
||||
"ag:localService" : "activegrid.server.deployment.LocalService",
|
||||
"ag:parameter" : "activegrid.server.layoutrenderer.Parameter",
|
||||
"ag:parameters" : "activegrid.server.layoutrenderer.Parameters",
|
||||
"ag:postInitialize" : "activegrid.model.processmodel.PostInitialize",
|
||||
"ag:processref" : "activegrid.server.deployment.ProcessRef",
|
||||
"ag:query" : "activegrid.model.processmodel.Query",
|
||||
"ag:soapService" : "activegrid.server.deployment.SoapService",
|
||||
"ag:redirect" : "activegrid.server.layoutrenderer.Redirect",
|
||||
"ag:requiredFile" : "activegrid.server.layoutrenderer.RequiredFile",
|
||||
"ag:resource" : "activegrid.model.identitymodel.IDResource",
|
||||
"ag:restService" : "activegrid.server.deployment.RestService",
|
||||
@@ -355,27 +338,38 @@ def getAgXsdToClassName():
|
||||
"xforms:xforms" : "activegrid.model.processmodel.XFormsRoot",
|
||||
"xs:all" : "activegrid.model.schema.XsdSequence",
|
||||
"xs:any" : "activegrid.model.schema.XsdAny",
|
||||
"xs:anyAttribute" : "activegrid.model.schema.XsdAnyAttribute",
|
||||
"xs:attribute" : "activegrid.model.schema.XsdAttribute",
|
||||
"xs:choice" : "activegrid.model.schema.XsdChoice",
|
||||
"xs:complexContent" : "activegrid.model.schema.XsdComplexContent",
|
||||
"xs:complexType" : "activegrid.model.schema.XsdComplexType",
|
||||
"xs:documentation" : "activegrid.model.schema.XsdDocumentation",
|
||||
"xs:element" : "activegrid.model.schema.XsdElement",
|
||||
"xs:enumeration" : "activegrid.model.schema.XsdEnumeration",
|
||||
"xs:enumeration" : "activegrid.model.schema.XsdFacetEnumeration",
|
||||
"xs:extension" : "activegrid.model.schema.XsdExtension",
|
||||
"xs:fractionDigits" : "activegrid.model.schema.XsdFacetFractionDigits",
|
||||
"xs:field" : "activegrid.model.schema.XsdKeyField",
|
||||
"xs:import" : "activegrid.model.schema.XsdInclude",
|
||||
"xs:include" : "activegrid.model.schema.XsdInclude",
|
||||
"xs:key" : "activegrid.model.schema.XsdKey",
|
||||
"xs:keyref" : "activegrid.model.schema.XsdKeyRef",
|
||||
"xs:length" : "activegrid.model.schema.XsdLength",
|
||||
"xs:length" : "activegrid.model.schema.XsdFacetLength",
|
||||
"xs:list" : "activegrid.model.schema.XsdList",
|
||||
"xs:maxLength" : "activegrid.model.schema.XsdMaxLength",
|
||||
"xs:maxExclusive" : "activegrid.model.schema.XsdFacetMaxExclusive",
|
||||
"xs:maxInclusive" : "activegrid.model.schema.XsdFacetMaxInclusive",
|
||||
"xs:maxLength" : "activegrid.model.schema.XsdFacetMaxLength",
|
||||
"xs:minExclusive" : "activegrid.model.schema.XsdFacetMinExclusive",
|
||||
"xs:minInclusive" : "activegrid.model.schema.XsdFacetMinInclusive",
|
||||
"xs:minLength" : "activegrid.model.schema.XsdFacetMinLength",
|
||||
"xs:pattern" : "activegrid.model.schema.XsdFacetPattern",
|
||||
"xs:restriction" : "activegrid.model.schema.XsdRestriction",
|
||||
"xs:schema" : "activegrid.model.schema.Schema",
|
||||
"xs:selector" : "activegrid.model.schema.XsdKeySelector",
|
||||
"xs:sequence" : "activegrid.model.schema.XsdSequence",
|
||||
"xs:simpleContent" : "activegrid.model.schema.XsdSimpleContent",
|
||||
"xs:simpleType" : "activegrid.model.schema.XsdSimpleType",
|
||||
"xs:totalDigits" : "activegrid.model.schema.XsdTotalDigits",
|
||||
"xs:totalDigits" : "activegrid.model.schema.XsdFacetTotalDigits",
|
||||
"xs:whiteSpace" : "activegrid.model.schema.XsdFacetWhiteSpace",
|
||||
}
|
||||
return agXsdToClassName
|
||||
|
||||
|
@@ -121,6 +121,7 @@ class FindService(wx.lib.pydocview.DocService):
|
||||
self._findDialog = None
|
||||
|
||||
self._replaceDialog = FindReplaceDialog(self.GetDocumentManager().FindSuitableParent(), -1, _("Replace"), size=(320,200), findString=findString)
|
||||
self._replaceDialog.CenterOnParent()
|
||||
self._replaceDialog.Show(True)
|
||||
else:
|
||||
if self._replaceDialog != None:
|
||||
@@ -129,6 +130,7 @@ class FindService(wx.lib.pydocview.DocService):
|
||||
self._replaceDialog = None
|
||||
|
||||
self._findDialog = FindDialog(self.GetDocumentManager().FindSuitableParent(), -1, _("Find"), size=(320,200), findString=findString)
|
||||
self._findDialog.CenterOnParent()
|
||||
self._findDialog.Show(True)
|
||||
|
||||
|
||||
@@ -152,6 +154,7 @@ class FindService(wx.lib.pydocview.DocService):
|
||||
""" Display Goto Line Number dialog box """
|
||||
line = -1
|
||||
dialog = wx.TextEntryDialog(parent, _("Enter line number to go to:"), _("Go to Line"))
|
||||
dialog.CenterOnParent()
|
||||
if dialog.ShowModal() == wx.ID_OK:
|
||||
try:
|
||||
line = int(dialog.GetValue())
|
||||
@@ -356,7 +359,10 @@ class FindDialog(wx.Dialog):
|
||||
wx.EVT_BUTTON(self, FindService.FINDONE_ID, self.OnActionEvent)
|
||||
cancelBtn = wx.Button(self, wx.ID_CANCEL)
|
||||
wx.EVT_BUTTON(self, wx.ID_CANCEL, self.OnClose)
|
||||
buttonSizer.Add(findBtn, 0, wx.BOTTOM, HALF_SPACE)
|
||||
BTM_SPACE = HALF_SPACE
|
||||
if wx.Platform == "__WXMAC__":
|
||||
BTM_SPACE = SPACE
|
||||
buttonSizer.Add(findBtn, 0, wx.BOTTOM, BTM_SPACE)
|
||||
buttonSizer.Add(cancelBtn, 0)
|
||||
gridSizer.Add(buttonSizer, pos=(0,2), span=(3,1))
|
||||
|
||||
@@ -455,9 +461,14 @@ class FindReplaceDialog(FindDialog):
|
||||
wx.EVT_BUTTON(self, FindService.REPLACEONE_ID, self.OnActionEvent)
|
||||
replaceAllBtn = wx.Button(self, FindService.REPLACEALL_ID, _("Replace All"))
|
||||
wx.EVT_BUTTON(self, FindService.REPLACEALL_ID, self.OnActionEvent)
|
||||
buttonSizer.Add(findBtn, 0, wx.BOTTOM, HALF_SPACE)
|
||||
buttonSizer.Add(replaceBtn, 0, wx.BOTTOM, HALF_SPACE)
|
||||
buttonSizer.Add(replaceAllBtn, 0, wx.BOTTOM, HALF_SPACE)
|
||||
|
||||
BTM_SPACE = HALF_SPACE
|
||||
if wx.Platform == "__WXMAC__":
|
||||
BTM_SPACE = SPACE
|
||||
|
||||
buttonSizer.Add(findBtn, 0, wx.BOTTOM, BTM_SPACE)
|
||||
buttonSizer.Add(replaceBtn, 0, wx.BOTTOM, BTM_SPACE)
|
||||
buttonSizer.Add(replaceAllBtn, 0, wx.BOTTOM, BTM_SPACE)
|
||||
buttonSizer.Add(cancelBtn, 0)
|
||||
gridSizer.Add(buttonSizer, pos=(0,2), span=(3,1))
|
||||
|
||||
@@ -495,12 +506,24 @@ def getFindData():
|
||||
return \
|
||||
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
|
||||
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
|
||||
\x00\x00\x81IDAT8\x8d\xa5S\xc1\x16\xc0\x10\x0ckk\xff\xff\xc7d\x87\xad^U\r\
|
||||
\x93S\xe5U$\n\xb3$:\xc1e\x17(\x19Z\xb3$\x9e\xf1DD\xe2\x15\x01x\xea\x93\xef\
|
||||
\x04\x989\xea\x1b\xf2U\xc0\xda\xb4\xeb\x11\x1f:\xd8\xb5\xff8\x93\xd4\xa9\xae\
|
||||
@/S\xaaUwJ3\x85\xc0\x81\xee\xeb.q\x17C\x81\xd5XU \x1a\x93\xc6\x18\x8d\x90\
|
||||
\xe8}\x89\x00\x9a&\x9b_k\x94\x0c\xdf\xd78\xf8\x0b\x99Y\xb4\x08c\x9e\xfe\xc6\
|
||||
\xe3\x087\xf9\xd0D\x180\xf1#\x8e\x00\x00\x00\x00IEND\xaeB`\x82'
|
||||
\x00\x01\xb1IDAT8\x8d\xa5\x93=o\xd3P\x14\x86\x1f\xa7\x11\x95<\xdc\xc6\xecN+5\
|
||||
[\x86B\x99\xacLQ2Zr[\x89\xa1\xfd\x0b%\x95\x90\x00\xf1\x03\x80\x01\x98\x80\
|
||||
\x19G\xac\x0cm\xff@Y\xd9:\xd9Ck\x94\xd6\xddb\x94\x9b\x98\xc8\xd2e1C\xe5\x8b\
|
||||
\xdd\x14\x96\xbe\xdb=\x1f\xefy\xef\xf90\x8c\xda\x12wA\xbd\xfc\x18\xfa\x9fs\
|
||||
\x80\xf9|\x0e\xc0\x93\xc1\x81\x01\xf0\xe6\xf5\xab\x1c`:\x9d\x02\xf0\xf6\xdd{\
|
||||
\xa3\xc8\xa9\xddd\xec\xf5z\xb4Z\xeb\x00\x1c\x1f\x1d\xe6\x85\xdd\xf3<\x06\x83\
|
||||
\xc1\x82\xbd\xa2 \x0cCL\xd3d<\x1e\x13\xc71\xb6m\x030\x1a\x8d\x08\x82\x00\x80\
|
||||
\xb3\xb3s:\x9d\x8e\xce\xa9(h6\x9b8\x8e\x83m\xdb4\x1a\r\x82 \xe0\xc5\xf3g\xb9\
|
||||
eY\xb4\xdbm\x1c\xc7Y\xe8\x81&\xf8\xf4\xf1C\xde\xedv+\xce\x97Owx\xfc\xe8k\xc5\
|
||||
\xb6\xb7\xb7\x8b\xef\x0foW \x84\xe0\xea\xea\x02\xa5\x94n\x18\x80\x94\x92\xd9\
|
||||
l\x02@\x96e\x95>\xd4nVO\xd3\xb9\x0e\xba\r\xa6i\xd2\xef\xf7\xf0\xfd!\xc7G\x87\
|
||||
y\xed:)\xd5\x01J\xfd\xd6c\xfc~\x9a\xfc\x93\xe8\xf2\xf2\x02(Ma6\x9b \x84@)\
|
||||
\xa5\t}\xff\x0b\xd0\'I~R\x14\xca\xb2L\xfb\x97\x97\xef-\xeeA!_J\x89\xeb\xba\
|
||||
\xb8\xae\xab\xbf\x06\x7f\x97\xacP[\x87\xeb9\x0b!H\x92\ta\x18"\xa5\xd4U\xbd\
|
||||
\xadm\xe3\xe1\x83\x8d<\x8a~\x90\xa6\xbf\x88\xe3\x18)\xa5&\xa9\x03X\x96E\xab\
|
||||
\xb5\x8em7\xf5\xc2\x94\xb1\xba\xba\xc6\xe6\xe6\x06++\xf7\x89\xa2\xa8\xe2\xd3\
|
||||
=89\xf9Va.\x14\x14\xd8\xdf?X VJa\x14\xd7X\xde\xef2\xbc\xadm\xe3\x7f~\xe3\xae\
|
||||
\xe7\xfc\x07\x84;\xc5\x82\xa1m&\x95\x00\x00\x00\x00IEND\xaeB`\x82'
|
||||
|
||||
|
||||
def getFindBitmap():
|
||||
|
@@ -18,44 +18,44 @@ _ = wx.GetTranslation
|
||||
|
||||
class TextDocument(wx.lib.docview.Document):
|
||||
|
||||
def __init__(self):
|
||||
wx.lib.docview.Document .__init__(self)
|
||||
self._inModify = False
|
||||
|
||||
def OnSaveDocument(self, filename):
|
||||
|
||||
def SaveObject(self, fileObject):
|
||||
view = self.GetFirstView()
|
||||
if not view.GetTextCtrl().SaveFile(filename):
|
||||
return False
|
||||
self.Modify(False)
|
||||
self.SetDocumentSaved(True)
|
||||
#if wx.Platform == "__WXMAC__":
|
||||
# fn = wx.Filename(filename)
|
||||
# fn.MacSetDefaultTypeAndCreator()
|
||||
fileObject.write(view.GetTextCtrl().GetValue())
|
||||
return True
|
||||
|
||||
|
||||
def OnOpenDocument(self, filename):
|
||||
def LoadObject(self, fileObject):
|
||||
view = self.GetFirstView()
|
||||
if not view.GetTextCtrl().LoadFile(filename):
|
||||
return False
|
||||
self.SetFilename(filename, True)
|
||||
self.Modify(False)
|
||||
self.UpdateAllViews()
|
||||
self._savedYet = True
|
||||
data = fileObject.read()
|
||||
view.GetTextCtrl().SetValue(data)
|
||||
return True
|
||||
|
||||
|
||||
def IsModified(self):
|
||||
view = self.GetFirstView()
|
||||
if view and view.GetTextCtrl():
|
||||
return wx.lib.docview.Document.IsModified(self) or view.GetTextCtrl().IsModified()
|
||||
else:
|
||||
return wx.lib.docview.Document.IsModified(self)
|
||||
return view.GetTextCtrl().IsModified()
|
||||
return False
|
||||
|
||||
|
||||
def Modify(self, mod):
|
||||
def Modify(self, modify):
|
||||
if self._inModify:
|
||||
return
|
||||
self._inModify = True
|
||||
|
||||
view = self.GetFirstView()
|
||||
wx.lib.docview.Document.Modify(self, mod)
|
||||
if not mod and view and view.GetTextCtrl():
|
||||
if not modify and view and view.GetTextCtrl():
|
||||
view.GetTextCtrl().DiscardEdits()
|
||||
|
||||
wx.lib.docview.Document.Modify(self, modify) # this must called be after the DiscardEdits call above.
|
||||
|
||||
self._inModify = False
|
||||
|
||||
|
||||
class TextView(wx.lib.docview.View):
|
||||
|
||||
@@ -75,6 +75,7 @@ class TextView(wx.lib.docview.View):
|
||||
sizer = wx.BoxSizer()
|
||||
font, color = self._GetFontAndColorFromConfig()
|
||||
self._textCtrl = self._BuildTextCtrl(frame, font, color = color)
|
||||
self._textCtrl.Bind(wx.EVT_TEXT, self.OnModify)
|
||||
sizer.Add(self._textCtrl, 1, wx.EXPAND, 0)
|
||||
frame.SetSizer(sizer)
|
||||
frame.Layout()
|
||||
@@ -83,6 +84,10 @@ class TextView(wx.lib.docview.View):
|
||||
return True
|
||||
|
||||
|
||||
def OnModify(self, event):
|
||||
self.GetDocument().Modify(True)
|
||||
|
||||
|
||||
def _BuildTextCtrl(self, parent, font, color = wx.BLACK, value = "", selection = [0, 0]):
|
||||
if self._wordWrap:
|
||||
wordWrapStyle = wx.TE_WORDWRAP
|
||||
@@ -131,6 +136,9 @@ class TextView(wx.lib.docview.View):
|
||||
|
||||
|
||||
def OnUpdate(self, sender = None, hint = None):
|
||||
if wx.lib.docview.View.OnUpdate(self, sender, hint):
|
||||
return
|
||||
|
||||
if hint == "Word Wrap":
|
||||
self.SetWordWrap(wx.ConfigBase_Get().ReadInt("TextEditorWordWrap", True))
|
||||
elif hint == "Font":
|
||||
|
@@ -6,7 +6,7 @@
|
||||
#
|
||||
# Created: 5/15/03
|
||||
# CVS-ID: $Id$
|
||||
# Copyright: (c) 2003-2005 ActiveGrid, Inc. (Port of wxWindows classes by Julian Smart et al)
|
||||
# Copyright: (c) 2003-2006 ActiveGrid, Inc. (Port of wxWindows classes by Julian Smart et al)
|
||||
# License: wxWindows license
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
@@ -214,8 +214,10 @@ class Document(wx.EvtHandler):
|
||||
false otherwise. You may need to override this if your document view
|
||||
maintains its own record of being modified (for example if using
|
||||
xTextWindow to view and edit the document).
|
||||
This method has been extended to notify its views that the dirty flag has changed.
|
||||
"""
|
||||
self._documentModified = modify
|
||||
self.UpdateAllViews(hint=("modify", self, self._documentModified))
|
||||
|
||||
|
||||
def SetDocumentModificationDate(self):
|
||||
@@ -236,6 +238,16 @@ class Document(wx.EvtHandler):
|
||||
return self._documentModificationDate
|
||||
|
||||
|
||||
def IsDocumentModificationDateCorrect(self):
|
||||
"""
|
||||
Returns False if the file has been modified outside of the application.
|
||||
This method has been added to wxPython and is not in wxWindows.
|
||||
"""
|
||||
if not os.path.exists(self.GetFilename()): # document must be in memory only and can't be out of date
|
||||
return True
|
||||
return self._documentModificationDate == os.path.getmtime(self.GetFilename())
|
||||
|
||||
|
||||
def GetViews(self):
|
||||
"""
|
||||
Returns the list whose elements are the views on the document.
|
||||
@@ -271,6 +283,7 @@ class Document(wx.EvtHandler):
|
||||
Destructor. Removes itself from the document manager.
|
||||
"""
|
||||
self.DeleteContents()
|
||||
self._documentModificationDate = None
|
||||
if self.GetDocumentManager():
|
||||
self.GetDocumentManager().RemoveDocument(self)
|
||||
wx.EvtHandler.Destroy(self)
|
||||
@@ -364,7 +377,7 @@ class Document(wx.EvtHandler):
|
||||
return True
|
||||
|
||||
""" check for file modification outside of application """
|
||||
if os.path.exists(self.GetFilename()) and os.path.getmtime(self.GetFilename()) != self.GetDocumentModificationDate():
|
||||
if not self.IsDocumentModificationDateCorrect():
|
||||
msgTitle = wx.GetApp().GetAppName()
|
||||
if not msgTitle:
|
||||
msgTitle = _("Application")
|
||||
@@ -485,9 +498,9 @@ class Document(wx.EvtHandler):
|
||||
self.GetDocumentWindow())
|
||||
return False
|
||||
|
||||
self.SetDocumentModificationDate()
|
||||
self.SetFilename(filename, True)
|
||||
self.Modify(False)
|
||||
self.SetDocumentModificationDate()
|
||||
self.SetDocumentSaved(True)
|
||||
#if wx.Platform == '__WXMAC__': # Not yet implemented in wxPython
|
||||
# wx.FileName(file).MacSetDefaultTypeAndCreator()
|
||||
@@ -529,9 +542,9 @@ class Document(wx.EvtHandler):
|
||||
self.GetDocumentWindow())
|
||||
return False
|
||||
|
||||
self.SetDocumentModificationDate()
|
||||
self.SetFilename(filename, True)
|
||||
self.Modify(False)
|
||||
self.SetDocumentModificationDate()
|
||||
self.SetDocumentSaved(True)
|
||||
self.UpdateAllViews()
|
||||
return True
|
||||
@@ -614,7 +627,7 @@ class Document(wx.EvtHandler):
|
||||
return True
|
||||
|
||||
""" check for file modification outside of application """
|
||||
if os.path.exists(self.GetFilename()) and os.path.getmtime(self.GetFilename()) != self.GetDocumentModificationDate():
|
||||
if not self.IsDocumentModificationDateCorrect():
|
||||
msgTitle = wx.GetApp().GetAppName()
|
||||
if not msgTitle:
|
||||
msgTitle = _("Warning")
|
||||
@@ -844,7 +857,13 @@ class View(wx.EvtHandler):
|
||||
unused but may in future contain application-specific information for
|
||||
making updating more efficient.
|
||||
"""
|
||||
pass
|
||||
if hint:
|
||||
if hint[0] == "modify": # if dirty flag changed, update the view's displayed title
|
||||
frame = self.GetFrame()
|
||||
if frame and hasattr(frame, "OnTitleIsModified"):
|
||||
frame.OnTitleIsModified()
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def OnChangeFilename(self):
|
||||
@@ -916,11 +935,11 @@ class View(wx.EvtHandler):
|
||||
Call this from your view frame's OnActivate member to tell the
|
||||
framework which view is currently active. If your windowing system
|
||||
doesn't call OnActivate, you may need to call this function from
|
||||
any place where you know the view must be active, and
|
||||
OnMenuCommand or any place where you know the view must be active, and
|
||||
the framework will need to get the current view.
|
||||
|
||||
The prepackaged view frame wxDocChildFrame calls wxView.Activate from
|
||||
its OnActivate member.
|
||||
its OnActivate member and from its OnMenuCommand member.
|
||||
"""
|
||||
if self.GetDocument() and self.GetDocumentManager():
|
||||
self.OnActivateView(activate, self, self.GetDocumentManager().GetCurrentView())
|
||||
@@ -1865,7 +1884,7 @@ class DocManager(wx.EvtHandler):
|
||||
for document in self._docs:
|
||||
if document.GetFilename() and os.path.normcase(document.GetFilename()) == os.path.normcase(path):
|
||||
""" check for file modification outside of application """
|
||||
if os.path.exists(path) and os.path.getmtime(path) != document.GetDocumentModificationDate():
|
||||
if not document.IsDocumentModificationDateCorrect():
|
||||
msgTitle = wx.GetApp().GetAppName()
|
||||
if not msgTitle:
|
||||
msgTitle = _("Warning")
|
||||
@@ -2148,7 +2167,7 @@ class DocManager(wx.EvtHandler):
|
||||
if len(descr) > 0:
|
||||
descr = descr + _('|')
|
||||
descr = descr + temp.GetDescription() + _(" (") + temp.GetFileFilter() + _(") |") + temp.GetFileFilter() # spacing is important, make sure there is no space after the "|", it causes a bug on wx_gtk
|
||||
descr = _("All (*.*)|*.*|%s") % descr # spacing is important, make sure there is no space after the "|", it causes a bug on wx_gtk
|
||||
descr = _("All|*.*|%s") % descr # spacing is important, make sure there is no space after the "|", it causes a bug on wx_gtk
|
||||
else:
|
||||
descr = _("*.*")
|
||||
|
||||
@@ -2791,6 +2810,7 @@ class DocMDIChildFrame(wx.MDIChildFrame):
|
||||
self._childView.Activate(event.GetActive())
|
||||
self._activated = 0
|
||||
|
||||
|
||||
def OnCloseWindow(self, event):
|
||||
"""
|
||||
Closes and deletes the current view and document.
|
||||
@@ -2846,6 +2866,28 @@ class DocMDIChildFrame(wx.MDIChildFrame):
|
||||
self._childView = view
|
||||
|
||||
|
||||
def OnTitleIsModified(self):
|
||||
"""
|
||||
Add/remove to the frame's title an indication that the document is dirty.
|
||||
If the document is dirty, an '*' is appended to the title
|
||||
This method has been added to wxPython and is not in wxWindows.
|
||||
"""
|
||||
title = self.GetTitle()
|
||||
if title:
|
||||
if self.GetDocument().IsModified():
|
||||
if title.endswith("*"):
|
||||
return
|
||||
else:
|
||||
title = title + "*"
|
||||
self.SetTitle(title)
|
||||
else:
|
||||
if title.endswith("*"):
|
||||
title = title[:-1]
|
||||
self.SetTitle(title)
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
class DocPrintout(wx.Printout):
|
||||
"""
|
||||
DocPrintout is a default Printout that prints the first page of a document
|
||||
@@ -2892,15 +2934,6 @@ class DocPrintout(wx.Printout):
|
||||
return pageNum == 1
|
||||
|
||||
|
||||
def OnBeginDocument(self, startPage, endPage):
|
||||
"""
|
||||
Not quite sure why this was overridden, but it was in wxWindows! :)
|
||||
"""
|
||||
if not wx.Printout.OnBeginDocument(self, startPage, endPage):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def GetPageInfo(self):
|
||||
"""
|
||||
Indicates that the DocPrintout only has a single page.
|
||||
|
@@ -2,11 +2,11 @@
|
||||
# Name: pydocview.py
|
||||
# Purpose: Python extensions to the wxWindows docview framework
|
||||
#
|
||||
# Author: Peter Yared, Morgan Hua
|
||||
# Author: Peter Yared, Morgan Hua, Matt Fryer
|
||||
#
|
||||
# Created: 5/15/03
|
||||
# CVS-ID: $Id$
|
||||
# Copyright: (c) 2003-2005 ActiveGrid, Inc.
|
||||
# Copyright: (c) 2003-2006 ActiveGrid, Inc.
|
||||
# License: wxWindows license
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
@@ -281,7 +281,7 @@ class DocMDIParentFrameMixIn:
|
||||
return pos, size
|
||||
|
||||
|
||||
def _InitFrame(self, embeddedWindows):
|
||||
def _InitFrame(self, embeddedWindows, minSize):
|
||||
"""
|
||||
Initializes the frame and creates the default menubar, toolbar, and status bar.
|
||||
"""
|
||||
@@ -306,7 +306,7 @@ class DocMDIParentFrameMixIn:
|
||||
# wxBug: On maximize, statusbar leaves a residual that needs to be refereshed, happens even when user does it
|
||||
self.Maximize()
|
||||
|
||||
self.CreateEmbeddedWindows(embeddedWindows)
|
||||
self.CreateEmbeddedWindows(embeddedWindows, minSize)
|
||||
self._LayoutFrame()
|
||||
|
||||
if wx.Platform == '__WXMAC__':
|
||||
@@ -374,18 +374,17 @@ class DocMDIParentFrameMixIn:
|
||||
return wx.GetApp().ProcessUpdateUIEvent(event)
|
||||
|
||||
|
||||
def CreateEmbeddedWindows(self, windows=0):
|
||||
def CreateEmbeddedWindows(self, windows=0, minSize=20):
|
||||
"""
|
||||
Create the specified embedded windows around the edges of the frame.
|
||||
"""
|
||||
frameSize = self.GetSize() # TODO: GetClientWindow.GetSize is still returning 0,0 since the frame isn't fully constructed yet, so using full frame size
|
||||
MIN_SIZE = 20
|
||||
defaultHSize = max(MIN_SIZE, int(frameSize[0] / 6))
|
||||
defaultVSize = max(MIN_SIZE, int(frameSize[1] / 7))
|
||||
defaultHSize = max(minSize, int(frameSize[0] / 6))
|
||||
defaultVSize = max(minSize, int(frameSize[1] / 7))
|
||||
defaultSubVSize = int(frameSize[1] / 2)
|
||||
config = wx.ConfigBase_Get()
|
||||
if windows & (EMBEDDED_WINDOW_LEFT | EMBEDDED_WINDOW_TOPLEFT | EMBEDDED_WINDOW_BOTTOMLEFT):
|
||||
self._leftEmbWindow = self._CreateEmbeddedWindow(self, (max(MIN_SIZE,config.ReadInt("MDIEmbedLeftSize", defaultHSize)), -1), wx.LAYOUT_VERTICAL, wx.LAYOUT_LEFT, visible = config.ReadInt("MDIEmbedLeftVisible", 1), sash = wx.SASH_RIGHT)
|
||||
self._leftEmbWindow = self._CreateEmbeddedWindow(self, (max(minSize,config.ReadInt("MDIEmbedLeftSize", defaultHSize)), -1), wx.LAYOUT_VERTICAL, wx.LAYOUT_LEFT, visible = config.ReadInt("MDIEmbedLeftVisible", 1), sash = wx.SASH_RIGHT)
|
||||
else:
|
||||
self._leftEmbWindow = None
|
||||
if windows & EMBEDDED_WINDOW_TOPLEFT:
|
||||
@@ -397,7 +396,7 @@ class DocMDIParentFrameMixIn:
|
||||
else:
|
||||
self._bottomLeftEmbWindow = None
|
||||
if windows & (EMBEDDED_WINDOW_RIGHT | EMBEDDED_WINDOW_TOPRIGHT | EMBEDDED_WINDOW_BOTTOMRIGHT):
|
||||
self._rightEmbWindow = self._CreateEmbeddedWindow(self, (max(MIN_SIZE,config.ReadInt("MDIEmbedRightSize", defaultHSize)), -1), wx.LAYOUT_VERTICAL, wx.LAYOUT_RIGHT, visible = config.ReadInt("MDIEmbedRightVisible", 1), sash = wx.SASH_LEFT)
|
||||
self._rightEmbWindow = self._CreateEmbeddedWindow(self, (max(minSize,config.ReadInt("MDIEmbedRightSize", defaultHSize)), -1), wx.LAYOUT_VERTICAL, wx.LAYOUT_RIGHT, visible = config.ReadInt("MDIEmbedRightVisible", 1), sash = wx.SASH_LEFT)
|
||||
else:
|
||||
self._rightEmbWindow = None
|
||||
if windows & EMBEDDED_WINDOW_TOPRIGHT:
|
||||
@@ -409,11 +408,11 @@ class DocMDIParentFrameMixIn:
|
||||
else:
|
||||
self._bottomRightEmbWindow = None
|
||||
if windows & EMBEDDED_WINDOW_TOP:
|
||||
self._topEmbWindow = self._CreateEmbeddedWindow(self, (-1, max(MIN_SIZE,config.ReadInt("MDIEmbedTopSize", defaultVSize))), wx.LAYOUT_HORIZONTAL, wx.LAYOUT_TOP, visible = config.ReadInt("MDIEmbedTopVisible", 1), sash = wx.SASH_BOTTOM)
|
||||
self._topEmbWindow = self._CreateEmbeddedWindow(self, (-1, max(minSize,config.ReadInt("MDIEmbedTopSize", defaultVSize))), wx.LAYOUT_HORIZONTAL, wx.LAYOUT_TOP, visible = config.ReadInt("MDIEmbedTopVisible", 1), sash = wx.SASH_BOTTOM)
|
||||
else:
|
||||
self._topEmbWindow = None
|
||||
if windows & EMBEDDED_WINDOW_BOTTOM:
|
||||
self._bottomEmbWindow = self._CreateEmbeddedWindow(self, (-1, max(MIN_SIZE,config.ReadInt("MDIEmbedBottomSize", defaultVSize))), wx.LAYOUT_HORIZONTAL, wx.LAYOUT_BOTTOM, visible = config.ReadInt("MDIEmbedBottomVisible", 1), sash = wx.SASH_TOP)
|
||||
self._bottomEmbWindow = self._CreateEmbeddedWindow(self, (-1, max(minSize,config.ReadInt("MDIEmbedBottomSize", defaultVSize))), wx.LAYOUT_HORIZONTAL, wx.LAYOUT_BOTTOM, visible = config.ReadInt("MDIEmbedBottomVisible", 1), sash = wx.SASH_TOP)
|
||||
else:
|
||||
self._bottomEmbWindow = None
|
||||
|
||||
@@ -664,6 +663,23 @@ class DocTabbedChildFrame(wx.Panel):
|
||||
wx.GetApp().GetTopWindow().SetNotebookPageTitle(self, title)
|
||||
|
||||
|
||||
def OnTitleIsModified(self):
|
||||
"""
|
||||
Add/remove to the frame's title an indication that the document is dirty.
|
||||
If the document is dirty, an '*' is appended to the title
|
||||
"""
|
||||
title = self.GetTitle()
|
||||
if title:
|
||||
if self.GetDocument().IsModified():
|
||||
if not title.endswith("*"):
|
||||
title = title + "*"
|
||||
self.SetTitle(title)
|
||||
else:
|
||||
if title.endswith("*"):
|
||||
title = title[:-1]
|
||||
self.SetTitle(title)
|
||||
|
||||
|
||||
def ProcessEvent(event):
|
||||
"""
|
||||
Processes an event, searching event tables and calling zero or more
|
||||
@@ -719,7 +735,7 @@ class DocTabbedParentFrame(wx.Frame, DocFrameMixIn, DocMDIParentFrameMixIn):
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, docManager, frame, id, title, pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE, name = "DocTabbedParentFrame", embeddedWindows = 0):
|
||||
def __init__(self, docManager, frame, id, title, pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE, name = "DocTabbedParentFrame", embeddedWindows = 0, minSize=20):
|
||||
"""
|
||||
Constructor. Note that the event table must be rebuilt for the
|
||||
frame since the EvtHandler is not virtual.
|
||||
@@ -764,7 +780,7 @@ class DocTabbedParentFrame(wx.Frame, DocFrameMixIn, DocMDIParentFrameMixIn):
|
||||
# End From docview.MDIParentFrame
|
||||
|
||||
self.CreateNotebook()
|
||||
self._InitFrame(embeddedWindows)
|
||||
self._InitFrame(embeddedWindows, minSize)
|
||||
|
||||
|
||||
def _LayoutFrame(self):
|
||||
@@ -852,7 +868,9 @@ class DocTabbedParentFrame(wx.Frame, DocFrameMixIn, DocMDIParentFrameMixIn):
|
||||
|
||||
if index > -1:
|
||||
doc = self._notebook.GetPage(index).GetView().GetDocument()
|
||||
self._notebook.SetToolTip(wx.ToolTip(doc.GetFilename()))
|
||||
# wxBug: Tooltips no longer appearing on tabs except on
|
||||
# about a 2 pixel area between tab top and contents that will show tip.
|
||||
self._notebook.GetParent().SetToolTip(wx.ToolTip(doc.GetFilename()))
|
||||
else:
|
||||
self._notebook.SetToolTip(wx.ToolTip(""))
|
||||
event.Skip()
|
||||
@@ -945,6 +963,9 @@ class DocTabbedParentFrame(wx.Frame, DocFrameMixIn, DocMDIParentFrameMixIn):
|
||||
|
||||
self._notebook.Layout()
|
||||
|
||||
windowMenuService = wx.GetApp().GetService(WindowMenuService)
|
||||
if windowMenuService:
|
||||
windowMenuService.BuildWindowMenu(wx.GetApp().GetTopWindow()) # build file menu list when we open a file
|
||||
|
||||
|
||||
def RemoveNotebookPage(self, panel):
|
||||
@@ -953,7 +974,18 @@ class DocTabbedParentFrame(wx.Frame, DocFrameMixIn, DocMDIParentFrameMixIn):
|
||||
"""
|
||||
index = self.GetNotebookPageIndex(panel)
|
||||
if index > -1:
|
||||
if self._notebook.GetPageCount() == 1 or index < 2:
|
||||
pass
|
||||
elif index >= 1:
|
||||
self._notebook.SetSelection(index - 1)
|
||||
elif index < self._notebook.GetPageCount():
|
||||
self._notebook.SetSelection(index + 1)
|
||||
self._notebook.DeletePage(index)
|
||||
self._notebook.GetParent().SetToolTip(wx.ToolTip(""))
|
||||
|
||||
windowMenuService = wx.GetApp().GetService(WindowMenuService)
|
||||
if windowMenuService:
|
||||
windowMenuService.BuildWindowMenu(wx.GetApp().GetTopWindow()) # build file menu list when we open a file
|
||||
|
||||
|
||||
def ActivateNotebookPage(self, panel):
|
||||
@@ -967,7 +999,11 @@ class DocTabbedParentFrame(wx.Frame, DocFrameMixIn, DocMDIParentFrameMixIn):
|
||||
|
||||
|
||||
def GetNotebookPageTitle(self, panel):
|
||||
index = self.GetNotebookPageIndex(panel)
|
||||
if index != -1:
|
||||
return self._notebook.GetPageText(self.GetNotebookPageIndex(panel))
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def SetNotebookPageTitle(self, panel, title):
|
||||
@@ -1121,6 +1157,27 @@ class DocMDIChildFrame(wx.MDIChildFrame):
|
||||
self._childView.Activate(True)
|
||||
|
||||
|
||||
def OnTitleIsModified(self):
|
||||
"""
|
||||
Add/remove to the frame's title an indication that the document is dirty.
|
||||
If the document is dirty, an '*' is appended to the title
|
||||
"""
|
||||
title = self.GetTitle()
|
||||
if title:
|
||||
if self.GetDocument().IsModified():
|
||||
if title.endswith("*"):
|
||||
return
|
||||
else:
|
||||
title = title + "*"
|
||||
self.SetTitle(title)
|
||||
else:
|
||||
if title.endswith("*"):
|
||||
title = title[:-1]
|
||||
self.SetTitle(title)
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
def ProcessEvent(event):
|
||||
"""
|
||||
Processes an event, searching event tables and calling zero or more
|
||||
@@ -1216,9 +1273,6 @@ class DocMDIChildFrame(wx.MDIChildFrame):
|
||||
self._childView = view
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class DocService(wx.EvtHandler):
|
||||
"""
|
||||
An abstract class used to add reusable services to a docview application.
|
||||
@@ -1544,7 +1598,7 @@ class GeneralOptionsPanel(wx.Panel):
|
||||
choices.append(self._mdiChoice)
|
||||
if wx.Platform == "__WXMSW__":
|
||||
choices.append(self._winMdiChoice)
|
||||
self._documentRadioBox = wx.RadioBox(self, -1, _("Document Interface"),
|
||||
self._documentRadioBox = wx.RadioBox(self, -1, _("Document Display Style"),
|
||||
choices = choices,
|
||||
majorDimension=1,
|
||||
)
|
||||
@@ -1574,7 +1628,7 @@ class GeneralOptionsPanel(wx.Panel):
|
||||
self.SetSizer(optionsBorderSizer)
|
||||
self.Layout()
|
||||
self._documentInterfaceMessageShown = False
|
||||
parent.AddPage(self, _("Options"))
|
||||
parent.AddPage(self, _("General"))
|
||||
|
||||
|
||||
def _AllowModeChanges(self):
|
||||
@@ -2155,7 +2209,7 @@ class _DocFrameFileDropTarget(wx.FileDropTarget):
|
||||
msgTitle = wx.GetApp().GetAppName()
|
||||
if not msgTitle:
|
||||
msgTitle = _("File Error")
|
||||
wx.MessageBox("Could not open '%s'. '%s'" % (docview.FileNameFromPath(file), sys.exc_value),
|
||||
wx.MessageBox("Could not open '%s'. '%s'" % (wx.lib.docview.FileNameFromPath(file), sys.exc_value),
|
||||
msgTitle,
|
||||
wx.OK | wx.ICON_EXCLAMATION,
|
||||
self._docManager.FindSuitableParent())
|
||||
@@ -2169,7 +2223,7 @@ class DocMDIParentFrame(wx.lib.docview.DocMDIParentFrame, DocFrameMixIn, DocMDIP
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, docManager, parent, id, title, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE, name="DocMDIFrame", embeddedWindows=0):
|
||||
def __init__(self, docManager, parent, id, title, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE, name="DocMDIFrame", embeddedWindows=0, minSize=20):
|
||||
"""
|
||||
Initializes the DocMDIParentFrame with the default menubar, toolbar, and status bar. Use the
|
||||
optional embeddedWindows parameter with the embedded window constants to create embedded
|
||||
@@ -2177,7 +2231,7 @@ class DocMDIParentFrame(wx.lib.docview.DocMDIParentFrame, DocFrameMixIn, DocMDIP
|
||||
"""
|
||||
pos, size = self._GetPosSizeFromConfig(pos, size)
|
||||
wx.lib.docview.DocMDIParentFrame.__init__(self, docManager, parent, id, title, pos, size, style, name)
|
||||
self._InitFrame(embeddedWindows)
|
||||
self._InitFrame(embeddedWindows, minSize)
|
||||
|
||||
|
||||
def _LayoutFrame(self):
|
||||
@@ -2795,22 +2849,23 @@ class WindowMenuService(DocService):
|
||||
the WindowMenuService.
|
||||
"""
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Constants
|
||||
#----------------------------------------------------------------------------
|
||||
ARRANGE_WINDOWS_ID = wx.NewId()
|
||||
SELECT_MORE_WINDOWS_ID = wx.NewId()
|
||||
SELECT_NEXT_WINDOW_ID = wx.NewId()
|
||||
SELECT_PREV_WINDOW_ID = wx.NewId()
|
||||
CLOSE_CURRENT_WINDOW_ID = wx.NewId()
|
||||
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Initializes the WindowMenu and its globals.
|
||||
"""
|
||||
self.ARRANGE_WINDOWS_ID = wx.NewId()
|
||||
self.SELECT_WINDOW_1_ID = wx.NewId()
|
||||
self.SELECT_WINDOW_2_ID = wx.NewId()
|
||||
self.SELECT_WINDOW_3_ID = wx.NewId()
|
||||
self.SELECT_WINDOW_4_ID = wx.NewId()
|
||||
self.SELECT_WINDOW_5_ID = wx.NewId()
|
||||
self.SELECT_WINDOW_6_ID = wx.NewId()
|
||||
self.SELECT_WINDOW_7_ID = wx.NewId()
|
||||
self.SELECT_WINDOW_8_ID = wx.NewId()
|
||||
self.SELECT_WINDOW_9_ID = wx.NewId()
|
||||
self.SELECT_MORE_WINDOWS_ID = wx.NewId()
|
||||
self._selectWinIds = []
|
||||
for i in range(0, 9):
|
||||
self._selectWinIds.append(wx.NewId())
|
||||
|
||||
|
||||
def InstallControls(self, frame, menuBar=None, toolBar=None, statusBar=None, document=None):
|
||||
@@ -2818,35 +2873,56 @@ class WindowMenuService(DocService):
|
||||
Installs the Window menu.
|
||||
"""
|
||||
|
||||
if not self.GetDocumentManager().GetFlags() & wx.lib.docview.DOC_SDI:
|
||||
return # Only need windows menu for SDI mode, MDI frame automatically creates one
|
||||
windowMenu = None
|
||||
if hasattr(frame, "GetWindowMenu"):
|
||||
windowMenu = frame.GetWindowMenu()
|
||||
if not windowMenu:
|
||||
needWindowMenu = True
|
||||
windowMenu = wx.Menu()
|
||||
else:
|
||||
needWindowMenu = False
|
||||
|
||||
if self.GetDocumentManager().GetFlags() & wx.lib.docview.DOC_SDI:
|
||||
if not _WINDOWS: # Arrange All and window navigation doesn't work on Linux
|
||||
return
|
||||
|
||||
windowMenu = wx.Menu()
|
||||
item = windowMenu.Append(self.ARRANGE_WINDOWS_ID, _("&Arrange All"), _("Arrange the open windows"))
|
||||
windowMenu.AppendSeparator()
|
||||
|
||||
wx.EVT_MENU(frame, self.ARRANGE_WINDOWS_ID, frame.ProcessEvent)
|
||||
wx.EVT_UPDATE_UI(frame, self.ARRANGE_WINDOWS_ID, frame.ProcessUpdateUIEvent)
|
||||
wx.EVT_MENU(frame, self.SELECT_WINDOW_1_ID, frame.ProcessEvent) # wxNewId may have been nonsequential, so can't use EVT_MENU_RANGE
|
||||
wx.EVT_MENU(frame, self.SELECT_WINDOW_2_ID, frame.ProcessEvent)
|
||||
wx.EVT_MENU(frame, self.SELECT_WINDOW_3_ID, frame.ProcessEvent)
|
||||
wx.EVT_MENU(frame, self.SELECT_WINDOW_4_ID, frame.ProcessEvent)
|
||||
wx.EVT_MENU(frame, self.SELECT_WINDOW_5_ID, frame.ProcessEvent)
|
||||
wx.EVT_MENU(frame, self.SELECT_WINDOW_6_ID, frame.ProcessEvent)
|
||||
wx.EVT_MENU(frame, self.SELECT_WINDOW_7_ID, frame.ProcessEvent)
|
||||
wx.EVT_MENU(frame, self.SELECT_WINDOW_8_ID, frame.ProcessEvent)
|
||||
wx.EVT_MENU(frame, self.SELECT_WINDOW_9_ID, frame.ProcessEvent)
|
||||
wx.EVT_MENU(frame, self.SELECT_MORE_WINDOWS_ID, frame.ProcessEvent)
|
||||
windowMenu.AppendSeparator()
|
||||
|
||||
for i, id in enumerate(self._selectWinIds):
|
||||
wx.EVT_MENU(frame, id, frame.ProcessEvent)
|
||||
wx.EVT_MENU(frame, self.SELECT_MORE_WINDOWS_ID, frame.ProcessEvent)
|
||||
elif wx.GetApp().GetUseTabbedMDI():
|
||||
item = windowMenu.Append(self.SELECT_PREV_WINDOW_ID, _("Previous"), _("Previous Tab"))
|
||||
wx.EVT_MENU(frame, self.SELECT_PREV_WINDOW_ID, frame.ProcessEvent)
|
||||
wx.EVT_UPDATE_UI(frame, self.SELECT_PREV_WINDOW_ID, frame.ProcessUpdateUIEvent)
|
||||
item = windowMenu.Append(self.SELECT_NEXT_WINDOW_ID, _("Next"), _("Next Tab"))
|
||||
wx.EVT_MENU(frame, self.SELECT_NEXT_WINDOW_ID, frame.ProcessEvent)
|
||||
wx.EVT_UPDATE_UI(frame, self.SELECT_NEXT_WINDOW_ID, frame.ProcessUpdateUIEvent)
|
||||
item = windowMenu.Append(self.CLOSE_CURRENT_WINDOW_ID, _("Close Current\tCtrl+F4"), _("Close Current Tab"))
|
||||
wx.EVT_MENU(frame, self.CLOSE_CURRENT_WINDOW_ID, frame.ProcessEvent)
|
||||
wx.EVT_UPDATE_UI(frame, self.CLOSE_CURRENT_WINDOW_ID, frame.ProcessUpdateUIEvent)
|
||||
self._sep = None
|
||||
|
||||
for i, id in enumerate(self._selectWinIds):
|
||||
wx.EVT_MENU(frame, id, self.OnCtrlKeySelect)
|
||||
|
||||
if needWindowMenu:
|
||||
helpMenuIndex = menuBar.FindMenu(_("&Help"))
|
||||
menuBar.Insert(helpMenuIndex, windowMenu, _("&Window"))
|
||||
|
||||
self._lastFrameUpdated = None
|
||||
|
||||
|
||||
def OnCtrlKeySelect(self, event):
|
||||
i = self._selectWinIds.index(event.GetId())
|
||||
notebook = wx.GetApp().GetTopWindow()._notebook
|
||||
if i < notebook.GetPageCount():
|
||||
notebook.SetSelection(i)
|
||||
|
||||
|
||||
def ProcessEvent(self, event):
|
||||
"""
|
||||
Processes a Window menu event.
|
||||
@@ -2858,9 +2934,27 @@ class WindowMenuService(DocService):
|
||||
elif id == self.SELECT_MORE_WINDOWS_ID:
|
||||
self.OnSelectMoreWindows(event)
|
||||
return True
|
||||
elif id == self.SELECT_WINDOW_1_ID or id == self.SELECT_WINDOW_2_ID or id == self.SELECT_WINDOW_3_ID or id == self.SELECT_WINDOW_4_ID or id == self.SELECT_WINDOW_5_ID or id == self.SELECT_WINDOW_6_ID or id == self.SELECT_WINDOW_7_ID or id == self.SELECT_WINDOW_8_ID or id == self.SELECT_WINDOW_9_ID:
|
||||
elif id in self._selectWinIds:
|
||||
self.OnSelectWindowMenu(event)
|
||||
return True
|
||||
elif wx.GetApp().GetUseTabbedMDI():
|
||||
if id == self.SELECT_NEXT_WINDOW_ID:
|
||||
notebook = wx.GetApp().GetTopWindow()._notebook
|
||||
i = notebook.GetSelection()
|
||||
notebook.SetSelection(i+1)
|
||||
return True
|
||||
elif id == self.SELECT_PREV_WINDOW_ID:
|
||||
notebook = wx.GetApp().GetTopWindow()._notebook
|
||||
i = notebook.GetSelection()
|
||||
notebook.SetSelection(i-1)
|
||||
return True
|
||||
elif id == self.CLOSE_CURRENT_WINDOW_ID:
|
||||
notebook = wx.GetApp().GetTopWindow()._notebook
|
||||
i = notebook.GetSelection()
|
||||
if i != -1:
|
||||
doc = notebook.GetPage(i).GetView().GetDocument()
|
||||
wx.GetApp().GetDocumentManager().CloseDocument(doc, False)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@@ -2876,6 +2970,38 @@ class WindowMenuService(DocService):
|
||||
self.BuildWindowMenu(frame) # It's a new frame, so update the windows menu... this is as if the View::OnActivateMethod had been invoked
|
||||
self._lastFrameUpdated = frame
|
||||
return True
|
||||
elif wx.GetApp().GetUseTabbedMDI():
|
||||
if id == self.SELECT_NEXT_WINDOW_ID:
|
||||
self.BuildWindowMenu(event.GetEventObject()) # build file list only when we are updating the windows menu
|
||||
|
||||
notebook = wx.GetApp().GetTopWindow()._notebook
|
||||
i = notebook.GetSelection()
|
||||
if i == -1:
|
||||
event.Enable(False)
|
||||
return True
|
||||
i += 1
|
||||
if i >= notebook.GetPageCount():
|
||||
event.Enable(False)
|
||||
return True
|
||||
event.Enable(True)
|
||||
return True
|
||||
elif id == self.SELECT_PREV_WINDOW_ID:
|
||||
notebook = wx.GetApp().GetTopWindow()._notebook
|
||||
i = notebook.GetSelection()
|
||||
if i == -1:
|
||||
event.Enable(False)
|
||||
return True
|
||||
i -= 1
|
||||
if i < 0:
|
||||
event.Enable(False)
|
||||
return True
|
||||
event.Enable(True)
|
||||
return True
|
||||
elif id == self.CLOSE_CURRENT_WINDOW_ID:
|
||||
event.Enable(wx.GetApp().GetTopWindow()._notebook.GetSelection() != -1)
|
||||
return True
|
||||
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
@@ -2884,9 +3010,13 @@ class WindowMenuService(DocService):
|
||||
"""
|
||||
Builds the Window menu and adds menu items for all of the open documents in the DocManager.
|
||||
"""
|
||||
if wx.GetApp().GetUseTabbedMDI():
|
||||
currentFrame = wx.GetApp().GetTopWindow()
|
||||
|
||||
windowMenuIndex = currentFrame.GetMenuBar().FindMenu(_("&Window"))
|
||||
windowMenu = currentFrame.GetMenuBar().GetMenu(windowMenuIndex)
|
||||
ids = self._GetWindowMenuIDList()
|
||||
|
||||
if self.GetDocumentManager().GetFlags() & wx.lib.docview.DOC_SDI:
|
||||
frames = self._GetWindowMenuFrameList(currentFrame)
|
||||
max = WINDOW_MENU_NUM_ITEMS
|
||||
if max > len(frames):
|
||||
@@ -2894,13 +3024,13 @@ class WindowMenuService(DocService):
|
||||
i = 0
|
||||
for i in range(0, max):
|
||||
frame = frames[i]
|
||||
item = windowMenu.FindItemById(ids[i])
|
||||
item = windowMenu.FindItemById(self._selectWinIds[i])
|
||||
label = '&' + str(i + 1) + ' ' + frame.GetTitle()
|
||||
if not item:
|
||||
item = windowMenu.AppendCheckItem(ids[i], label)
|
||||
item = windowMenu.AppendCheckItem(self._selectWinIds[i], label)
|
||||
else:
|
||||
windowMenu.SetLabel(ids[i], label)
|
||||
windowMenu.Check(ids[i], (frame == currentFrame))
|
||||
windowMenu.SetLabel(self._selectWinIds[i], label)
|
||||
windowMenu.Check(self._selectWinIds[i], (frame == currentFrame))
|
||||
if len(frames) > WINDOW_MENU_NUM_ITEMS: # Add the more items item
|
||||
if not windowMenu.FindItemById(self.SELECT_MORE_WINDOWS_ID):
|
||||
windowMenu.Append(self.SELECT_MORE_WINDOWS_ID, _("&More Windows..."))
|
||||
@@ -2908,18 +3038,42 @@ class WindowMenuService(DocService):
|
||||
if windowMenu.FindItemById(self.SELECT_MORE_WINDOWS_ID):
|
||||
windowMenu.Remove(self.SELECT_MORE_WINDOWS_ID)
|
||||
|
||||
|
||||
|
||||
for j in range(i + 1, WINDOW_MENU_NUM_ITEMS):
|
||||
if windowMenu.FindItemById(ids[j]):
|
||||
windowMenu.Remove(ids[j])
|
||||
if windowMenu.FindItemById(self._selectWinIds[j]):
|
||||
windowMenu.Remove(self._selectWinIds[j])
|
||||
|
||||
elif wx.GetApp().GetUseTabbedMDI():
|
||||
notebook = wx.GetApp().GetTopWindow()._notebook
|
||||
numPages = notebook.GetPageCount()
|
||||
|
||||
for id in self._selectWinIds:
|
||||
item = windowMenu.FindItemById(id)
|
||||
if item:
|
||||
windowMenu.DeleteItem(item)
|
||||
if numPages == 0 and self._sep:
|
||||
windowMenu.DeleteItem(self._sep)
|
||||
self._sep = None
|
||||
|
||||
if numPages > len(self._selectWinIds):
|
||||
for i in range(len(self._selectWinIds), numPages):
|
||||
self._selectWinIds.append(wx.NewId())
|
||||
wx.EVT_MENU(currentFrame, self._selectWinIds[i], self.OnCtrlKeySelect)
|
||||
|
||||
for i in range(0, numPages):
|
||||
if i == 0 and not self._sep:
|
||||
self._sep = windowMenu.AppendSeparator()
|
||||
if i < 9:
|
||||
menuLabel = "%s\tCtrl+%s" % (notebook.GetPageText(i), i+1)
|
||||
else:
|
||||
menuLabel = notebook.GetPageText(i)
|
||||
windowMenu.Append(self._selectWinIds[i], menuLabel)
|
||||
|
||||
|
||||
def _GetWindowMenuIDList(self):
|
||||
"""
|
||||
Returns a list of the Window menu item IDs.
|
||||
"""
|
||||
return [self.SELECT_WINDOW_1_ID, self.SELECT_WINDOW_2_ID, self.SELECT_WINDOW_3_ID, self.SELECT_WINDOW_4_ID, self.SELECT_WINDOW_5_ID, self.SELECT_WINDOW_6_ID, self.SELECT_WINDOW_7_ID, self.SELECT_WINDOW_8_ID, self.SELECT_WINDOW_9_ID]
|
||||
return self._selectWinIds
|
||||
|
||||
|
||||
def _GetWindowMenuFrameList(self, currentFrame=None):
|
||||
@@ -2988,7 +3142,7 @@ class WindowMenuService(DocService):
|
||||
Frame to the front of the desktop.
|
||||
"""
|
||||
id = event.GetId()
|
||||
index = self._GetWindowMenuIDList().index(id)
|
||||
index = self._selectWinIds.index(id)
|
||||
if index > -1:
|
||||
currentFrame = event.GetEventObject()
|
||||
frame = self._GetWindowMenuFrameList(currentFrame)[index]
|
||||
|
Reference in New Issue
Block a user