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:
Robin Dunn
2006-04-20 06:26:03 +00:00
parent ea5449ae51
commit aca310e5cc
41 changed files with 11425 additions and 4018 deletions

View 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]

View File

@@ -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"))

View File

@@ -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()

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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()

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -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):

View File

@@ -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

View File

@@ -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):

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

View File

@@ -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.

View File

@@ -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,

View File

@@ -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

View File

@@ -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):

View File

@@ -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()

View 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

View File

@@ -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")

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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()

View 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 = {'"':'&quot;'}
global saxXMLescapesAllQuotes
# IE doesn't support &apos; but it doesn't seem like we should need this escaped at all so I took it out.
saxXMLescapesAllQuotes = {'"':'&quot;', "'":"&#039;"}
global saxXMLunescapes
saxXMLunescapes = {'&quot;':'"', "&#039;":"'"}
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)

View File

@@ -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

View File

@@ -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("\"", "&quot;")
# IE doesn't support &apos;
# data=data.replace("\'", "&apos;")
data=data.replace("\'", "&#039;")
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("&quot;", "\"")
data=data.replace("&apos;", "\'")
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

View File

@@ -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():

View File

@@ -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":

View File

@@ -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.

View File

@@ -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]