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 # Author: Morgan Hua
# #
# Created: 3/22/05 # Created: 3/22/05
# Copyright: (c) 2005 ActiveGrid, Inc. # Copyright: (c) 2005-2006 ActiveGrid, Inc.
# CVS-ID: $Id$ # CVS-ID: $Id$
# License: wxWindows License # License: wxWindows License
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------
@@ -30,23 +30,25 @@ licenseData = [ # add licenses for base IDE features
("Python 2.4", "Python Software Foundation License", "http://www.python.org/2.4/license.html"), ("Python 2.4", "Python Software Foundation License", "http://www.python.org/2.4/license.html"),
("wxPython 2.6", "wxWidgets 2 - LGPL", "http://wxwidgets.org/newlicen.htm"), ("wxPython 2.6", "wxWidgets 2 - LGPL", "http://wxwidgets.org/newlicen.htm"),
("wxWidgets", "wxWindows Library License 3", "http://www.wxwidgets.org/manuals/2.6.1/wx_wxlicense.html"), ("wxWidgets", "wxWindows Library License 3", "http://www.wxwidgets.org/manuals/2.6.1/wx_wxlicense.html"),
("pychecker", "MetaSlash - BSD", "http://pychecker.sourceforge.net/COPYRIGHT"), ("pychecker", "MetaSlash - BSD", "http://pychecker.sourceforge.net/COPYRIGHT"),
("process.py", "See file", "http://starship.python.net/~tmick/"), ("process.py", "See file", "http://starship.python.net/~tmick/"),
("pysvn", "Apache License, Version 2.0", "http://pysvn.tigris.org/"), ("pysvn", "Apache License, Version 2.0", "http://pysvn.tigris.org/"),
] ]
if not ACTIVEGRID_BASE_IDE: # add licenses for non-base IDE features such as database connections if not ACTIVEGRID_BASE_IDE: # add licenses for non-base IDE features such as database connections
licenseData += [ licenseData += [
("pydb2", "LGPL", "http://sourceforge.net/projects/pydb2"), ("pydb2", "LGPL", "http://sourceforge.net/projects/pydb2"),
("pysqlite", "Python License (CNRI)", "http://sourceforge.net/projects/pysqlite"), ("pysqlite", "Python License (CNRI)", "http://sourceforge.net/projects/pysqlite"),
("mysql-python", "GPL, Python License (CNRI), Zope Public License", "http://sourceforge.net/projects/mysql-python"), ("mysql-python", "GPL, Python License (CNRI), Zope Public License", "http://sourceforge.net/projects/mysql-python"),
("cx_Oracle", "Computronix", "http://www.computronix.com/download/License(cxOracle).txt"), ("cx_Oracle", "Computronix", "http://www.computronix.com/download/License(cxOracle).txt"),
("SQLite", "Public Domain", "http://www.sqlite.org/copyright.html"), ("SQLite", "Public Domain", "http://www.sqlite.org/copyright.html"),
("PyGreSQL", "BSD", "http://www.pygresql.org"), ("PyGreSQL", "BSD", "http://www.pygresql.org"),
("pyXML", "CNRI Python License", "http://sourceforge.net/softwaremap/trove_list.php?form_cat=194"), ("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/"), ("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/"), ("Sarissa", "LGPL", "http://sourceforge.net/projects/sarissa/"),
("Dynarch DHTML Calendar", "LGPL", "http://www.dynarch.com/projects/calendar/"), ("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 if wx.Platform == '__WXMSW__': # add Windows only licenses
@@ -70,7 +72,7 @@ class AboutDialog(wx.Dialog):
else: else:
splash_bmp = getIDESplashBitmap() splash_bmp = getIDESplashBitmap()
# find version number from # find version number from
versionFilepath = os.path.join(sysutilslib.mainModuleDir, "version.txt") versionFilepath = os.path.join(sysutilslib.mainModuleDir, "version.txt")
if os.path.exists(versionFilepath): if os.path.exists(versionFilepath):
versionfile = open(versionFilepath, 'r') versionfile = open(versionFilepath, 'r')
@@ -82,7 +84,7 @@ class AboutDialog(wx.Dialog):
image = wx.StaticBitmap(aboutPage, -1, splash_bmp, (0,0), (splash_bmp.GetWidth(), splash_bmp.GetHeight())) 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(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) sizer.Add(wx.StaticText(aboutPage, -1, _("http://www.activegrid.com")), 0, wx.ALIGN_LEFT|wx.LEFT|wx.BOTTOM, 10)
aboutPage.SetSizer(sizer) aboutPage.SetSizer(sizer)
nb.AddPage(aboutPage, _("Copyright")) nb.AddPage(aboutPage, _("Copyright"))
@@ -90,15 +92,14 @@ class AboutDialog(wx.Dialog):
licensePage = wx.Panel(nb, -1) licensePage = wx.Panel(nb, -1)
grid = wx.grid.Grid(licensePage, -1) grid = wx.grid.Grid(licensePage, -1)
grid.CreateGrid(len(licenseData), 2) grid.CreateGrid(len(licenseData), 2)
dc = wx.ClientDC(grid) dc = wx.ClientDC(grid)
dc.SetFont(grid.GetLabelFont()) dc.SetFont(grid.GetLabelFont())
grid.SetColLabelValue(0, _("License")) grid.SetColLabelValue(0, _("License"))
grid.SetColLabelValue(1, _("URL")) grid.SetColLabelValue(1, _("URL"))
w, maxHeight = dc.GetTextExtent(_("License")) w, h1 = dc.GetTextExtent(_("License"))
w, h = dc.GetTextExtent(_("URL")) w, h2 = dc.GetTextExtent(_("URL"))
if h > maxHeight: maxHeight = max(h1, h2)
maxHeight = h
grid.SetColLabelSize(maxHeight + 6) # add a 6 pixel margin grid.SetColLabelSize(maxHeight + 6) # add a 6 pixel margin
maxW = 0 maxW = 0
@@ -115,7 +116,7 @@ class AboutDialog(wx.Dialog):
grid.SetCellValue(row, 0, license) grid.SetCellValue(row, 0, license)
if url: if url:
grid.SetCellValue(row, 1, url) grid.SetCellValue(row, 1, url)
grid.EnableEditing(False) grid.EnableEditing(False)
grid.EnableDragGridSize(False) grid.EnableDragGridSize(False)
grid.EnableDragColSize(False) grid.EnableDragColSize(False)
@@ -132,10 +133,10 @@ class AboutDialog(wx.Dialog):
creditsPage = wx.Panel(nb, -1) creditsPage = wx.Panel(nb, -1)
sizer = wx.BoxSizer(wx.VERTICAL) 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) creditsPage.SetSizer(sizer)
nb.AddPage(creditsPage, _("Credits")) nb.AddPage(creditsPage, _("Credits"))
sizer = wx.BoxSizer(wx.VERTICAL) sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(nb, 0, wx.ALIGN_CENTRE|wx.ALL, 5) sizer.Add(nb, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
btn = wx.Button(self, wx.ID_OK) btn = wx.Button(self, wx.ID_OK)
@@ -145,5 +146,5 @@ class AboutDialog(wx.Dialog):
self.Layout() self.Layout()
self.Fit() self.Fit()
grid.ForceRefresh() # wxBug: Get rid of unnecessary scrollbars grid.ForceRefresh() # wxBug: Get rid of unnecessary scrollbars

View File

@@ -36,6 +36,7 @@ PARKING_VERTICAL = 1
PARKING_HORIZONTAL = 2 PARKING_HORIZONTAL = 2
PARKING_OFFSET = 30 # space between shapes PARKING_OFFSET = 30 # space between shapes
FORCE_REDRAW_METHOD = "ForceRedraw"
def GetRawModel(model): def GetRawModel(model):
if hasattr(model, "GetRawModel"): if hasattr(model, "GetRawModel"):
@@ -85,6 +86,7 @@ class CanvasView(wx.lib.docview.View):
self._propShape = None self._propShape = None
self._maxWidth = 2000 self._maxWidth = 2000
self._maxHeight = 16000 self._maxHeight = 16000
self._valetParking = False
def OnDraw(self, dc): def OnDraw(self, dc):
@@ -195,6 +197,16 @@ class CanvasView(wx.lib.docview.View):
self.SetPropertyModel(None) 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): def OnKeyPressed(self, event):
key = event.KeyCode() key = event.KeyCode()
if key == wx.WXK_DELETE: if key == wx.WXK_DELETE:
@@ -211,6 +223,7 @@ class CanvasView(wx.lib.docview.View):
dc = wx.ClientDC(self._canvas) dc = wx.ClientDC(self._canvas)
self._canvas.PrepareDC(dc) self._canvas.PrepareDC(dc)
x, y = event.GetLogicalPosition(dc) # this takes into account scrollbar offset x, y = event.GetLogicalPosition(dc) # this takes into account scrollbar offset
self.SetLastRightClick(x, y)
shape = self._canvas.FindShape(x, y)[0] shape = self._canvas.FindShape(x, y)[0]
model = None model = None
@@ -260,12 +273,15 @@ class CanvasView(wx.lib.docview.View):
pass pass
else: else:
# click on empty part of canvas, deselect everything # click on empty part of canvas, deselect everything
forceRedrawShapes = []
needRefresh = False needRefresh = False
for shape in self._diagram.GetShapeList(): for shape in self._diagram.GetShapeList():
if hasattr(shape, "GetModel"): if hasattr(shape, "GetModel"):
if shape.Selected(): if shape.Selected():
needRefresh = True needRefresh = True
shape.Select(False, dc) shape.Select(False, dc)
if hasattr(shape, FORCE_REDRAW_METHOD):
forceRedrawShapes.append(shape)
if needRefresh: if needRefresh:
self._canvas.Redraw(dc) self._canvas.Redraw(dc)
@@ -274,7 +290,8 @@ class CanvasView(wx.lib.docview.View):
if len(self.GetSelection()) == 0: if len(self.GetSelection()) == 0:
self.SetPropertyShape(None) self.SetPropertyShape(None)
for shape in forceRedrawShapes:
shape.ForceRedraw()
def OnLeftDoubleClick(self, event): def OnLeftDoubleClick(self, event):
propertyService = wx.GetApp().GetService(PropertyService.PropertyService) propertyService = wx.GetApp().GetService(PropertyService.PropertyService)
@@ -401,8 +418,20 @@ class CanvasView(wx.lib.docview.View):
dc.EndDrawing() 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): 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 max = 700 # max distance to the right where we'll place tables
noParkingSpot = True noParkingSpot = True
@@ -422,6 +451,9 @@ class CanvasView(wx.lib.docview.View):
else: else:
noParkingSpot = False noParkingSpot = False
if self._valetParking:
self._valetPosition = (x, y)
return x, y return x, y
@@ -518,7 +550,8 @@ class CanvasView(wx.lib.docview.View):
self._diagram.RemoveShape(line) self._diagram.RemoveShape(line)
line.Delete() line.Delete()
shape.RemoveFromCanvas(self._canvas) if self._canvas:
shape.RemoveFromCanvas(self._canvas)
self._diagram.RemoveShape(shape) self._diagram.RemoveShape(shape)
shape.Delete() shape.Delete()
@@ -698,6 +731,9 @@ class CanvasView(wx.lib.docview.View):
self._propShape.SetTextColour("WHITE", 0) self._propShape.SetTextColour("WHITE", 0)
self._propShape.Draw(dc) self._propShape.Draw(dc)
if hasattr(self._propShape, FORCE_REDRAW_METHOD):
self._propShape.ForceRedraw()
dc.EndDrawing() dc.EndDrawing()

View File

@@ -19,7 +19,6 @@ import os
import re import re
import string import string
import sys import sys
import DebuggerService
import MarkerService import MarkerService
from UICommon import CaseInsensitiveCompare from UICommon import CaseInsensitiveCompare
_ = wx.GetTranslation _ = wx.GetTranslation
@@ -120,16 +119,27 @@ class CodeView(STCTextEditor.TextView):
return False return False
id = event.GetId() id = event.GetId()
if id == EXPAND_TEXT_ID: if id == EXPAND_TEXT_ID:
event.Enable(self.GetCtrl().CanLineExpand(self.GetCtrl().GetCurrentLine())) if self.GetCtrl().GetViewFolding():
event.Enable(self.GetCtrl().CanLineExpand(self.GetCtrl().GetCurrentLine()))
else:
event.Enable(False)
return True return True
elif id == COLLAPSE_TEXT_ID: elif id == COLLAPSE_TEXT_ID:
event.Enable(self.GetCtrl().CanLineCollapse(self.GetCtrl().GetCurrentLine())) if self.GetCtrl().GetViewFolding():
event.Enable(self.GetCtrl().CanLineCollapse(self.GetCtrl().GetCurrentLine()))
else:
event.Enable(False)
return True return True
elif (id == EXPAND_TOP_ID elif (id == EXPAND_TOP_ID
or id == COLLAPSE_TOP_ID or id == COLLAPSE_TOP_ID
or id == EXPAND_ALL_ID or id == EXPAND_ALL_ID
or id == COLLAPSE_ALL_ID or id == COLLAPSE_ALL_ID):
or id == AUTO_COMPLETE_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 == CLEAN_WHITESPACE
or id == INDENT_LINES_ID or id == INDENT_LINES_ID
or id == DEDENT_LINES_ID or id == DEDENT_LINES_ID
@@ -140,10 +150,12 @@ class CodeView(STCTextEditor.TextView):
elif id == CHECK_CODE_ID: elif id == CHECK_CODE_ID:
event.Enable(False) event.Enable(False)
return True return True
elif (id == SET_INDENT_WIDTH_ID elif id == SET_INDENT_WIDTH_ID:
or id == FOLDING_ID):
event.Enable(True) event.Enable(True)
return True return True
elif id == FOLDING_ID:
event.Enable(self.GetCtrl().GetViewFolding())
return True
elif id == USE_TABS_ID: elif id == USE_TABS_ID:
event.Enable(True) event.Enable(True)
event.Check(self.GetCtrl().GetUseTabs()) event.Check(self.GetCtrl().GetUseTabs())
@@ -210,7 +222,7 @@ class CodeView(STCTextEditor.TextView):
filename = document.GetFilename() filename = document.GetFilename()
if filename: if filename:
rootItem = treeCtrl.AddRoot(os.path.basename(filename)) rootItem = treeCtrl.AddRoot(os.path.basename(filename))
treeCtrl.SetDoSelectCallback(rootItem, self, None) treeCtrl.SetDoSelectCallback(rootItem, self, (0,0))
else: else:
return True return True
@@ -232,11 +244,13 @@ class CodeView(STCTextEditor.TextView):
if classLine: if classLine:
indent = classLine.start(0) indent = classLine.start(0)
itemStr = classLine.string[classLine.start(0):classLine.end(0)-1] # don't take the closing ':' 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: else:
defLine = defPat.search(line) defLine = defPat.search(line)
if defLine: if defLine:
indent = defLine.start(0) indent = defLine.start(0)
itemStr = defLine.string[defLine.start(0):defLine.end(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: if indent == 0:
parentItem = rootItem parentItem = rootItem
@@ -467,6 +481,9 @@ class CodeView(STCTextEditor.TextView):
def OnUpdate(self, sender = None, hint = None): def OnUpdate(self, sender = None, hint = None):
if wx.lib.docview.View.OnUpdate(self, sender, hint):
return
if hint == "ViewStuff": if hint == "ViewStuff":
self.GetCtrl().SetViewDefaults() self.GetCtrl().SetViewDefaults()
elif hint == "Font": elif hint == "Font":
@@ -474,6 +491,7 @@ class CodeView(STCTextEditor.TextView):
self.GetCtrl().SetFont(font) self.GetCtrl().SetFont(font)
self.GetCtrl().SetFontColor(color) self.GetCtrl().SetFontColor(color)
else: else:
import DebuggerService
dbg_service = wx.GetApp().GetService(DebuggerService.DebuggerService) dbg_service = wx.GetApp().GetService(DebuggerService.DebuggerService)
if dbg_service: if dbg_service:
dbg_service.SetCurrentBreakpointMarkers(self) dbg_service.SetCurrentBreakpointMarkers(self)
@@ -623,7 +641,7 @@ class CodeCtrl(STCTextEditor.TextCtrl):
BREAKPOINT_MARKER_MASK = 0x2 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) STCTextEditor.TextCtrl.__init__(self, parent, id, style)
self.UsePopUp(False) self.UsePopUp(False)
@@ -635,7 +653,6 @@ class CodeCtrl(STCTextEditor.TextCtrl):
self.SetMarginType(2, wx.stc.STC_MARGIN_SYMBOL) self.SetMarginType(2, wx.stc.STC_MARGIN_SYMBOL)
self.SetMarginMask(2, wx.stc.STC_MASK_FOLDERS) self.SetMarginMask(2, wx.stc.STC_MASK_FOLDERS)
self.SetMarginSensitive(2, True) self.SetMarginSensitive(2, True)
self.SetMarginWidth(2, 12)
self.SetMarginSensitive(1, False) self.SetMarginSensitive(1, False)
self.SetMarginMask(1, 0x4) self.SetMarginMask(1, 0x4)
@@ -657,7 +674,7 @@ class CodeCtrl(STCTextEditor.TextCtrl):
# Define the breakpoint marker # Define the breakpoint marker
self.MarkerDefine(CodeCtrl.BREAKPOINT_MARKER_NUM, wx.stc.STC_MARK_CIRCLE, wx.BLACK, (255,0,0)) 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 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) 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")) item = wx.MenuItem(menu, TOGGLEBREAKPOINT_ID, _("Toggle Breakpoint"))
menu.AppendItem(item) menu.AppendItem(item)
self.Bind(wx.EVT_MENU, self.OnPopToggleMarker, id=TOGGLEMARKER_ID) 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.AppendItem(item)
menu.AppendSeparator() menu.AppendSeparator()
@@ -715,6 +732,7 @@ class CodeCtrl(STCTextEditor.TextCtrl):
def OnPopToggleBP(self, event): def OnPopToggleBP(self, event):
""" Toggle break point on right click line, not current line """ """ Toggle break point on right click line, not current line """
import DebuggerService
wx.GetApp().GetService(DebuggerService.DebuggerService).OnToggleBreakpoint(event, line=self._rightClickLine) wx.GetApp().GetService(DebuggerService.DebuggerService).OnToggleBreakpoint(event, line=self._rightClickLine)
@@ -859,6 +877,7 @@ class CodeCtrl(STCTextEditor.TextCtrl):
elif evt.GetMargin() == 0: elif evt.GetMargin() == 0:
#This is used to toggle breakpoints via the debugger service. #This is used to toggle breakpoints via the debugger service.
import DebuggerService
db_service = wx.GetApp().GetService(DebuggerService.DebuggerService) db_service = wx.GetApp().GetService(DebuggerService.DebuggerService)
if db_service: if db_service:
db_service.OnToggleBreakpoint(evt, line=self.LineFromPosition(evt.GetPosition())) 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 # Created: 5/23/05
# CVS-ID: $ID:$ # CVS-ID: $ID:$
# Copyright: (c) 2005 ActiveGrid, Inc. # Copyright: (c) 2005-2006 ActiveGrid, Inc.
# License: wxWindows License # License: wxWindows License
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------
@@ -17,27 +17,22 @@ import ProjectEditor
import os import os
import os.path import os.path
import activegrid.util.xmlutils as xmlutils import activegrid.util.xmlutils as xmlutils
_ = wx.GetTranslation _ = wx.GetTranslation
#----------------------------------------------------------------------------
# Constants
#----------------------------------------------------------------------------
SPACE = 10 SPACE = 10
HALF_SPACE = 5 HALF_SPACE = 5
EXTENSIONS_CONFIG_STRING = "Extensions"
# TODO: Redo extensions menu on OK, or provide alert that it won't happen until restart
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------
# Classes # Classes
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------
class Extension: class Extension:
def __init__(self, menuItemName=None): def __init__(self, menuItemName=None):
self.menuItemName = menuItemName self.menuItemName = menuItemName
@@ -48,7 +43,7 @@ class Extension:
self.commandPostArgs = '' self.commandPostArgs = ''
self.fileExt = None self.fileExt = None
self.opOnSelectedFile = True self.opOnSelectedFile = True
class ExtensionService(wx.lib.pydocview.DocService): class ExtensionService(wx.lib.pydocview.DocService):
@@ -60,8 +55,8 @@ class ExtensionService(wx.lib.pydocview.DocService):
def __getExtensionKeyName(extensionName): def __getExtensionKeyName(extensionName):
return "%s/%s" % (ExtensionService.EXTENSIONS_KEY, extensionName) return "%s/%s" % (ExtensionService.EXTENSIONS_KEY, extensionName)
__getExtensionKeyName = staticmethod(__getExtensionKeyName) __getExtensionKeyName = staticmethod(__getExtensionKeyName)
@@ -79,7 +74,7 @@ class ExtensionService(wx.lib.pydocview.DocService):
cont, value, index = config.GetNextEntry(index) cont, value, index = config.GetNextEntry(index)
finally: finally:
config.SetPath(path) config.SetPath(path)
for extensionName in extensionNames: for extensionName in extensionNames:
extensionData = config.Read(self.__getExtensionKeyName(extensionName)) extensionData = config.Read(self.__getExtensionKeyName(extensionName))
if extensionData: if extensionData:
@@ -112,10 +107,10 @@ class ExtensionService(wx.lib.pydocview.DocService):
toolsMenu = menuBar.GetMenu(toolsMenuIndex) toolsMenu = menuBar.GetMenu(toolsMenuIndex)
else: else:
toolsMenu = wx.Menu() toolsMenu = wx.Menu()
if self._extensions: if self._extensions:
if toolsMenu.GetMenuItems(): if toolsMenu.GetMenuItems():
toolsMenu.AppendSeparator() toolsMenu.AppendSeparator()
for ext in self._extensions: for ext in self._extensions:
# Append a tool menu item for each extension # Append a tool menu item for each extension
ext.id = wx.NewId() ext.id = wx.NewId()
@@ -192,7 +187,7 @@ class ExtensionService(wx.lib.pydocview.DocService):
if extension.commandPostArgs: if extension.commandPostArgs:
cmds.append(extension.commandPostArgs) cmds.append(extension.commandPostArgs)
os.spawnv(os.P_NOWAIT, extension.command, cmds) os.spawnv(os.P_NOWAIT, extension.command, cmds)
else: else:
cmd = extension.command cmd = extension.command
if extension.commandPreArgs: if extension.commandPreArgs:
@@ -207,24 +202,24 @@ class ExtensionService(wx.lib.pydocview.DocService):
view.AddLines(line) view.AddLines(line)
view.GetControl().EnsureCaretVisible() view.GetControl().EnsureCaretVisible()
f.close() f.close()
class ExtensionOptionsPanel(wx.Panel): class ExtensionOptionsPanel(wx.Panel):
def __init__(self, parent, id): def __init__(self, parent, id):
wx.Panel.__init__(self, parent, id) wx.Panel.__init__(self, parent, id)
extOptionsPanelBorderSizer = wx.BoxSizer(wx.VERTICAL) extOptionsPanelBorderSizer = wx.BoxSizer(wx.VERTICAL)
extOptionsPanelSizer = wx.BoxSizer(wx.HORIZONTAL) extOptionsPanelSizer = wx.BoxSizer(wx.HORIZONTAL)
extCtrlSizer = wx.BoxSizer(wx.VERTICAL) extCtrlSizer = wx.BoxSizer(wx.VERTICAL)
extCtrlSizer.Add(wx.StaticText(self, -1, _("External Tools:")), 0, wx.BOTTOM, HALF_SPACE) 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) self.Bind(wx.EVT_LISTBOX, self.OnListBoxSelect, self._extListBox)
extCtrlSizer.Add(self._extListBox, 1, wx.BOTTOM | wx.EXPAND, SPACE) 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._moveUpButton = wx.Button(self, -1, _("Move Up"))
self.Bind(wx.EVT_BUTTON, self.OnMoveUp, self._moveUpButton) self.Bind(wx.EVT_BUTTON, self.OnMoveUp, self._moveUpButton)
buttonSizer.Add(self._moveUpButton, 1, wx.EXPAND) buttonSizer.Add(self._moveUpButton, 1, wx.EXPAND)
@@ -243,21 +238,21 @@ class ExtensionOptionsPanel(wx.Panel):
self._extDetailPanel = wx.Panel(self) self._extDetailPanel = wx.Panel(self)
staticBox = wx.StaticBox(self, label=_("Selected External Tool")) staticBox = wx.StaticBox(self, label=_("Selected External Tool"))
staticBoxSizer = wx.StaticBoxSizer(staticBox, wx.VERTICAL) 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.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)) self._menuItemNameTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1))
extDetailSizer.Add(self._menuItemNameTextCtrl, 0, wx.EXPAND) extDetailSizer.Add(self._menuItemNameTextCtrl, 0, wx.EXPAND)
self.Bind(wx.EVT_TEXT, self.SaveCurrentItem, self._menuItemNameTextCtrl) 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)) self._menuItemDescTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1))
extDetailSizer.Add(self._menuItemDescTextCtrl, 0, wx.EXPAND) 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)) self._commandTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1))
findFileButton = wx.Button(self._extDetailPanel, -1, _("Browse...")) findFileButton = wx.Button(self._extDetailPanel, -1, _("Browse..."))
def OnBrowseButton(event): def OnBrowseButton(event):
fileDlg = wx.FileDialog(self, _("Choose an Executable:"), style=wx.OPEN|wx.FILE_MUST_EXIST|wx.HIDE_READONLY|wx.CHANGE_DIR) fileDlg = wx.FileDialog(self, _("Choose an Executable:"), style=wx.OPEN|wx.FILE_MUST_EXIST|wx.HIDE_READONLY|wx.CHANGE_DIR)
@@ -276,26 +271,26 @@ class ExtensionOptionsPanel(wx.Panel):
hsizer.Add(findFileButton, 0, wx.LEFT, HALF_SPACE) hsizer.Add(findFileButton, 0, wx.LEFT, HALF_SPACE)
extDetailSizer.Add(hsizer, 0, wx.EXPAND) 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)) self._commandPreArgsTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1))
extDetailSizer.Add(self._commandPreArgsTextCtrl, 0, wx.EXPAND) 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)) self._commandPostArgsTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1))
extDetailSizer.Add(self._commandPostArgsTextCtrl, 0, wx.EXPAND) 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 = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1))
self._fileExtTextCtrl.SetToolTipString(_("""For example: "txt, text" (comma separated) or "*" for all files""")) self._fileExtTextCtrl.SetToolTipString(_("""For example: "txt, text" (comma separated) or "*" for all files"""))
extDetailSizer.Add(self._fileExtTextCtrl, 0, wx.EXPAND) extDetailSizer.Add(self._fileExtTextCtrl, 0, wx.EXPAND)
self._selFileCtrl = wx.CheckBox(self._extDetailPanel, -1, _("Operate on Selected File")) 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._selFileCtrl.SetToolTipString(_("If focus is in the project, instead of operating on the project file, operate on the selected file."))
self._extDetailPanel.SetSizer(extDetailSizer) self._extDetailPanel.SetSizer(extDetailSizer)
staticBoxSizer.Add(self._extDetailPanel, 1, wx.ALL|wx.EXPAND, SPACE) staticBoxSizer.Add(self._extDetailPanel, 1, wx.ALL|wx.EXPAND, SPACE)
extOptionsPanelSizer.Add(staticBoxSizer, 1, wx.LEFT|wx.EXPAND, SPACE) extOptionsPanelSizer.Add(staticBoxSizer, 1, wx.LEFT|wx.EXPAND, SPACE)
extOptionsPanelBorderSizer.Add(extOptionsPanelSizer, 1, wx.ALL|wx.EXPAND, SPACE) extOptionsPanelBorderSizer.Add(extOptionsPanelSizer, 1, wx.ALL|wx.EXPAND, SPACE)
@@ -306,8 +301,8 @@ class ExtensionOptionsPanel(wx.Panel):
self.OnListBoxSelect() self.OnListBoxSelect()
self.Layout() self.Layout()
parent.AddPage(self, _("External Tools")) parent.AddPage(self, _("External Tools"))
def OnOK(self, optionsDialog): def OnOK(self, optionsDialog):
@@ -323,7 +318,7 @@ class ExtensionOptionsPanel(wx.Panel):
msgTitle, msgTitle,
wx.OK | wx.ICON_INFORMATION, wx.OK | wx.ICON_INFORMATION,
self.GetParent()) self.GetParent())
def PopulateItems(self): def PopulateItems(self):
extensionsService = wx.GetApp().GetService(ExtensionService) extensionsService = wx.GetApp().GetService(ExtensionService)
@@ -335,7 +330,7 @@ class ExtensionOptionsPanel(wx.Panel):
self._currentItem = None self._currentItem = None
self._currentItemIndex = -1 self._currentItemIndex = -1
return len(self._extensions) return len(self._extensions)
def OnListBoxSelect(self, event=None): def OnListBoxSelect(self, event=None):
self.SaveCurrentItem() self.SaveCurrentItem()
@@ -370,7 +365,7 @@ class ExtensionOptionsPanel(wx.Panel):
else: else:
extension.fileExt = fileExt.split(',') extension.fileExt = fileExt.split(',')
extension.opOnSelectedFile = self._selFileCtrl.GetValue() extension.opOnSelectedFile = self._selFileCtrl.GetValue()
def LoadItem(self, extension): def LoadItem(self, extension):
if extension: if extension:
@@ -401,8 +396,8 @@ class ExtensionOptionsPanel(wx.Panel):
self._fileExtTextCtrl.SetValue('') self._fileExtTextCtrl.SetValue('')
self._selFileCtrl.SetValue(True) self._selFileCtrl.SetValue(True)
self._extDetailPanel.Enable(False) self._extDetailPanel.Enable(False)
def OnAdd(self, event): def OnAdd(self, event):
self.SaveCurrentItem() self.SaveCurrentItem()
name = _("Untitled") name = _("Untitled")
@@ -417,11 +412,11 @@ class ExtensionOptionsPanel(wx.Panel):
self.OnListBoxSelect() self.OnListBoxSelect()
self._menuItemNameTextCtrl.SetFocus() self._menuItemNameTextCtrl.SetFocus()
self._menuItemNameTextCtrl.SetSelection(-1, -1) self._menuItemNameTextCtrl.SetSelection(-1, -1)
def OnDelete(self, event): def OnDelete(self, event):
self._extListBox.Delete(self._currentItemIndex) self._extListBox.Delete(self._currentItemIndex)
self._extensions.remove(self._currentItem) self._extensions.remove(self._currentItem)
self._currentItemIndex = min(self._currentItemIndex, self._extListBox.GetCount() - 1) self._currentItemIndex = min(self._currentItemIndex, self._extListBox.GetCount() - 1)
if self._currentItemIndex > -1: if self._currentItemIndex > -1:
self._extListBox.SetSelection(self._currentItemIndex) self._extListBox.SetSelection(self._currentItemIndex)

View File

@@ -27,6 +27,7 @@ _ = wx.GetTranslation
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------
FILENAME_MARKER = _("Found in file: ") FILENAME_MARKER = _("Found in file: ")
PROJECT_MARKER = _("Searching project: ") PROJECT_MARKER = _("Searching project: ")
FILE_MARKER = _("Searching file: ")
FIND_MATCHDIR = "FindMatchDir" FIND_MATCHDIR = "FindMatchDir"
FIND_MATCHDIRSUBFOLDERS = "FindMatchDirSubfolders" FIND_MATCHDIRSUBFOLDERS = "FindMatchDirSubfolders"
@@ -39,6 +40,7 @@ class FindInDirService(FindService.FindService):
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------
# Constants # Constants
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------
FINDFILE_ID = wx.NewId() # for bringing up Find in File dialog box
FINDALL_ID = wx.NewId() # for bringing up Find All dialog box FINDALL_ID = wx.NewId() # for bringing up Find All dialog box
FINDDIR_ID = wx.NewId() # for bringing up Find Dir 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) FindService.FindService.InstallControls(self, frame, menuBar, toolBar, statusBar, document)
editMenu = menuBar.GetMenu(menuBar.FindMenu(_("&Edit"))) 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_MENU(frame, FindInDirService.FINDALL_ID, self.ProcessEvent)
wx.EVT_UPDATE_UI(frame, FindInDirService.FINDALL_ID, self.ProcessUpdateUIEvent) 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_MENU(frame, FindInDirService.FINDDIR_ID, self.ProcessEvent)
wx.EVT_UPDATE_UI(frame, FindInDirService.FINDDIR_ID, self.ProcessUpdateUIEvent) 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): def ProcessEvent(self, event):
id = event.GetId() id = event.GetId()
if id == FindInDirService.FINDALL_ID: if id == FindInDirService.FINDFILE_ID:
view = wx.GetApp().GetDocumentManager().GetCurrentView() view = wx.GetApp().GetDocumentManager().GetCurrentView()
if hasattr(view, "GetCtrl") and view.GetCtrl() and hasattr(view.GetCtrl(), "GetSelectedText"): if hasattr(view, "GetCtrl") and view.GetCtrl() and hasattr(view.GetCtrl(), "GetSelectedText"):
self.ShowFindAllDialog(view.GetCtrl().GetSelectedText()) self.ShowFindInFileDialog(view.GetCtrl().GetSelectedText())
else: 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 return True
elif id == FindInDirService.FINDDIR_ID: elif id == FindInDirService.FINDDIR_ID:
view = wx.GetApp().GetDocumentManager().GetCurrentView() view = wx.GetApp().GetDocumentManager().GetCurrentView()
if hasattr(view, "GetCtrl") and view.GetCtrl() and hasattr(view.GetCtrl(), "GetSelectedText"): if hasattr(view, "GetCtrl") and view.GetCtrl() and hasattr(view.GetCtrl(), "GetSelectedText"):
self.ShowFindDirDialog(view.GetCtrl().GetSelectedText()) self.ShowFindInDirDialog(view.GetCtrl().GetSelectedText())
else: else:
self.ShowFindDirDialog() self.ShowFindInDirDialog()
return True return True
else: else:
return FindService.FindService.ProcessEvent(self, event) return FindService.FindService.ProcessEvent(self, event)
@@ -77,7 +89,14 @@ class FindInDirService(FindService.FindService):
def ProcessUpdateUIEvent(self, event): def ProcessUpdateUIEvent(self, event):
id = event.GetId() 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) projectService = wx.GetApp().GetService(ProjectEditor.ProjectService)
if projectService.GetFilesFromCurrentProject(): if projectService.GetFilesFromCurrentProject():
event.Enable(True) event.Enable(True)
@@ -90,7 +109,7 @@ class FindInDirService(FindService.FindService):
return FindService.FindService.ProcessUpdateUIEvent(self, event) return FindService.FindService.ProcessUpdateUIEvent(self, event)
def ShowFindDirDialog(self, findString=None): def ShowFindInDirDialog(self, findString=None):
config = wx.ConfigBase_Get() config = wx.ConfigBase_Get()
frame = wx.Dialog(wx.GetApp().GetTopWindow(), -1, _("Find in Directory"), size= (320,200)) frame = wx.Dialog(wx.GetApp().GetTopWindow(), -1, _("Find in Directory"), size= (320,200))
@@ -105,7 +124,7 @@ class FindInDirService(FindService.FindService):
findDirButton = wx.Button(frame, -1, _("Browse...")) findDirButton = wx.Button(frame, -1, _("Browse..."))
lineSizer.Add(findDirButton, 0, wx.LEFT, HALF_SPACE) lineSizer.Add(findDirButton, 0, wx.LEFT, HALF_SPACE)
contentSizer.Add(lineSizer, 0, wx.BOTTOM, SPACE) contentSizer.Add(lineSizer, 0, wx.BOTTOM, SPACE)
def OnBrowseButton(event): def OnBrowseButton(event):
dlg = wx.DirDialog(frame, _("Choose a directory:"), style=wx.DD_DEFAULT_STYLE) dlg = wx.DirDialog(frame, _("Choose a directory:"), style=wx.DD_DEFAULT_STYLE)
dir = dirCtrl.GetValue() dir = dirCtrl.GetValue()
@@ -126,10 +145,10 @@ class FindInDirService(FindService.FindService):
lineSizer = wx.BoxSizer(wx.VERTICAL) # let the line expand horizontally without vertical expansion lineSizer = wx.BoxSizer(wx.VERTICAL) # let the line expand horizontally without vertical expansion
lineSizer.Add(wx.StaticLine(frame, -1, size = (10,-1)), 0, flag=wx.EXPAND) lineSizer.Add(wx.StaticLine(frame, -1, size = (10,-1)), 0, flag=wx.EXPAND)
contentSizer.Add(lineSizer, flag=wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.BOTTOM, border=HALF_SPACE) contentSizer.Add(lineSizer, flag=wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.BOTTOM, border=HALF_SPACE)
if wx.Platform == "__WXMAC__": if wx.Platform == "__WXMAC__":
contentSizer.Add((-1, 10), 0, wx.EXPAND) contentSizer.Add((-1, 10), 0, wx.EXPAND)
lineSizer = wx.BoxSizer(wx.HORIZONTAL) lineSizer = wx.BoxSizer(wx.HORIZONTAL)
lineSizer.Add(wx.StaticText(frame, -1, _("Find what:")), 0, wx.ALIGN_CENTER | wx.RIGHT, HALF_SPACE) lineSizer.Add(wx.StaticText(frame, -1, _("Find what:")), 0, wx.ALIGN_CENTER | wx.RIGHT, HALF_SPACE)
if not findString: if not findString:
@@ -192,13 +211,13 @@ class FindInDirService(FindService.FindService):
status = frame.ShowModal() status = frame.ShowModal()
else: else:
passedCheck = True passedCheck = True
# save user choice state for this and other Find Dialog Boxes # save user choice state for this and other Find Dialog Boxes
dirString = dirCtrl.GetValue() dirString = dirCtrl.GetValue()
searchSubfolders = subfolderCtrl.IsChecked() searchSubfolders = subfolderCtrl.IsChecked()
self.SaveFindDirConfig(dirString, searchSubfolders) self.SaveFindInDirConfig(dirString, searchSubfolders)
findString = findCtrl.GetValue() findString = findCtrl.GetValue()
matchCase = matchCaseCtrl.IsChecked() matchCase = matchCaseCtrl.IsChecked()
wholeWord = wholeWordCtrl.IsChecked() wholeWord = wholeWordCtrl.IsChecked()
@@ -206,52 +225,23 @@ class FindInDirService(FindService.FindService):
self.SaveFindConfig(findString, wholeWord, matchCase, regExpr) self.SaveFindConfig(findString, wholeWord, matchCase, regExpr)
frame.Destroy() frame.Destroy()
if status == wx.ID_OK: if status == wx.ID_OK:
messageService = wx.GetApp().GetService(MessageService.MessageService) messageService = wx.GetApp().GetService(MessageService.MessageService)
messageService.ShowWindow() messageService.ShowWindow()
view = messageService.GetView() view = messageService.GetView()
if view: if view:
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT)) wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
view.ClearLines()
view.SetCallback(self.OnJumpToFoundLine)
view.AddLines(_("Searching for '%s' in '%s'\n\n") % (findString, dirString))
if os.path.isfile(dirString): try:
try: view.ClearLines()
docFile = file(dirString, 'r') view.SetCallback(self.OnJumpToFoundLine)
lineNum = 1
needToDisplayFilename = True view.AddLines(_("Searching for '%s' in '%s'\n\n") % (findString, dirString))
line = docFile.readline()
while line: if os.path.isfile(dirString):
count, foundStart, foundEnd, newText = self.DoFind(findString, None, line, 0, 0, True, matchCase, wholeWord, regExpr) try:
if count != -1: docFile = file(dirString, 'r')
if needToDisplayFilename:
view.AddLines(FILENAME_MARKER + dirString + "\n")
needToDisplayFilename = False
line = repr(lineNum).zfill(4) + ":" + line
view.AddLines(line)
line = docFile.readline()
lineNum += 1
if not needToDisplayFilename:
view.AddLines("\n")
except IOError, (code, message):
print _("Warning, unable to read file: '%s'. %s") % (dirString, message)
else:
# do search in files on disk
for root, dirs, files in os.walk(dirString):
if not searchSubfolders and root != dirString:
break
for name in files:
filename = os.path.join(root, name)
try:
docFile = file(filename, 'r')
except IOError, (code, message):
print _("Warning, unable to read file: '%s'. %s") % (filename, message)
continue
lineNum = 1 lineNum = 1
needToDisplayFilename = True needToDisplayFilename = True
line = docFile.readline() line = docFile.readline()
@@ -259,7 +249,7 @@ class FindInDirService(FindService.FindService):
count, foundStart, foundEnd, newText = self.DoFind(findString, None, line, 0, 0, True, matchCase, wholeWord, regExpr) count, foundStart, foundEnd, newText = self.DoFind(findString, None, line, 0, 0, True, matchCase, wholeWord, regExpr)
if count != -1: if count != -1:
if needToDisplayFilename: if needToDisplayFilename:
view.AddLines(FILENAME_MARKER + filename + "\n") view.AddLines(FILENAME_MARKER + dirString + "\n")
needToDisplayFilename = False needToDisplayFilename = False
line = repr(lineNum).zfill(4) + ":" + line line = repr(lineNum).zfill(4) + ":" + line
view.AddLines(line) view.AddLines(line)
@@ -267,27 +257,186 @@ class FindInDirService(FindService.FindService):
lineNum += 1 lineNum += 1
if not needToDisplayFilename: if not needToDisplayFilename:
view.AddLines("\n") view.AddLines("\n")
except IOError, (code, message):
view.AddLines(_("Search completed.")) print _("Warning, unable to read file: '%s'. %s") % (dirString, message)
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) else:
# do search in files on disk
for root, dirs, files in os.walk(dirString):
if not searchSubfolders and root != dirString:
break
for name in files:
filename = os.path.join(root, name)
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 completed."))
finally:
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
return True return True
else: else:
return False return False
def SaveFindDirConfig(self, dirString, searchSubfolders):
def SaveFindInDirConfig(self, dirString, searchSubfolders):
""" Save search dir patterns and flags to registry. """ Save search dir patterns and flags to registry.
dirString = search directory dirString = search directory
searchSubfolders = Search subfolders searchSubfolders = Search subfolders
""" """
config = wx.ConfigBase_Get() config = wx.ConfigBase_Get()
config.Write(FIND_MATCHDIR, dirString) config.Write(FIND_MATCHDIR, dirString)
config.WriteInt(FIND_MATCHDIRSUBFOLDERS, searchSubfolders) 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() config = wx.ConfigBase_Get()
frame = wx.Dialog(wx.GetApp().GetTopWindow(), -1, _("Find in Project"), size= (320,200)) 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) self.SaveFindConfig(findString, wholeWord, matchCase, regExpr)
frame.Destroy() frame.Destroy()
if status == wx.ID_OK: if status == wx.ID_OK:
messageService = wx.GetApp().GetService(MessageService.MessageService) self.DoFindIn(findString, matchCase, wholeWord, regExpr)
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)
return True return True
else: else:
return False 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) messageService = wx.GetApp().GetService(MessageService.MessageService)
lineText, pos = messageService.GetView().GetCurrLine() if defLineNum == -1:
if lineText == "\n" or lineText.find(FILENAME_MARKER) != -1 or lineText.find(PROJECT_MARKER) != -1: lineText, pos = messageService.GetView().GetCurrLine()
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 return
lineEnd = lineText.find(":") lineEnd = lineText.find(":")
if lineEnd == -1: if lineEnd == -1:
@@ -435,7 +567,10 @@ class FindInDirService(FindService.FindService):
lineNum = int(lineText[0:lineEnd]) lineNum = int(lineText[0:lineEnd])
text = messageService.GetView().GetText() text = messageService.GetView().GetText()
curPos = messageService.GetView().GetCurrentPos() if defLineNum == -1:
curPos = messageService.GetView().GetCurrentPos()
else:
curPos = messageService.GetView().GetControl().GetLineEndPosition(defLineNum)
startPos = text.rfind(FILENAME_MARKER, 0, curPos) startPos = text.rfind(FILENAME_MARKER, 0, curPos)
endPos = text.find("\n", startPos) 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 # time, we don't see the selection, it is scrolled off screen
foundView.SetSelection(startPos - 1 + len(lineText[lineEnd:].rstrip("\n")), startPos) foundView.SetSelection(startPos - 1 + len(lineText[lineEnd:].rstrip("\n")), startPos)
wx.GetApp().GetService(OutlineService.OutlineService).LoadOutline(foundView, position=startPos) wx.GetApp().GetService(OutlineService.OutlineService).LoadOutline(foundView, position=startPos)

View File

@@ -119,7 +119,7 @@ class HtmlCtrl(CodeEditor.CodeCtrl):
def SetViewDefaults(self): 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): def GetFontAndColorFromConfig(self):
@@ -156,7 +156,7 @@ class HtmlCtrl(CodeEditor.CodeCtrl):
class HtmlOptionsPanel(STCTextEditor.TextOptionsPanel): class HtmlOptionsPanel(STCTextEditor.TextOptionsPanel):
def __init__(self, parent, id): 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): 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 = menuBar.GetMenu(menuBar.FindMenu(_("&Edit")))
editMenu.AppendSeparator() 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_MENU(frame, MarkerService.MARKERTOGGLE_ID, frame.ProcessEvent)
wx.EVT_UPDATE_UI(frame, MarkerService.MARKERTOGGLE_ID, frame.ProcessUpdateUIEvent) 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_MENU(frame, MarkerService.MARKERDELALL_ID, frame.ProcessEvent)
wx.EVT_UPDATE_UI(frame, MarkerService.MARKERDELALL_ID, frame.ProcessUpdateUIEvent) 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_MENU(frame, MarkerService.MARKERNEXT_ID, frame.ProcessEvent)
wx.EVT_UPDATE_UI(frame, MarkerService.MARKERNEXT_ID, frame.ProcessUpdateUIEvent) 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_MENU(frame, MarkerService.MARKERPREV_ID, frame.ProcessEvent)
wx.EVT_UPDATE_UI(frame, MarkerService.MARKERPREV_ID, frame.ProcessUpdateUIEvent) wx.EVT_UPDATE_UI(frame, MarkerService.MARKERPREV_ID, frame.ProcessUpdateUIEvent)

View File

@@ -124,6 +124,7 @@ class MessageView(Service.ServiceView):
def AddLines(self, text): def AddLines(self, text):
self.GetControl().SetCurrentPos(self.GetControl().GetTextLength())
self.GetControl().SetReadOnly(False) self.GetControl().SetReadOnly(False)
self.GetControl().AddText(text) self.GetControl().AddText(text)
self.GetControl().SetReadOnly(True) self.GetControl().SetReadOnly(True)

View File

@@ -147,7 +147,11 @@ class OutlineView(Service.ServiceView):
return return
treeCtrl = self.GetControl() treeCtrl = self.GetControl()
parentItem = treeCtrl.GetRootItem() parentItem = treeCtrl.GetRootItem()
if not parentItem:
return
if expanded[0] != treeCtrl.GetItemText(parentItem): if expanded[0] != treeCtrl.GetItemText(parentItem):
return return
@@ -157,8 +161,7 @@ class OutlineView(Service.ServiceView):
treeCtrl.Expand(child) treeCtrl.Expand(child)
(child, cookie) = treeCtrl.GetNextChild(parentItem, cookie) (child, cookie) = treeCtrl.GetNextChild(parentItem, cookie)
if parentItem: treeCtrl.EnsureVisible(parentItem)
treeCtrl.EnsureVisible(parentItem)
class OutlineTreeCtrl(wx.TreeCtrl): class OutlineTreeCtrl(wx.TreeCtrl):
@@ -267,7 +270,7 @@ class OutlineTreeCtrl(wx.TreeCtrl):
if self.ItemHasChildren(item): if self.ItemHasChildren(item):
child, cookie = self.GetFirstChild(item) child, cookie = self.GetFirstChild(item)
while child and child.IsOk(): while child.IsOk():
self.FindDistanceToTreeItems(child, position, distances, items) self.FindDistanceToTreeItems(child, position, distances, items)
child, cookie = self.GetNextChild(item, cookie) child, cookie = self.GetNextChild(item, cookie)
return False return False

File diff suppressed because it is too large Load Diff

View File

@@ -17,6 +17,10 @@ import CodeEditor
import OutlineService import OutlineService
import os import os
import re import re
import FindInDirService
import activegrid.util.appdirs as appdirs
import activegrid.util.sysutils as sysutils
_ = wx.GetTranslation
class PHPDocument(CodeEditor.CodeDocument): 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): def __init__(self, parent, id=-1, style=wx.NO_FULL_REPAINT_ON_RESIZE):
CodeEditor.CodeCtrl.__init__(self, parent, id, style) 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.SetStyleBits(7)
self.SetKeyWords(4, string.join(PHPKEYWORDS)) self.SetKeyWords(4, string.join(PHPKEYWORDS))
self.SetProperty("fold.html", "1") 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): def CanWordWrap(self):
return True return True
def SetViewDefaults(self): 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): def GetFontAndColorFromConfig(self):
@@ -216,8 +254,110 @@ class PHPCtrl(CodeEditor.CodeCtrl):
class PHPOptionsPanel(STCTextEditor.TextOptionsPanel): class PHPOptionsPanel(STCTextEditor.TextOptionsPanel):
def __init__(self, parent, id): 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): def GetIcon(self):
return getPHPIcon() return getPHPIcon()

View File

@@ -73,7 +73,7 @@ class PerlCtrl(CodeEditor.CodeCtrl):
def SetViewDefaults(self): 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): def GetFontAndColorFromConfig(self):
@@ -130,7 +130,7 @@ class PerlCtrl(CodeEditor.CodeCtrl):
class PerlOptionsPanel(STCTextEditor.TextOptionsPanel): class PerlOptionsPanel(STCTextEditor.TextOptionsPanel):
def __init__(self, parent, id): 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): 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 sys # for GetAutoCompleteKeywordList
import MessageService # for OnCheckCode import MessageService # for OnCheckCode
import OutlineService import OutlineService
import FindInDirService
from UICommon import CaseInsensitiveCompare from UICommon import CaseInsensitiveCompare
try: try:
import checker # for pychecker import checker # for pychecker
@@ -143,11 +144,13 @@ class PythonView(CodeEditor.CodeView):
# Set cursor to Wait cursor # Set cursor to Wait cursor
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT)) wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
# This takes a while for involved code try:
checker.checkSyntax(self.GetDocument().GetFilename(), view) # This takes a while for involved code
checker.checkSyntax(self.GetDocument().GetFilename(), view)
# Set cursor to Default cursor finally:
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) # Set cursor to Default cursor
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
def OnJumpToFoundLine(self, event): def OnJumpToFoundLine(self, event):
@@ -369,8 +372,42 @@ class PythonCtrl(CodeEditor.CodeCtrl):
self.SetKeyWords(0, string.join(keyword.kwlist)) 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): 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): def GetFontAndColorFromConfig(self):
@@ -567,7 +604,7 @@ class PythonOptionsPanel(wx.Panel):
mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer = wx.BoxSizer(wx.VERTICAL)
mainSizer.Add(pathSizer, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, SPACE) 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) mainSizer.Add(self._otherOptions, 0, wx.EXPAND|wx.BOTTOM, SPACE)
self.SetSizer(mainSizer) self.SetSizer(mainSizer)
parent.AddPage(self, _("Python")) parent.AddPage(self, _("Python"))
@@ -577,7 +614,7 @@ class PythonOptionsPanel(wx.Panel):
defaultDir = os.path.dirname(self._pathTextCtrl.GetValue().strip()) defaultDir = os.path.dirname(self._pathTextCtrl.GetValue().strip())
defaultFile = os.path.basename(self._pathTextCtrl.GetValue().strip()) defaultFile = os.path.basename(self._pathTextCtrl.GetValue().strip())
if _WINDOWS: if _WINDOWS:
wildcard = _("Executable (*.exe)|*.exe|All (*.*)|*.*") wildcard = _("Executable (*.exe)|*.exe|All|*.*")
if not defaultFile: if not defaultFile:
defaultFile = "python.exe" defaultFile = "python.exe"
else: else:

View File

@@ -6,7 +6,7 @@
# #
# Created: 8/10/03 # Created: 8/10/03
# CVS-ID: $Id$ # CVS-ID: $Id$
# Copyright: (c) 2003-2005 ActiveGrid, Inc. # Copyright: (c) 2003-2006 ActiveGrid, Inc.
# License: wxWindows License # License: wxWindows License
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------
@@ -47,9 +47,15 @@ TEXT_STATUS_BAR_ID = wx.NewId()
class TextDocument(wx.lib.docview.Document): class TextDocument(wx.lib.docview.Document):
def __init__(self):
wx.lib.docview.Document .__init__(self)
self._inModify = False
def SaveObject(self, fileObject): def SaveObject(self, fileObject):
view = self.GetFirstView() view = self.GetFirstView()
fileObject.write(view.GetValue()) fileObject.write(view.GetValue())
view.SetModifyFalse()
return True return True
@@ -57,24 +63,31 @@ class TextDocument(wx.lib.docview.Document):
view = self.GetFirstView() view = self.GetFirstView()
data = fileObject.read() data = fileObject.read()
view.SetValue(data) view.SetValue(data)
view.SetModifyFalse()
return True return True
def IsModified(self): def IsModified(self):
view = self.GetFirstView() view = self.GetFirstView()
if view: if view:
return wx.lib.docview.Document.IsModified(self) or view.IsModified() return view.IsModified()
else: return False
return wx.lib.docview.Document.IsModified(self)
def Modify(self, mod): def Modify(self, modify):
if self._inModify:
return
self._inModify = True
view = self.GetFirstView() view = self.GetFirstView()
wx.lib.docview.Document.Modify(self, mod) if not modify and view:
if not mod and view:
view.SetModifyFalse() view.SetModifyFalse()
wx.lib.docview.Document.Modify(self, modify) # this must called be after the SetModifyFalse call above.
self._inModify = False
def OnCreateCommandProcessor(self): def OnCreateCommandProcessor(self):
# Don't create a command processor, it has its own # Don't create a command processor, it has its own
pass pass
@@ -142,6 +155,8 @@ class TextView(wx.lib.docview.View):
self._dynSash._view = self self._dynSash._view = self
self._textEditor = self.GetCtrlClass()(self._dynSash, -1, style=wx.NO_BORDER) self._textEditor = self.GetCtrlClass()(self._dynSash, -1, style=wx.NO_BORDER)
wx.EVT_LEFT_DOWN(self._textEditor, self.OnLeftClick) wx.EVT_LEFT_DOWN(self._textEditor, self.OnLeftClick)
self._textEditor.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModify)
self._CreateSizer(frame) self._CreateSizer(frame)
self.Activate() self.Activate()
frame.Show(True) frame.Show(True)
@@ -149,6 +164,10 @@ class TextView(wx.lib.docview.View):
return True return True
def OnModify(self, event):
self.GetDocument().Modify(self._textEditor.GetModify())
def _CreateSizer(self, frame): def _CreateSizer(self, frame):
sizer = wx.BoxSizer(wx.HORIZONTAL) sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self._dynSash, 1, wx.EXPAND) sizer.Add(self._dynSash, 1, wx.EXPAND)
@@ -161,6 +180,9 @@ class TextView(wx.lib.docview.View):
def OnUpdate(self, sender = None, hint = None): def OnUpdate(self, sender = None, hint = None):
if wx.lib.docview.View.OnUpdate(self, sender, hint):
return
if hint == "ViewStuff": if hint == "ViewStuff":
self.GetCtrl().SetViewDefaults() self.GetCtrl().SetViewDefaults()
elif hint == "Font": elif hint == "Font":
@@ -571,9 +593,11 @@ class TextView(wx.lib.docview.View):
def EnsureVisible(self, line): def EnsureVisible(self, line):
self.GetCtrl().EnsureVisible(line-1) # line numbering for editor is 0 based, we are 1 based. self.GetCtrl().EnsureVisible(line-1) # line numbering for editor is 0 based, we are 1 based.
def EnsureVisibleEnforcePolicy(self, line): def EnsureVisibleEnforcePolicy(self, line):
self.GetCtrl().EnsureVisibleEnforcePolicy(line-1) # line numbering for editor is 0 based, we are 1 based. self.GetCtrl().EnsureVisibleEnforcePolicy(line-1) # line numbering for editor is 0 based, we are 1 based.
def LineFromPosition(self, pos): def LineFromPosition(self, pos):
return self.GetCtrl().LineFromPosition(pos)+1 # line numbering for editor is 0 based, we are 1 based. 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): 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) wx.Panel.__init__(self, parent, id)
self._configPrefix = configPrefix self._configPrefix = configPrefix
self._hasWordWrap = hasWordWrap self._hasWordWrap = hasWordWrap
self._hasTabs = hasTabs self._hasTabs = hasTabs
self._hasFolding = hasFolding
SPACE = 10 SPACE = 10
HALF_SPACE = 5 HALF_SPACE = 5
config = wx.ConfigBase_Get() config = wx.ConfigBase_Get()
@@ -854,6 +879,9 @@ class TextOptionsPanel(wx.Panel):
self._viewRightEdgeCheckBox.SetValue(config.ReadInt(self._configPrefix + "EditorViewRightEdge", False)) self._viewRightEdgeCheckBox.SetValue(config.ReadInt(self._configPrefix + "EditorViewRightEdge", False))
self._viewLineNumbersCheckBox = wx.CheckBox(self, -1, _("Show line numbers")) self._viewLineNumbersCheckBox = wx.CheckBox(self, -1, _("Show line numbers"))
self._viewLineNumbersCheckBox.SetValue(config.ReadInt(self._configPrefix + "EditorViewLineNumbers", True)) 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: if self._hasTabs:
self._hasTabsCheckBox = wx.CheckBox(self, -1, _("Use spaces instead of tabs")) self._hasTabsCheckBox = wx.CheckBox(self, -1, _("Use spaces instead of tabs"))
self._hasTabsCheckBox.SetValue(not wx.ConfigBase_Get().ReadInt(self._configPrefix + "EditorUseTabs", False)) 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._viewIndentationGuideCheckBox, 0, wx.ALL, HALF_SPACE)
textPanelSizer.Add(self._viewRightEdgeCheckBox, 0, wx.ALL, HALF_SPACE) textPanelSizer.Add(self._viewRightEdgeCheckBox, 0, wx.ALL, HALF_SPACE)
textPanelSizer.Add(self._viewLineNumbersCheckBox, 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: if self._hasTabs:
textPanelSizer.Add(self._hasTabsCheckBox, 0, wx.ALL, HALF_SPACE) textPanelSizer.Add(self._hasTabsCheckBox, 0, wx.ALL, HALF_SPACE)
textIndentWidthSizer = wx.BoxSizer(wx.HORIZONTAL) textIndentWidthSizer = wx.BoxSizer(wx.HORIZONTAL)
@@ -947,6 +977,9 @@ class TextOptionsPanel(wx.Panel):
config.WriteInt(self._configPrefix + "EditorViewRightEdge", self._viewRightEdgeCheckBox.GetValue()) config.WriteInt(self._configPrefix + "EditorViewRightEdge", self._viewRightEdgeCheckBox.GetValue())
doViewStuffUpdate = doViewStuffUpdate or config.ReadInt(self._configPrefix + "EditorViewLineNumbers", True) != self._viewLineNumbersCheckBox.GetValue() doViewStuffUpdate = doViewStuffUpdate or config.ReadInt(self._configPrefix + "EditorViewLineNumbers", True) != self._viewLineNumbersCheckBox.GetValue()
config.WriteInt(self._configPrefix + "EditorViewLineNumbers", 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: if self._hasWordWrap:
doViewStuffUpdate = doViewStuffUpdate or config.ReadInt(self._configPrefix + "EditorWordWrap", False) != self._wordWrapCheckBox.GetValue() doViewStuffUpdate = doViewStuffUpdate or config.ReadInt(self._configPrefix + "EditorWordWrap", False) != self._wordWrapCheckBox.GetValue()
config.WriteInt(self._configPrefix + "EditorWordWrap", self._wordWrapCheckBox.GetValue()) config.WriteInt(self._configPrefix + "EditorWordWrap", self._wordWrapCheckBox.GetValue())
@@ -1062,13 +1095,15 @@ class TextCtrl(wx.stc.StyledTextCtrl):
event.Skip() 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() config = wx.ConfigBase_Get()
self.SetViewWhiteSpace(config.ReadInt(configPrefix + "EditorViewWhitespace", False)) self.SetViewWhiteSpace(config.ReadInt(configPrefix + "EditorViewWhitespace", False))
self.SetViewEOL(config.ReadInt(configPrefix + "EditorViewEOL", False)) self.SetViewEOL(config.ReadInt(configPrefix + "EditorViewEOL", False))
self.SetIndentationGuides(config.ReadInt(configPrefix + "EditorViewIndentationGuides", False)) self.SetIndentationGuides(config.ReadInt(configPrefix + "EditorViewIndentationGuides", False))
self.SetViewRightEdge(config.ReadInt(configPrefix + "EditorViewRightEdge", False)) self.SetViewRightEdge(config.ReadInt(configPrefix + "EditorViewRightEdge", False))
self.SetViewLineNumbers(config.ReadInt(configPrefix + "EditorViewLineNumbers", True)) self.SetViewLineNumbers(config.ReadInt(configPrefix + "EditorViewLineNumbers", True))
if hasFolding:
self.SetViewFolding(config.ReadInt(configPrefix + "EditorViewFolding", True))
if hasWordWrap: if hasWordWrap:
self.SetWordWrap(config.ReadInt(configPrefix + "EditorWordWrap", False)) self.SetWordWrap(config.ReadInt(configPrefix + "EditorWordWrap", False))
if hasTabs: # These methods do not exist in STCTextEditor and are meant for subclasses 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) 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): def CanWordWrap(self):
return True return True

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@
# #
# Created: 3/10/05 # Created: 3/10/05
# CVS-ID: $Id$ # CVS-ID: $Id$
# Copyright: (c) 2005 ActiveGrid, Inc. # Copyright: (c) 2005-2006 ActiveGrid, Inc.
# License: wxWindows License # License: wxWindows License
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------
@@ -15,12 +15,14 @@ import os.path
import wx import wx
import string import string
import ProjectEditor import ProjectEditor
import activegrid.util.sysutils as sysutils
import activegrid.util.strutils as strutils
import activegrid.util.appdirs as appdirs 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 _ = 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: if not choiceDirs:
choiceDirs = [] choiceDirs = []
@@ -61,8 +63,8 @@ def CreateDirectoryControl( parent, fileLabel=_("File Name:"), dirLabel=_("Direc
if os.getcwd() not in choiceDirs: if os.getcwd() not in choiceDirs:
choiceDirs.append(os.getcwd()) choiceDirs.append(os.getcwd())
if appdirs.documents_folder not in choiceDirs: if appdirs.getSystemDir() not in choiceDirs:
choiceDirs.append(appdirs.documents_folder) choiceDirs.append(appdirs.getSystemDir())
if not startingDirectory: if not startingDirectory:
startingDirectory = os.getcwd() startingDirectory = os.getcwd()
@@ -85,12 +87,18 @@ def CreateDirectoryControl( parent, fileLabel=_("File Name:"), dirLabel=_("Direc
else: else:
name = _("%s.%s") % (nameCtrlValue, fileExtension) name = _("%s.%s") % (nameCtrlValue, fileExtension)
dlg = wx.FileDialog(parent, _("Choose a filename and directory"), if not useDirDialog:
dlg = wx.FileDialog(parent, _("Choose a filename and directory"),
defaultDir = dirControl.GetValue().strip(), defaultDir = dirControl.GetValue().strip(),
defaultFile = name, defaultFile = name,
wildcard= "*.%s" % fileExtension, wildcard= "*.%s" % fileExtension,
style=wx.SAVE|wx.CHANGE_DIR) 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: if dlg.ShowModal() != wx.ID_OK:
dlg.Destroy() dlg.Destroy()
return return
@@ -98,49 +106,78 @@ def CreateDirectoryControl( parent, fileLabel=_("File Name:"), dirLabel=_("Direc
dlg.Destroy() dlg.Destroy()
if path: if path:
dir, filename = os.path.split(path) if not useDirDialog:
if dirControl.FindString(dir) == wx.NOT_FOUND: dir, filename = os.path.split(path)
dirControl.Insert(dir, 0) if dirControl.FindString(dir) == wx.NOT_FOUND:
dirControl.SetValue(dir) dirControl.Insert(dir, 0)
dirControl.SetToolTipString(dir) dirControl.SetValue(dir)
nameControl.SetValue(filename) dirControl.SetToolTipString(dir)
nameControl.SetValue(filename)
else:
dirControl.SetValue(path)
dirControl.SetToolTipString(path)
parent.Bind(wx.EVT_BUTTON, OnFindDirClick, button) 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() projName = nameControl.GetValue().strip()
if projName == "": if projName == "":
wx.MessageBox(_("Please provide a %sfile name.") % infoString, _("Provide a File Name")) wx.MessageBox(_("Please provide a %sfile name.") % infoString, _("Provide a File Name"))
return False 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: if projName.find(' ') != -1:
wx.MessageBox(_("Please provide a %sfile name that does not contains spaces.") % infoString, _("Spaces in File Name")) wx.MessageBox(_("Please provide a %sfile name that does not contains spaces.") % infoString, _("Spaces in File Name"))
return False return False
if not os.path.exists(dirControl.GetValue()): if validClassName:
wx.MessageBox(_("That %sdirectory does not exist. Please choose an existing directory.") % infoString, _("Provide a Valid Directory")) 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
dirName = dirControl.GetValue().strip()
if dirName == "":
wx.MessageBox(_("No directory. Please provide a directory."), _("Provide a Directory"))
return False return False
if os.sep == "\\" and dirName.find("/") != -1:
filePath = os.path.join(dirControl.GetValue(), MakeNameEndInExtension(projName, "." + fileExtension)) wx.MessageBox(_("Wrong delimiter '/' found in directory path. Use '%s' as delimiter.") % os.sep, _("Provide a Valid Directory"))
if os.path.exists(filePath): return False
if allowOverwriteOnPrompt: if not os.path.exists(dirName):
res = wx.MessageBox(_("That %sfile already exists. Would you like to overwrite it.") % infoString, "File Exists", style=wx.YES_NO|wx.NO_DEFAULT) wx.MessageBox(_("That %sdirectory does not exist. Please choose an existing directory.") % infoString, _("Provide a Valid Directory"))
return (res == wx.YES) return False
else: if not ignoreFileConflicts:
wx.MessageBox(_("That %sfile already exists. Please choose a different name.") % infoString, "File Exists") filePath = os.path.join(dirName, MakeNameEndInExtension(projName, "." + fileExtension))
return False 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)
return (res == wx.YES)
else:
wx.MessageBox(_("That %sfile already exists. Please choose a different name.") % infoString, "File Exists")
return False
return True return True
HALF_SPACE = 5 HALF_SPACE = 5
flexGridSizer = wx.FlexGridSizer(cols = 3, vgap = HALF_SPACE, hgap = HALF_SPACE) flexGridSizer = wx.FlexGridSizer(cols = 3, vgap = HALF_SPACE, hgap = HALF_SPACE)
flexGridSizer.AddGrowableCol(1,1) flexGridSizer.AddGrowableCol(1,1)
flexGridSizer.Add(nameLabelText, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT) if not useDirDialog:
flexGridSizer.Add(nameControl, 2, flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND) flexGridSizer.Add(nameLabelText, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)
flexGridSizer.Add(button, flag=wx.ALIGN_RIGHT|wx.LEFT, border=HALF_SPACE) 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)
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)
if returnAll: if returnAll:
return nameControl, dirControl, flexGridSizer, Validate, allControls return nameControl, dirControl, flexGridSizer, Validate, allControls
else: else:
@@ -188,8 +225,8 @@ def CreateDirectoryOnlyControl( parent, dirLabel=_("Location:"), startingDirecto
if os.getcwd() not in choiceDirs: if os.getcwd() not in choiceDirs:
choiceDirs.append(os.getcwd()) choiceDirs.append(os.getcwd())
if appdirs.documents_folder not in choiceDirs: if appdirs.getSystemDir() not in choiceDirs:
choiceDirs.append(appdirs.documents_folder) choiceDirs.append(appdirs.getSystemDir())
if not startingDirectory: if not startingDirectory:
@@ -221,6 +258,9 @@ def CreateDirectoryOnlyControl( parent, dirLabel=_("Location:"), startingDirecto
if dirName == "": if dirName == "":
wx.MessageBox(_("Please provide a directory."), _("Provide a Directory")) wx.MessageBox(_("Please provide a directory."), _("Provide a Directory"))
return False 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): if not os.path.exists(dirName):
wx.MessageBox(_("That directory does not exist. Please choose an existing directory."), _("Provide a Valid Directory")) wx.MessageBox(_("That directory does not exist. Please choose an existing directory."), _("Provide a Valid Directory"))
return False return False
@@ -241,17 +281,25 @@ def CreateNameOnlyControl( parent, fileLabel, startingName="", startingDirectory
fileLabelText = wx.StaticText(parent, -1, fileLabel) fileLabelText = wx.StaticText(parent, -1, fileLabel)
nameControl = wx.TextCtrl(parent, -1, startingName, size=(-1,-1)) 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() projName = nameControl.GetValue().strip()
if projName == "": if projName == "":
wx.MessageBox(_("Blank name. Please enter a valid name."), _("Project Name")) wx.MessageBox(_("Blank name. Please enter a valid name."), _("Project Name"))
return False return False
if noFirstCharDigit and projName[0].isdigit():
wx.MessageBox(_("Name cannot start with a number. Please enter a valid name."), _("Project Name"))
return False
if projName.find(' ') != -1: if projName.find(' ') != -1:
wx.MessageBox(_("Spaces in name. Name cannot have spaces.") % infoString, _("Project Name")) wx.MessageBox(_("Spaces in name. Name cannot have spaces."), _("Project Name"))
return False 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.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) path = os.path.join(startingDirectoryControl.GetValue().strip(), projName)
if os.path.exists(path): if os.path.exists(path):
if os.path.isdir(path): if os.path.isdir(path):
@@ -280,6 +328,29 @@ def CreateNameOnlyControl( parent, fileLabel, startingName="", startingDirectory
return nameControl, flexGridSizer, Validate 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(): def GetCurrentProject():
projectDocument = None projectDocument = None
projectService = wx.GetApp().GetService(ProjectEditor.ProjectService) projectService = wx.GetApp().GetService(ProjectEditor.ProjectService)
@@ -330,6 +401,16 @@ def GetPythonExecPath():
return pythonExecPath 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): def _DoRemoveRecursive(path, skipFile=None, skipped=False):
if path == skipFile: if path == skipFile:
skipped = True skipped = True
@@ -362,16 +443,62 @@ def CaseInsensitiveCompare(s1, s2):
def GetAnnotation(model, elementName): def GetAnnotation(model, elementName):
""" Get an object's annotation used for tooltips """ """ 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__ ct = model.__xsdcomplextype__
if ct: else:
el = ct.findElement(elementName) ct = None
if el and el.annotation:
return el.annotation if ct:
el = ct.findElement(elementName)
if el and el.annotation:
return el.annotation
return "" 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 # Methods for finding application level info
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------
@@ -435,7 +562,8 @@ def GetAppDocMgrForDoc(doc):
def GetAppInfoLanguage(doc=None): def GetAppInfoLanguage(doc=None):
from activegrid.server.deployment import LANGUAGE_DEFAULT from activegrid.server.projectmodel import LANGUAGE_DEFAULT
if doc: if doc:
language = doc.GetAppInfo().language language = doc.GetAppInfo().language
else: else:
@@ -449,3 +577,159 @@ def GetAppInfoLanguage(doc=None):
doc.GetAppInfo().language = language # once it is selected, it must be set. doc.GetAppInfo().language = language # once it is selected, it must be set.
return language 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): 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): def GetFontAndColorFromConfig(self):
@@ -115,7 +115,7 @@ class XmlCtrl(CodeEditor.CodeCtrl):
class XmlOptionsPanel(STCTextEditor.TextOptionsPanel): class XmlOptionsPanel(STCTextEditor.TextOptionsPanel):
def __init__(self, parent, id): 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): 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. 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. 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 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 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: elif env:
uenv = {} uenv = {}
for key, val in env.items(): 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 env = uenv
hProcess, hThread, processId, threadId\ hProcess, hThread, processId, threadId\
= win32process.CreateProcess(appName, cmd, processSA, = win32process.CreateProcess(appName, cmd, processSA,

View File

@@ -14,7 +14,16 @@ import copy
import os import os
import os.path import os.path
import activegrid.util.xmlutils as xmlutils import activegrid.util.xmlutils as xmlutils
from IDE import ACTIVEGRID_BASE_IDE 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: if not ACTIVEGRID_BASE_IDE:
import activegrid.model.basedocmgr as basedocmgr import activegrid.model.basedocmgr as basedocmgr
import AppInfo import AppInfo
@@ -27,64 +36,6 @@ if not ACTIVEGRID_BASE_IDE:
PROJECT_VERSION_050730 = '10' PROJECT_VERSION_050730 = '10'
PROJECT_VERSION_050826 = '11' 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 # Classes
@@ -93,7 +44,7 @@ def save(fileObject, project, productionDeployment=False):
class BaseProject(object): class BaseProject(object):
__xmlname__ = "project" __xmlname__ = "project"
__xmlexclude__ = ('fileName', '_projectDir', '_getDocCallback') __xmlexclude__ = ('fileName', '_projectDir', '_getDocCallback', '_cacheEnabled')
__xmlattributes__ = ("_homeDir", "version") __xmlattributes__ = ("_homeDir", "version")
__xmlrename__ = { "_homeDir":"homeDir", "_appInfo":"appInfo" } __xmlrename__ = { "_homeDir":"homeDir", "_appInfo":"appInfo" }
__xmlflattensequence__ = { "_files":("file",) } __xmlflattensequence__ = { "_files":("file",) }
@@ -107,9 +58,15 @@ class BaseProject(object):
self._files = [] self._files = []
self._projectDir = None # default for homeDir, set on load self._projectDir = None # default for homeDir, set on load
self._homeDir = None # user set homeDir for use in calculating relative path self._homeDir = None # user set homeDir for use in calculating relative path
self._cacheEnabled = 0
if not ACTIVEGRID_BASE_IDE: if not ACTIVEGRID_BASE_IDE:
self._appInfo = AppInfo.AppInfo() self._appInfo = AppInfo.AppInfo()
def initialize(self):
for file in self._files:
file._parentProj = self
def __copy__(self): def __copy__(self):
clone = Project() clone = Project()
@@ -117,18 +74,13 @@ class BaseProject(object):
clone._projectDir = self._projectDir clone._projectDir = self._projectDir
clone._homeDir = self._homeDir clone._homeDir = self._homeDir
if not ACTIVEGRID_BASE_IDE: if not ACTIVEGRID_BASE_IDE:
clone._appInfo = self._appInfo clone._appInfo = copy.copy(self._appInfo)
return clone return clone
def initialize(self):
""" Required method for xmlmarshaller """
pass
def GetAppInfo(self): def GetAppInfo(self):
return self._appInfo return self._appInfo
def AddFile(self, filePath=None, logicalFolder=None, type=None, name=None, file=None): def AddFile(self, filePath=None, logicalFolder=None, type=None, name=None, file=None):
""" Usage: self.AddFile(filePath, logicalFolder, type, name) # used for initial generation of object """ Usage: self.AddFile(filePath, logicalFolder, type, name) # used for initial generation of object
@@ -138,7 +90,7 @@ class BaseProject(object):
if file: if file:
self._files.append(file) self._files.append(file)
else: 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): def RemoveFile(self, file):
@@ -150,7 +102,7 @@ class BaseProject(object):
for file in self._files: for file in self._files:
if file.filePath == filePath: if file.filePath == filePath:
return file return file
return None return None
@@ -160,6 +112,10 @@ class BaseProject(object):
filePaths = property(_GetFilePaths) filePaths = property(_GetFilePaths)
def _GetProjectFiles(self):
return self._files
projectFiles = property(_GetProjectFiles)
def _GetLogicalFolders(self): def _GetLogicalFolders(self):
folders = [] folders = []
@@ -170,7 +126,7 @@ class BaseProject(object):
logicalFolders = property(_GetLogicalFolders) logicalFolders = property(_GetLogicalFolders)
def _GetPhysicalFolders(self): def _GetPhysicalFolders(self):
physicalFolders = [] physicalFolders = []
@@ -189,11 +145,11 @@ class BaseProject(object):
return self._homeDir return self._homeDir
else: else:
return self._projectDir return self._projectDir
def _SetHomeDir(self, parentPath): def _SetHomeDir(self, parentPath):
self._homeDir = parentPath self._homeDir = parentPath
def _IsDefaultHomeDir(self): def _IsDefaultHomeDir(self):
return (self._homeDir == None) return (self._homeDir == None)
@@ -212,7 +168,7 @@ class BaseProject(object):
if relFolder and relFolder not in relativeFolders: if relFolder and relFolder not in relativeFolders:
relativeFolders.append(relFolder) relativeFolders.append(relFolder)
return relativeFolders return relativeFolders
def AbsToRelativePath(self): def AbsToRelativePath(self):
for file in self._files: for file in self._files:
@@ -224,6 +180,33 @@ class BaseProject(object):
file.RelativeToAbsPath(self.homeDir) 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 # BaseDocumentMgr methods
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------
@@ -231,7 +214,7 @@ class BaseProject(object):
def fullPath(self, fileName): def fullPath(self, fileName):
fileName = super(BaseProject, self).fullPath(fileName) fileName = super(BaseProject, self).fullPath(fileName)
if os.path.isabs(fileName): if os.path.isabs(fileName):
absPath = fileName absPath = fileName
elif self.homeDir: elif self.homeDir:
@@ -242,7 +225,7 @@ class BaseProject(object):
def documentRefFactory(self, name, fileType, filePath): 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): def findAllRefs(self):
@@ -256,8 +239,8 @@ class BaseProject(object):
if not xformdir: if not xformdir:
xformdir = self.homeDir xformdir = self.homeDir
return xformdir return xformdir
def setRefs(self, files): def setRefs(self, files):
self._files = files self._files = files
@@ -295,16 +278,17 @@ if ACTIVEGRID_BASE_IDE:
else: else:
class Project(BaseProject, basedocmgr.BaseDocumentMgr): class Project(BaseProject, basedocmgr.BaseDocumentMgr):
pass pass
class ProjectFile(object): class ProjectFile(object):
__xmlname__ = "file" __xmlname__ = "file"
__xmlexclude__ = ('_getDocCallback', '_docCallbackCacheReturnValue', '_docModelCallbackCacheReturnValue', '_doc',) __xmlexclude__ = ('_parentProj', '_getDocCallback', '_docCallbackCacheReturnValue', '_docModelCallbackCacheReturnValue', '_doc',)
__xmlattributes__ = ["filePath", "logicalFolder", "type", "name"] __xmlattributes__ = ["filePath", "logicalFolder", "type", "name"]
__xmldefaultnamespace__ = xmlutils.AG_NS_URL __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.filePath = filePath
self.logicalFolder = logicalFolder self.logicalFolder = logicalFolder
self.type = type self.type = type
@@ -316,35 +300,44 @@ class ProjectFile(object):
def _GetDocumentModel(self): def _GetDocumentModel(self):
# possible bug is if document gets replaced outside of IDE, where we'll return previous doc. if (self._docCallbackCacheReturnValue
# originally added a timestamp check but that increased the time again to 4x and (self._parentProj.cacheEnabled or self._docCallbackCacheReturnValue.IsDocumentModificationDateCorrect())):
if self._docModelCallbackCacheReturnValue: # accelerator for caching document, got 4x speed up.
return self._docModelCallbackCacheReturnValue return self._docModelCallbackCacheReturnValue
if self._getDocCallback: if self._getDocCallback:
self._docCallbackCacheReturnValue, self._docModelCallbackCacheReturnValue = self._getDocCallback(self.filePath) self._docCallbackCacheReturnValue, self._docModelCallbackCacheReturnValue = self._getDocCallback(self.filePath)
return self._docModelCallbackCacheReturnValue return self._docModelCallbackCacheReturnValue
return None return None
document = property(_GetDocumentModel) document = property(_GetDocumentModel)
def _GetDocument(self): def _GetDocument(self):
# Hack, just return the IDE document wrapper that corresponds to the runtime document model # Return the IDE document wrapper that corresponds to the runtime document model
# callers should have called ".document" before calling ".ideDocument" if (self._docCallbackCacheReturnValue
if self._docCallbackCacheReturnValue: # accelerator for caching document, got 4x speed up. and (self._parentProj.cacheEnabled or self._docCallbackCacheReturnValue.IsDocumentModificationDateCorrect())):
return self._docCallbackCacheReturnValue return self._docCallbackCacheReturnValue
if self._getDocCallback:
self._docCallbackCacheReturnValue, self._docModelCallbackCacheReturnValue = self._getDocCallback(self.filePath)
return self._docCallbackCacheReturnValue
return None return None
ideDocument = property(_GetDocument) ideDocument = property(_GetDocument)
def ClearCache(self):
self._docCallbackCacheReturnValue = None
self._docModelCallbackCacheReturnValue = None
def _typeEnumeration(self): def _typeEnumeration(self):
return basedocmgr.FILE_TYPE_LIST return basedocmgr.FILE_TYPE_LIST
def _GetPhysicalFolder(self): def _GetPhysicalFolder(self):
dir = None dir = None
@@ -356,7 +349,7 @@ class ProjectFile(object):
physicalFolder = property(_GetPhysicalFolder) physicalFolder = property(_GetPhysicalFolder)
def GetRelativeFolder(self, parentPath): def GetRelativeFolder(self, parentPath):
parentPathLen = len(parentPath) parentPathLen = len(parentPath)
@@ -364,7 +357,7 @@ class ProjectFile(object):
dir = None dir = None
if self.filePath: if self.filePath:
dir = os.path.dirname(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 dir = "." + dir[parentPathLen:] # convert to relative path
if os.sep != '/': if os.sep != '/':
dir = dir.replace(os.sep, '/') # always save out with '/' as path separator for cross-platform compatibility. 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) """ """ Used to convert path to relative path for saving (disk format) """
parentPathLen = len(parentPath) parentPathLen = len(parentPath)
if self.filePath.startswith(parentPath): if self.filePath.startswith(parentPath + os.sep):
self.filePath = "." + self.filePath[parentPathLen:] # convert to relative path self.filePath = "." + self.filePath[parentPathLen:] # convert to relative path
if os.sep != '/': if os.sep != '/':
self.filePath = self.filePath.replace(os.sep, '/') # always save out with '/' as path separator for cross-platform compatibility. 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): def RelativeToAbsPath(self, parentPath):
""" Used to convert path to absolute path (for any necessary disk access) """ """ Used to convert path to absolute path (for any necessary disk access) """
if self.filePath.startswith("."): # relative to project file if self.filePath.startswith("./"): # relative to project file
self.filePath = os.path.normpath(os.path.join(parentPath, self.filePath)) self.filePath = os.path.normpath(os.path.join(parentPath, self.filePath)) # also converts '/' to os.sep
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------
@@ -399,21 +392,29 @@ class ProjectFile(object):
import wx.lib.docview import wx.lib.docview
if not self._doc: if not self._doc:
docMgr = wx.GetApp().GetDocumentManager() docMgr = wx.GetApp().GetDocumentManager()
doc = docMgr.CreateDocument(self.filePath, docMgr.GetFlags()|wx.lib.docview.DOC_SILENT|wx.lib.docview.DOC_OPEN_ONCE|wx.lib.docview.DOC_NO_VIEW) try:
if (doc == None): # already open doc = docMgr.CreateDocument(self.filePath, docMgr.GetFlags()|wx.lib.docview.DOC_SILENT|wx.lib.docview.DOC_OPEN_ONCE|wx.lib.docview.DOC_NO_VIEW)
docs = docMgr.GetDocuments() if (doc == None): # already open
for d in docs: docs = docMgr.GetDocuments()
if d.GetFilename() == self.filePath: for d in docs:
doc = d if d.GetFilename() == self.filePath:
break doc = d
self._doc = doc break
self._doc = doc
except Exception,e:
aglogging.reportException(e, stacktrace=True)
return self._doc return self._doc
def _GetLocalServiceProcessName(self): def _GetLocalServiceProcessName(self):
# HACK: temporary solution to getting process name from wsdlag file. # 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) processName = property(_GetLocalServiceProcessName)
@@ -458,33 +459,39 @@ class ProjectFile(object):
localServiceClassName = property(_GetLocalServiceClassName, _SetLocalServiceClassName) 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 # only activate this code if we programatically need to access these values
## def _GetRssServiceBaseURL(self): ## def _GetRssServiceBaseURL(self):
## return self._GetDoc().GetModel().rssServiceBaseURL ## return self._GetDoc().GetModel().rssServiceBaseURL
## ##
## ##
## def _SetRssServiceBaseURL(self, baseURL): ## def _SetRssServiceBaseURL(self, baseURL):
## self._GetDoc().GetModel().rssServiceBaseURL = baseURL ## self._GetDoc().GetModel().rssServiceBaseURL = baseURL
## ##
## ##
## rssServiceBaseURL = property(_GetRssServiceBaseURL, _SetRssServiceBaseURL) ## rssServiceBaseURL = property(_GetRssServiceBaseURL, _SetRssServiceBaseURL)
## ##
## ##
## def _GetRssServiceRssVersion(self): ## def _GetRssServiceRssVersion(self):
## return self._GetDoc().GetModel().rssServiceRssVersion ## return self._GetDoc().GetModel().rssServiceRssVersion
## ##
## ##
## def _SetRssServiceRssVersion(self, rssVersion): ## def _SetRssServiceRssVersion(self, rssVersion):
## self._GetDoc().GetModel().rssServiceRssVersion = rssVersion ## self._GetDoc().GetModel().rssServiceRssVersion = rssVersion
## ##
## ##
## rssServiceRssVersion = property(_GetRssServiceRssVersion, _SetRssServiceRssVersion) ## rssServiceRssVersion = property(_GetRssServiceRssVersion, _SetRssServiceRssVersion)
def _GetServiceRefServiceType(self): def _GetServiceRefServiceType(self):
# HACK: temporary solution to getting service type from wsdlag file. # 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'): if hasattr(model, 'serviceType'):
return model.serviceType return model.serviceType
else: else:
@@ -494,25 +501,27 @@ class ProjectFile(object):
def _SetServiceRefServiceType(self, serviceType): def _SetServiceRefServiceType(self, serviceType):
# HACK: temporary solution to getting service type from wsdlag file. # HACK: temporary solution to getting service type from wsdlag file.
self._GetDoc().GetModel().serviceType = serviceType self._GetDoc().GetModel().serviceType = serviceType
serviceType = property(_GetServiceRefServiceType, _SetServiceRefServiceType) serviceType = property(_GetServiceRefServiceType, _SetServiceRefServiceType)
def getExternalPackage(self): def getExternalPackage(self):
# HACK: temporary solution to getting custom code filename from wsdlag file. # 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() appInfo = self._GetDoc().GetAppInfo()
if appInfo.language == None: if appInfo.language == None:
language = deploymentlib.LANGUAGE_DEFAULT language = wx.ConfigBase_Get().Read(ProjectEditor.APP_LAST_LANGUAGE, projectmodel.LANGUAGE_DEFAULT)
else: else:
language = appInfo.language language = appInfo.language
if language == deploymentlib.LANGUAGE_PYTHON: if language == projectmodel.LANGUAGE_PYTHON:
suffix = ".py" suffix = ".py"
elif language == deploymentlib.LANGUAGE_PHP: elif language == projectmodel.LANGUAGE_PHP:
suffix = ".php" suffix = ".php"
pyFilename = self.name + suffix pyFilename = self.name + suffix
return self._GetDoc().GetAppDocMgr().fullPath(pyFilename) return self._GetDoc().GetAppDocMgr().fullPath(pyFilename)
@@ -543,7 +552,63 @@ class Project_10:
def upgradeVersion(self): def upgradeVersion(self):
currModel = Project() currModel = Project()
for file in self._files: for file in self._files:
currModel._files.append(ProjectFile(file)) currModel._files.append(ProjectFile(currModel, file))
return currModel 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 * from activegrid.util.lang import *
import activegrid.util.objutils as objutils import activegrid.util.objutils as objutils
import activegrid.util.sysutils as sysutils import activegrid.util.sysutils as sysutils
import activegrid.util.appdirs as appdirs
LEVEL_FATAL = logging.FATAL LEVEL_FATAL = logging.FATAL
LEVEL_ERROR = logging.ERROR LEVEL_ERROR = logging.ERROR
@@ -27,38 +28,47 @@ LEVEL_INFO = logging.INFO
LEVEL_DEBUG = logging.DEBUG LEVEL_DEBUG = logging.DEBUG
EXCEPTION_INFO = 'exceptionInfo' EXCEPTION_INFO = 'exceptionInfo'
loggingInitialized = False
LOG_MODE_IDE = 1 LOG_MODE_IDE = 1
LOG_MODE_TESTRUN = 2 LOG_MODE_TESTRUN = 2
LOG_MODE_RUN = 3 LOG_MODE_RUN = 3
def initLogging(mode): def initLogging(mode, force=False):
configFile = None global ag_debugLogger, loggingInitialized
if (mode == LOG_MODE_IDE): if (force or not loggingInitialized):
configFile = os.getenv("AG_LOGCONFIG_IDE") loggingInitialized = True
elif (mode == LOG_MODE_TESTRUN): configFile = None
configFile = os.getenv("AG_LOGCONFIG_TESTRUN")
else:
configFile = os.getenv("AG_LOGCONFIG_RUN")
if ((configFile == None) or not os.path.exists(configFile)):
if (mode == LOG_MODE_IDE): if (mode == LOG_MODE_IDE):
configFile = "IDELog" configFile = os.getenv("AG_LOGCONFIG_IDE")
elif (mode == LOG_MODE_TESTRUN): elif (mode == LOG_MODE_TESTRUN):
configFile = "TestRunLog" configFile = os.getenv("AG_LOGCONFIG_PYTESTRUN")
else: else:
configFile = "RunLog" configFile = os.getenv("AG_LOGCONFIG_RUN")
configFile = sysutils.mainModuleDir + "/py" + configFile + ".ini" if ((configFile == None) or not os.path.exists(configFile)):
if (os.path.exists(configFile)): if (mode == LOG_MODE_IDE):
fileConfig(configFile) configFile = "IDELog"
else: elif (mode == LOG_MODE_TESTRUN):
defaultStream = sys.stderr configFile = "TestRunLog"
if (mode == LOG_MODE_RUN): else:
defaultStream = sys.stdout configFile = "RunLog"
handler = logging.StreamHandler(defaultStream) configFile = os.path.join(appdirs.getSystemDir(appdirs.AG_LOGS_DIR), "py" + configFile + ".ini")
handler.setLevel(logging.INFO) if (os.path.exists(configFile)):
handler.setFormatter(logging.Formatter("%(asctime)s %(name)s %(levelname)s: %(message)s")) print "Using logging configuration file: %s" % configFile
logging.getLogger().addHandler(handler) fileConfig(configFile)
return 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.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") ag_debugLogger = logging.getLogger("activegrid.debug")
def log(logger, level, msg, *params): def log(logger, level, msg, *params):
@@ -181,21 +191,18 @@ def addExceptionInfo(e, key, value):
if not e.exceptionInfo.has_key(key): # Never overwrite exception info since we assume earlier info is more specific if not e.exceptionInfo.has_key(key): # Never overwrite exception info since we assume earlier info is more specific
e.exceptionInfo[key] = value 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) exstr = exceptionToString(exception, stacktrace, diffable)
if (out == None): if (out == None):
print exstr print exstr
else: else:
print >> out, exstr print >> out, exstr
def exceptionToString(exception=None, stacktrace=False, diffable=False): def exceptionToString(exception, stacktrace=False, diffable=False):
if (exception == None): extype = objutils.typeToString(exception)
extype, val, t = sys.exc_info() val = exception
else: if (stacktrace):
extype = objutils.typeToString(exception) e,v,t = sys.exc_info()
val = exception
if (stacktrace):
e,v,t = sys.exc_info()
if (diffable): if (diffable):
exstr = removeFileRefs(str(val)) exstr = removeFileRefs(str(val))
else: else:

View File

@@ -2,7 +2,7 @@
# Name: appdirs.py # Name: appdirs.py
# Purpose: Utilities for retrieving special application dirs # Purpose: Utilities for retrieving special application dirs
# #
# Author: Kevin Ollivier # Author: Kevin Ollivier, Jeff Norton
# #
# Created: 8/27/05 # Created: 8/27/05
# CVS-ID: $Id$ # CVS-ID: $Id$
@@ -10,50 +10,117 @@
# License: wxWindows License # License: wxWindows License
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------
# NOTE: This was made a separate file because it depends upon the from activegrid.util.lang import *
# 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.
import sys import sys
import os import os
import string import string
import wx import activegrid.util.sysutils as sysutils
def isWindows(): def _getSystemDir(kind):
return os.name == 'nt' if (kind == AG_LOGS_DIR):
return os.path.join(getSystemDir(AG_SYSTEM_DIR) , "logs")
def _generateDocumentsDir(): elif (kind == AG_DEMOS_DIR):
path = "" return os.path.join(getSystemDir(AG_SYSTEM_DIR), "demos")
if sys.platform == "win32": else:
from win32com.shell import shell, shellcon path = ""
path=shell.SHGetFolderPath(0, shellcon.CSIDL_PERSONAL, None, 0) if (sysutils.isServer()):
elif sys.platform == "darwin": path = os.getenv("ACTIVEGRID_SERVER_HOME")
import macfs, MACFS if ((path is None) or (len(path) < 1)):
fsspec_disk, fsspec_desktop = macfs.FindFolder( MACFS.kOnSystemDisk, MACFS.kDocumentsFolderType, 0) path = sysutils.mainModuleDir
path = macfs.FSSpec((fsspec_disk, fsspec_desktop, '')).as_pathname() else:
path = os.getenv("AG_DOCUMENTS_DIR")
if path == "": if ((path is None) or (len(path) < 1)):
path = os.path.expanduser("~") if sysutils.isWindows():
ifDefPy()
return path try:
from win32com.shell import shell, shellcon
path = shell.SHGetFolderPath(0, shellcon.CSIDL_PERSONAL, None, 0)
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()
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")
documents_folder = _generateDocumentsDir() return path
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 # 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 # application object. This makes sure the wxApp will always be created when
# we get the folder. # we get the folder.
ifDefPy()
def getAppDataFolder(): def getAppDataFolder():
# wxStandardPaths requires a running app try:
if wx.GetApp() and wx.Platform != "__WXGTK__": # NOTE: cannot import wx from the server
data_folder = wx.StandardPaths.Get().GetUserDataDir() import wx
if not os.path.exists(data_folder): # wxStandardPaths requires a running app
os.mkdir(data_folder) if wx.GetApp() and wx.Platform != "__WXGTK__":
return data_folder data_folder = wx.StandardPaths.Get().GetUserDataDir()
else: if not os.path.exists(data_folder):
# wxBug: on *nix, it wants to point to ~/.appname, but os.mkdir(data_folder)
# so does wxConfig... For now, redirect this to ~/.appbuilder return data_folder
# when this is fixed, we'll migrate settings to the correct place except:
return os.path.join(os.path.expanduser("~"), ".appbuilder") 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.aglogging as aglogging
import activegrid.util.sysutils as sysutils import activegrid.util.sysutils as sysutils
import activegrid.util.utillang as utillang
from activegrid.util.lang import * from activegrid.util.lang import *
global fileutilsLogger global fileutilsLogger
@@ -31,6 +32,65 @@ fileutilsLogger = logging.getLogger("activegrid.util.fileutils")
aglogging.setLevelFatal(fileutilsLogger) aglogging.setLevelFatal(fileutilsLogger)
#logging.getLogger().addHandler(logging.StreamHandler(sys.stderr)) #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): def makeDirsForFile(filename):
d = os.path.dirname(filename) d = os.path.dirname(filename)
@@ -44,7 +104,7 @@ def createFile(filename, mode='w'):
f = file(filename, mode) f = file(filename, mode)
return f return f
def compareFiles(file1, file2): def compareFiles(file1, file2, ignore=None):
## result = filecmp.cmp(file1, file2) ## result = filecmp.cmp(file1, file2)
## if result: ## if result:
## return 0 ## return 0
@@ -62,6 +122,9 @@ def compareFiles(file1, file2):
elif (len(line2) == 0): elif (len(line2) == 0):
return -1 return -1
elif (line1 != line2): elif (line1 != line2):
if (ignore != None):
if (line1.startswith(ignore) or line2.startswith(ignore)):
continue
line1 = line1.replace(" ", "") line1 = line1.replace(" ", "")
line2 = line2.replace(" ", "") line2 = line2.replace(" ", "")
if (line1 != line2): if (line1 != line2):
@@ -81,7 +144,10 @@ def compareFiles(file1, file2):
continue continue
return -1 return -1
def expandVars(value): def expandKnownAGVars(value):
return expandVars(value, includeEnv=False)
def expandVars(value, includeEnv=True):
"""Syntax: ${myvar,default="default value"}""" """Syntax: ${myvar,default="default value"}"""
import activegrid.runtime as runtime import activegrid.runtime as runtime
sx = value.find("${") sx = value.find("${")
@@ -97,16 +163,19 @@ def expandVars(value):
defaultValue = value[defsx+10:endx-1] defaultValue = value[defsx+10:endx-1]
if (defaultValue == None): if (defaultValue == None):
varname = value[sx+2:endx] varname = value[sx+2:endx]
if (varname == "AG_SYSTEM"): if (varname == AG_SYSTEM_VAR):
varval = runtime.appInfo.getSystemDir() varval = runtime.appInfo.getSystemDir()
elif (varname == "AG_SYSTEM_STATIC"): elif (varname == AG_SYSTEM_STATIC_VAR):
varval = runtime.appInfo.getSystemStaticDir() varval = runtime.appInfo.getSystemStaticDir()
elif (varname == "AG_APP"): elif (varname == AG_APP_VAR):
varval = runtime.appInfo.getAppDir() varval = runtime.appInfo.getAppDir()
elif (varname == "AG_APP_STATIC"): elif (varname == AG_APP_STATIC_VAR):
varval = runtime.appInfo.getAppStaticDir() varval = runtime.appInfo.getAppStaticDir()
else: else:
varval = os.getenv(varname) if (includeEnv):
varval = os.getenv(varname)
else:
varval = None
if ((varval == None) and (defaultValue != None)): if ((varval == None) and (defaultValue != None)):
varval = defaultValue varval = defaultValue
if (varval == None): if (varval == None):
@@ -148,22 +217,21 @@ def convertSourcePath(path, to, otherdir=None):
return otherdir + path[ix+7:] return otherdir + path[ix+7:]
def visit(directory, files, extension): def visit(directory, files, extension, maxLevel=None, level=1):
testdirs = os.listdir(directory) testdirs = os.listdir(directory)
for thing in testdirs: for thing in testdirs:
fullpath = os.path.join(directory, thing) fullpath = os.path.join(directory, thing)
if (os.path.isdir(fullpath)): if (os.path.isdir(fullpath) and (maxLevel == None or level < maxLevel)):
visit(fullpath, files, extension) visit(fullpath, files, extension, maxLevel, level+1)
elif thing.endswith(extension): elif thing.endswith(extension):
fullname = os.path.normpath(os.path.join(directory, thing)) fullname = os.path.normpath(os.path.join(directory, thing))
if not fullname in files: if not fullname in files:
files.append(fullname) files.append(fullname)
def listFilesByExtensionInPath(path=[], extension='.lyt'): def listFilesByExtensionInPath(path=[], extension='.lyt', maxLevel=None):
#Collect input and output arguments into one bunch
retval = [] retval = []
for directory in path: for directory in path:
visit(directory, retval, extension) visit(directory, retval, extension, maxLevel)
return retval return retval
def getFileLastModificationTime(fileName): def getFileLastModificationTime(fileName):
@@ -311,6 +379,21 @@ def remove(file):
shutil.rmtree(file) shutil.rmtree(file)
endIfDef() 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() ifDefPy()
import warnings import warnings
warnings.filterwarnings("ignore", message="tmpnam is a potential security risk to your program") warnings.filterwarnings("ignore", message="tmpnam is a potential security risk to your program")

View File

@@ -16,7 +16,8 @@ import sys
import os import os
import __builtin__ import __builtin__
import types import types
import xml.sax.saxutils as saxutils import activegrid.util.utillang as utillang
import activegrid.util.datetimeparser as datetimeparser
from types import * from types import *
from activegrid.util.lang import * from activegrid.util.lang import *
@@ -65,6 +66,18 @@ def setStaticAttr(obj, attr, value):
classDesc = obj.__class__ classDesc = obj.__class__
setattr(classDesc, attr, value) 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): def moduleForName(moduleName):
module = None module = None
pathList = moduleName.split('.') 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])): if ((len(objargs) < 1) or (objargs[0].lower() == "false") or (not objargs[0])):
return False return False
return True 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: if len(objargs) > 0:
try: try:
return saxutils.unescape(objargs[0]).encode() return utillang.unescape(objargs[0]).encode()
except: except:
return "?" return "?"
else: else:
return "" 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) classtype = classForName(className)
if (classtype == None): if (classtype == None):
raise Exception("Could not find class %s" % className) raise Exception("Could not find class %s" % className)
@@ -135,23 +155,35 @@ def newInstance(className, objargs=None):
def getClassProperty(classType, propertyName): def getClassProperty(classType, propertyName):
return getattr(classType, propertyName) return getattr(classType, propertyName)
def toDiffableRepr(value, exclude=None): def toDiffableRepr(value, maxLevel=None):
if (value == None): if (value == None):
return "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__")): ## elif (isinstance(value, ObjectType) and hasattr(value, "__dict__")):
## if (exclude == None): ## if (exclude == None):
## exclude = [] ## exclude = []
## s = "%s(%s)" % (type(value), toDiffableString(value.__dict__, 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, FloatType, IntType, ListType, LongType, StringType, TupleType,
UnicodeType, BufferType, BuiltinFunctionType, BuiltinMethodType, UnicodeType, BufferType, BuiltinFunctionType, BuiltinMethodType,
CodeType, FrameType, FunctionType, GeneratorType, InstanceType, CodeType, FrameType, FunctionType, GeneratorType, InstanceType,
LambdaType, MethodType, ModuleType, SliceType, TracebackType, LambdaType, MethodType, ModuleType, SliceType, TracebackType,
TypeType, XRangeType))): TypeType, XRangeType))):
if (hasattr(value, "__str__")): if (hasattr(value, "_toDiffableString")):
s = value._toDiffableString(maxLevel)
elif (hasattr(value, "__str__")):
s = str(value) s = str(value)
elif (hasattr(value, "__dict__")): elif (hasattr(value, "__dict__")):
s = "%s(%s)" % (type(value), toDiffableString(value.__dict__, exclude)) s = "%s(%s)" % (type(value), toDiffableString(value.__dict__, maxLevel))
else: else:
s = str(type(value)) s = str(type(value))
ix2 = s.find(" object at 0x") ix2 = s.find(" object at 0x")
@@ -173,33 +205,31 @@ def toDiffableRepr(value, exclude=None):
else: else:
items.append("'%s'" % v) items.append("'%s'" % v)
else: else:
items.append(toDiffableString(v, exclude)) items.append(toDiffableString(v, maxLevel))
s = "[" + ", ".join(items) + "]" s = "[" + ", ".join(items) + "]"
elif (isinstance(value, dict)): elif (isinstance(value, dict)):
if (exclude == None):
exclude = []
items = [] items = []
for key, val in value.iteritems(): for key, val in value.iteritems():
if (isinstance(val, UnicodeType)): 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)): elif (isinstance(val, basestring)):
items.append("'%s': '%s'" % (key, toDiffableString(val, exclude))) items.append("'%s': '%s'" % (key, toDiffableString(val, maxLevel)))
else: else:
items.append("'%s': %s" % (key, toDiffableString(val, exclude))) items.append("'%s': %s" % (key, toDiffableString(val, maxLevel)))
s = "{" + ", ".join(items) + "}" s = "{" + ", ".join(items) + "}"
else: else:
s = str(value) s = str(value)
return s return s
def toDiffableString(value, exclude=None): def toDiffableString(value, maxLevel=None):
if (value == None): ## if (value == None):
return "None" ## return "None"
if ((exclude != None) and not isinstance(value, (basestring, int))): ## if ((exclude != None) and not isinstance(value, (basestring, int))):
for v in exclude: ## for v in exclude:
if (v is value): ## if (v is value):
return "<recursive reference>" ## return "<recursive reference>"
exclude.append(value) ## exclude.append(value)
s = toDiffableRepr(value) s = toDiffableRepr(value, maxLevel)
ds = "" ds = ""
i = s.find(" at 0x") i = s.find(" at 0x")
start = 0 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 return -1
else: else:
return 1 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 sys
import os import os
import time
# this will be set to true in IDE.py when we are running release builds. # this will be set to true in IDE.py when we are running release builds.
isRelease = False isRelease = False
@@ -26,6 +27,12 @@ isRelease = False
MAINMODULE_DIR = "AG_MAINMODULE_DIR" MAINMODULE_DIR = "AG_MAINMODULE_DIR"
IS_RELEASE = "AG_IS_RELEASE" 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(): def isRelease():
return 'true' == (str(os.getenv(IS_RELEASE)).lower()) return 'true' == (str(os.getenv(IS_RELEASE)).lower())
@@ -39,7 +46,16 @@ def setRelease(value):
def isWindows(): def isWindows():
return os.name == 'nt' return os.name == 'nt'
__isServer = False
def setServerMode(isServer):
global __isServer
__isServer = isServer
def isServer():
global __isServer
return __isServer
def _generateMainModuleDir(): def _generateMainModuleDir():
mainModuleDir = os.getenv(MAINMODULE_DIR) mainModuleDir = os.getenv(MAINMODULE_DIR)
if mainModuleDir: # if environment variable set, return it if mainModuleDir: # if environment variable set, return it
@@ -85,3 +101,16 @@ def getCommandNameForExecPath(execPath):
return '"%s"' % execPath return '"%s"' % execPath
return 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 # Name: xmlmarshaller.py
# Purpose: # Purpose:
# #
# Authors: John Spurling, Joel Hare, Alan Mullendore # Authors: John Spurling, Joel Hare, Jeff Norton, Alan Mullendore
# #
# Created: 7/28/04 # Created: 7/28/04
# CVS-ID: $Id$ # CVS-ID: $Id$
@@ -16,14 +16,18 @@ import logging
ifDefPy() ifDefPy()
import xml.sax import xml.sax
import xml.sax.handler import xml.sax.handler
import xml.sax.saxutils
import datetime
endIfDef() endIfDef()
import xml.sax.saxutils as saxutils import activegrid.util.utillang as utillang
import activegrid.util.objutils as objutils import activegrid.util.objutils as objutils
import activegrid.util.sysutils as sysutils
import activegrid.util.aglogging as aglogging import activegrid.util.aglogging as aglogging
MODULE_PATH = "__main__" MODULE_PATH = "__main__"
## ToDO remove maxOccurs "unbounded" resolves to -1 hacks after bug 177 is fixed ## 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: Special attributes that we recognize:
@@ -109,7 +113,6 @@ __xmlcdatacontent__ = "messyContent"
global xmlMarshallerLogger global xmlMarshallerLogger
xmlMarshallerLogger = logging.getLogger("activegrid.util.xmlmarshaller.marshal") xmlMarshallerLogger = logging.getLogger("activegrid.util.xmlmarshaller.marshal")
xmlMarshallerLogger.setLevel(aglogging.LEVEL_WARN)
# INFO : low-level info # INFO : low-level info
# DEBUG : debugging info # DEBUG : debugging info
@@ -184,6 +187,7 @@ DICT_ITEM_VALUE_NAME = "value"
################################################################################ ################################################################################
def setattrignorecase(object, name, value): def setattrignorecase(object, name, value):
## print "[setattrignorecase] name = %s, value = %s" % (name, value)
if (name not in object.__dict__): if (name not in object.__dict__):
namelow = name.lower() namelow = name.lower()
for attr in object.__dict__: for attr in object.__dict__:
@@ -193,27 +197,95 @@ def setattrignorecase(object, name, value):
object.__dict__[name] = value object.__dict__[name] = value
def getComplexType(obj): def getComplexType(obj):
if (hasattr(obj, "_instancexsdcomplextype")):
return obj._instancexsdcomplextype
if (hasattr(obj, "__xsdcomplextype__")): if (hasattr(obj, "__xsdcomplextype__")):
return obj.__xsdcomplextype__ return obj.__xsdcomplextype__
return None return None
def _objectfactory(objname, objargs=None, objclass=None): def _objectfactory(objtype, objargs=None, objclass=None):
"dynamically create an object based on the objname and return it." "dynamically create an object based on the objtype and return it."
## print "[objectfactory] objname [%s]" % (objname)
if not isinstance(objargs, list): if not isinstance(objargs, list):
objargs = [objargs] objargs = [objargs]
if (objclass != None): if (objclass != None):
obj = None
if (len(objargs) > 0): if (len(objargs) > 0):
if (hasattr(objclass, "__xmlcdatacontent__")): if (hasattr(objclass, "__xmlcdatacontent__")):
obj = objclass() obj = objclass()
contentAttr = obj.__xmlcdatacontent__ contentAttr = obj.__xmlcdatacontent__
obj.__dict__[contentAttr] = str(objargs[0]) obj.__dict__[contentAttr] = str(objargs[0])
return obj else:
return objclass(*objargs) obj = objclass(*objargs)
else: else:
return objclass() obj = objclass()
return objutils.newInstance(objname, objargs) 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: class Element:
def __init__(self, name, attrs=None, xsname=None): def __init__(self, name, attrs=None, xsname=None):
self.name = name self.name = name
@@ -222,9 +294,11 @@ class Element:
self.children = [] self.children = []
self.objclass = None self.objclass = None
self.xsname = xsname self.xsname = xsname
self.objtype = None
def getobjtype(self): def getobjtype(self):
objtype = self.attrs.get("objtype") # objtype = self.attrs.get("objtype")
objtype = self.objtype
if (objtype == None): if (objtype == None):
if (len(self.children) > 0): if (len(self.children) > 0):
objtype = "dict" objtype = "dict"
@@ -238,16 +312,35 @@ class NsElement(object):
self.targetNS = None self.targetNS = None
self.defaultNS = None self.defaultNS = None
self.prefix = 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): def setKnownTypes(self, masterKnownTypes, masterKnownNamespaces, parentNSE):
# if we're a nested element, extend our parent element's mapping # if we're a nested element, extend our parent element's mapping
if parentNSE != None: if parentNSE != None:
self.knownTypes = parentNSE.knownTypes.copy() self.knownTypes = parentNSE.knownTypes.copy()
# but if we have a different default namespace, replace the parent's default mappings # 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() newKT = self.knownTypes.copy()
for tag in newKT: for tag in newKT:
if tag.find(':') < 0: if tag.find(':') < 0:
@@ -283,7 +376,6 @@ class NsElement(object):
self.knownTypes[knownTagName] = mapClass self.knownTypes[knownTagName] = mapClass
else: # e.g. "ItemSearchRequest" else: # e.g. "ItemSearchRequest"
self.knownTypes[tag] = mapClass self.knownTypes[tag] = mapClass
## print 'mapping <%s> to class "%s"' % (tag, mapClass.__name__)
def expandQName(self, eName, attrName, attrValue): def expandQName(self, eName, attrName, attrValue):
bigValue = attrValue bigValue = attrValue
@@ -298,38 +390,57 @@ class NsElement(object):
if shortNs == attrNS: if shortNs == attrNS:
bigValue = '%s:%s' % (longNs, attrNCName) bigValue = '%s:%s' % (longNs, attrNCName)
break break
## print '[expandQName] input attrName = "%s" and attrValue "%s"; output = "%s"' % (attrName, attrValue, bigValue)
return bigValue return bigValue
class XMLObjectFactory(xml.sax.ContentHandler): 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 self.rootelement = None
if (knownTypes == None): if xmlSource == None:
self.knownTypes = {} self.xmlSource = "unknown"
else: else:
self.knownTypes = knownTypes self.xmlSource = xmlSource
if (knownNamespaces == None): self.createGenerics = createGenerics
self.knownNamespaces = {}
else:
self.knownNamespaces = knownNamespaces
self.skipper = False self.skipper = False
self.elementstack = [] self.elementstack = []
self.nsstack = [] self.nsstack = []
self.collectContent = None 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) xml.sax.handler.ContentHandler.__init__(self)
def appendElementStack(self, newElement, newNS): def appendElementStack(self, newElement, newNS):
self.elementstack.append(newElement) self.elementstack.append(newElement)
if (newNS.isEmpty()): if (len(self.nsstack) > 0):
if (len(self.nsstack) > 0): oldNS = self.nsstack[-1]
newNS = self.nsstack[-1] if newNS.defaultNS == None:
else: newNS.defaultNS = oldNS.defaultNS
newNS.knownTypes = self.knownTypes.copy() if newNS.targetNS == None:
else: newNS.targetNS = oldNS.targetNS
if (len(self.nsstack) > 0): if len(newNS.nsMap) == 0:
newNS.setKnownTypes(self.knownTypes, self.knownNamespaces, self.nsstack[-1]) newNS.nsMap = oldNS.nsMap
else: elif len(oldNS.nsMap) > 0:
newNS.setKnownTypes(self.knownTypes, self.knownNamespaces, None) map = oldNS.nsMap.copy()
map.update(newNS.nsMap)
newNS.nsMap = map
self.nsstack.append(newNS) self.nsstack.append(newNS)
return newNS return newNS
@@ -353,11 +464,16 @@ class XMLObjectFactory(xml.sax.ContentHandler):
strVal += '>' strVal += '>'
self.collectContent.content += strVal self.collectContent.content += strVal
xsname = name xsname = name
if name.find(':') > -1: # Strip namespace prefixes for now until actually looking them up in xsd i = name.rfind(':')
name = name[name.rfind(":") + 1:] if i >= 0:
nsname = name[:i]
name = name[i+1:]
else:
nsname = None
element = Element(name, attrs.copy(), xsname=xsname) element = Element(name, attrs.copy(), xsname=xsname)
# if the element has namespace attributes, process them and add them to our stack # if the element has namespace attributes, process them and add them to our stack
nse = NsElement() nse = NsElement()
objtype = None
for k in attrs.getNames(): for k in attrs.getNames():
if k.startswith('xmlns'): if k.startswith('xmlns'):
longNs = attrs[k] longNs = attrs[k]
@@ -371,8 +487,28 @@ class XMLObjectFactory(xml.sax.ContentHandler):
nse.nsMap[shortNs] = longNs nse.nsMap[shortNs] = longNs
elif k == 'targetNamespace': elif k == 'targetNamespace':
nse.targetNS = attrs.getValue(k) nse.targetNS = attrs.getValue(k)
elif k == 'objtype':
objtype = attrs.getValue(k)
nse = self.appendElementStack(element, nse) 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__")): if (hasattr(element.objclass, "__xmlcontent__")):
self.collectContent = element self.collectContent = element
@@ -387,8 +523,9 @@ class XMLObjectFactory(xml.sax.ContentHandler):
def endElement(self, name): def endElement(self, name):
## print "[endElement] </%s>" % name ## print "[endElement] </%s>" % name
xsname = name xsname = name
if name.find(":") > -1: # Strip namespace prefixes for now until actually looking them up in xsd i = name.rfind(':')
name = name[name.find(":") + 1:] if i >= 0: # Strip namespace prefixes for now until actually looking them up in xsd
name = name[i+1:]
if self.skipper: if self.skipper:
if xsname == "xs:annotation" or xsname == "xsd:annotation": # here too if xsname == "xs:annotation" or xsname == "xsd:annotation": # here too
self.skipper = False self.skipper = False
@@ -405,34 +542,36 @@ class XMLObjectFactory(xml.sax.ContentHandler):
element, nse = self.popElementStack() element, nse = self.popElementStack()
if ((len(self.elementstack) > 1) and (self.elementstack[-1].getobjtype() == "None")): if ((len(self.elementstack) > 1) and (self.elementstack[-1].getobjtype() == "None")):
parentElement = self.elementstack[-2] parentElement = self.elementstack[-2]
## print "[endElement] %s: found parent with objtype==None: using its grandparent" % name
elif (len(self.elementstack) > 0): elif (len(self.elementstack) > 0):
parentElement = self.elementstack[-1] parentElement = self.elementstack[-1]
objtype = element.getobjtype() objtype = element.getobjtype()
## print "element objtype is: ", objtype
if (objtype == "None"): if (objtype == "None"):
## print "[endElement] %s: skipping a (objtype==None) end tag" % name
return return
constructorarglist = [] constructorarglist = []
if (len(element.content) > 0): if (len(element.content) > 0):
strippedElementContent = element.content.strip() strippedElementContent = element.content.strip()
if (len(strippedElementContent) > 0): if (len(strippedElementContent) > 0):
constructorarglist.append(element.content) 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) 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) complexType = getComplexType(obj)
if (obj != None): if (obj != None):
if (hasattr(obj, "__xmlname__") and getattr(obj, "__xmlname__") == "sequence"): if (hasattr(obj, "__xmlname__") and getattr(obj, "__xmlname__") == "sequence"):
self.elementstack[-1].children = oldChildren self.elementstack[-1].children = oldChildren
return return
if (len(element.attrs) > 0) and not isinstance(obj, list): 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(): for attrname, attr in element.attrs.items():
if attrname == XMLNS or attrname.startswith(XMLNS_PREFIX): if attrname == XMLNS or attrname.startswith(XMLNS_PREFIX):
if attrname.startswith(XMLNS_PREFIX): if attrname.startswith(XMLNS_PREFIX):
ns = attrname[XMLNS_PREFIX_LENGTH:] ns = attrname[XMLNS_PREFIX_LENGTH:]
else: else:
ns = "" ns = ""
if complexType != None: if complexType != None or element.objclass == GenericXMLObject:
if not hasattr(obj, "__xmlnamespaces__"): if not hasattr(obj, "__xmlnamespaces__"):
obj.__xmlnamespaces__ = {ns:attr} obj.__xmlnamespaces__ = {ns:attr}
elif ns not in obj.__xmlnamespaces__: elif ns not in obj.__xmlnamespaces__:
@@ -447,7 +586,6 @@ class XMLObjectFactory(xml.sax.ContentHandler):
xsdElement = complexType.findElement(attrname) xsdElement = complexType.findElement(attrname)
if (xsdElement != None): if (xsdElement != None):
type = xsdElement.type type = xsdElement.type
## print 'Unmarshalling element "%s", attribute "%s" with type "%s"' % (name, xsdElement.name, type)
if (type != None): if (type != None):
if (type == TYPE_QNAME): if (type == TYPE_QNAME):
attr = nse.expandQName(name, attrname, attr) attr = nse.expandQName(name, attrname, attr)
@@ -455,11 +593,15 @@ class XMLObjectFactory(xml.sax.ContentHandler):
### ToDO remove maxOccurs hack after bug 177 is fixed ### ToDO remove maxOccurs hack after bug 177 is fixed
if attrname == "maxOccurs" and attr == "unbounded": if attrname == "maxOccurs" and attr == "unbounded":
attr = "-1" attr = "-1"
attr = _objectfactory(type, attr) 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: try:
setattrignorecase(obj, _toAttrName(obj, attrname), attr) setattrignorecase(obj, _toAttrName(obj, attrname), attr)
except AttributeError: 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) raise UnmarshallerException(errorString)
## obj.__dict__[_toAttrName(obj, attrname)] = attr ## obj.__dict__[_toAttrName(obj, attrname)] = attr
# stuff any child attributes meant to be in a sequence via the __xmlflattensequence__ # 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 flattenDict[str(xmlnametuple)] = sequencename
else: else:
for xmlname in xmlnametuple: for xmlname in xmlnametuple:
## print "[endElement]: adding flattenDict[%s] = %s" % (xmlname, sequencename)
flattenDict[xmlname] = sequencename flattenDict[xmlname] = sequencename
else: else:
raise Exception("Invalid type for __xmlflattensequence___ : it must be a dict") raise Exception("Invalid type for __xmlflattensequence___ : it must be a dict")
# reattach an object"s attributes to it # reattach an object"s attributes to it
for childname, child in element.children: for childname, child in element.children:
## print "[endElement] childname is: ", childname, "; child is: ", child
if (childname in flattenDict): if (childname in flattenDict):
sequencename = _toAttrName(obj, flattenDict[childname]) sequencename = _toAttrName(obj, flattenDict[childname])
if (not hasattr(obj, sequencename)): if (not hasattr(obj, sequencename)):
@@ -499,12 +639,13 @@ class XMLObjectFactory(xml.sax.ContentHandler):
else: else:
obj[childname] = child obj[childname] = child
else: else:
## print "childname = %s, obj = %s, child = %s" % (childname, repr(obj), repr(child)) # don't replace a good attribute value with a bad one
try: childAttrName = _toAttrName(obj, childname)
setattrignorecase(obj, _toAttrName(obj, childname), child) if (not hasattr(obj, childAttrName)) or (getattr(obj, childAttrName) == None) or (getattr(obj, childAttrName) == []) or (not isinstance(child, GenericXMLObject)):
except AttributeError: try:
raise MarshallerException("Error unmarshalling child element \"%s\" of XML element \"%s\": object type not specified or known" % (childname, name)) setattrignorecase(obj, childAttrName, child)
## obj.__dict__[_toAttrName(obj, childname)] = child except AttributeError:
raise MarshallerException("Error unmarshalling child element \"%s\" of XML element \"%s\": object type not specified or known" % (childname, name))
if (complexType != None): if (complexType != None):
for element in complexType.elements: for element in complexType.elements:
@@ -524,7 +665,6 @@ class XMLObjectFactory(xml.sax.ContentHandler):
if (len(self.elementstack) > 0): if (len(self.elementstack) > 0):
## print "[endElement] appending child with name: ", name, "; objtype: ", objtype ## print "[endElement] appending child with name: ", name, "; objtype: ", objtype
parentElement.children.append((name, obj)) parentElement.children.append((name, obj))
## print "parentElement now has ", len(parentElement.children), " children"
else: else:
self.rootelement = obj self.rootelement = obj
@@ -539,7 +679,12 @@ def _toAttrName(obj, name):
break break
## if (name.startswith("__") and not name.endswith("__")): ## if (name.startswith("__") and not name.endswith("__")):
## name = "_%s%s" % (obj.__class__.__name__, name) ## 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 = { __typeMappingXsdToLang = {
"string": "str", "string": "str",
@@ -569,7 +714,7 @@ def xsdToLangType(xsdType):
if xsdType.startswith(XMLSCHEMA_XSD_URL): if xsdType.startswith(XMLSCHEMA_XSD_URL):
xsdType = xsdType[len(XMLSCHEMA_XSD_URL)+1:] xsdType = xsdType[len(XMLSCHEMA_XSD_URL)+1:]
elif xsdType.startswith(AG_URL): elif xsdType.startswith(AG_URL):
xsdType = xsdType[len(AG_URL)+1:] xsdType = xsdType[len(AG_URL)+1:]
langType = __typeMappingXsdToLang.get(xsdType) langType = __typeMappingXsdToLang.get(xsdType)
if (langType == None): if (langType == None):
raise Exception("Unknown xsd type %s" % xsdType) raise Exception("Unknown xsd type %s" % xsdType)
@@ -588,8 +733,11 @@ def _getXmlValue(langValue):
else: else:
return str(langValue) return str(langValue)
def unmarshal(xmlstr, knownTypes=None, knownNamespaces=None, xmlSource=None): def unmarshal(xmlstr, knownTypes=None, knownNamespaces=None, xmlSource=None, createGenerics=False):
objectfactory = XMLObjectFactory(knownTypes, knownNamespaces) objectfactory = XMLObjectFactory(knownTypes, knownNamespaces, xmlSource, createGenerics)
# on Linux, pyXML's sax.parseString fails when passed unicode
if (not sysutils.isWindows()):
xmlstr = str(xmlstr)
try: try:
xml.sax.parseString(xmlstr, objectfactory) xml.sax.parseString(xmlstr, objectfactory)
except xml.sax.SAXParseException, errorData: except xml.sax.SAXParseException, errorData:
@@ -600,17 +748,19 @@ def unmarshal(xmlstr, knownTypes=None, knownNamespaces=None, xmlSource=None):
return objectfactory.getRootObject() return objectfactory.getRootObject()
def marshal(obj, elementName=None, prettyPrint=False, marshalType=True, indent=0, knownTypes=None, knownNamespaces=None, encoding=-1): 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) worker = XMLMarshalWorker(prettyPrint=prettyPrint, marshalType=marshalType, knownTypes=knownTypes, knownNamespaces=knownNamespaces)
if obj != None and hasattr(obj, '__xmldeepexclude__'): if obj != None and hasattr(obj, '__xmldeepexclude__'):
worker.xmldeepexclude = obj.__xmldeepexclude__ worker.xmldeepexclude = obj.__xmldeepexclude__
xmlstr = "".join(worker._marshal(obj, elementName, indent=indent)) xmlstr = "".join(worker._marshal(obj, elementName, indent=indent))
if (isinstance(encoding, basestring)): aglogging.info(xmlMarshallerLogger, "marshal produced string of type %s", type(xmlstr))
return '<?xml version="1.0" encoding="%s"?>\n%s' % (encoding, xmlstr.encode(encoding)) if (encoding == None):
elif (encoding == None):
return xmlstr return xmlstr
else: if (not isinstance(encoding, basestring)):
return '<?xml version="1.0" encoding="%s"?>\n%s' % (sys.getdefaultencoding(), xmlstr) 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): class XMLMarshalWorker(object):
def __init__(self, marshalType=True, prettyPrint=False, knownTypes=None, knownNamespaces=None): def __init__(self, marshalType=True, prettyPrint=False, knownTypes=None, knownNamespaces=None):
@@ -695,7 +845,7 @@ class XMLMarshalWorker(object):
newNS.prefix = self.nsstack[-1].prefix newNS.prefix = self.nsstack[-1].prefix
else: else:
newNS.prefix = '' newNS.prefix = ''
if hasattr(obj, "__xmldefaultnamespace__"): if obj != None and hasattr(obj, "__xmldefaultnamespace__"):
longPrefixNS = getattr(obj, "__xmldefaultnamespace__") longPrefixNS = getattr(obj, "__xmldefaultnamespace__")
if longPrefixNS == defaultLongNS: if longPrefixNS == defaultLongNS:
newNS.prefix = '' newNS.prefix = ''
@@ -705,13 +855,12 @@ class XMLMarshalWorker(object):
if v == longPrefixNS: if v == longPrefixNS:
newNS.prefix = k + ':' newNS.prefix = k + ':'
break; break;
## print '[appendNSStack] found longPrefixNS in nameSpaces = "%s"' % (newNS.prefix)
except: except:
if (longPrefixNS in asDict(self.knownNamespaces)): if (longPrefixNS in asDict(self.knownNamespaces)):
newNS.prefix = self.knownNamespaces[longPrefixNS] + ':' newNS.prefix = self.knownNamespaces[longPrefixNS] + ':'
else: else:
raise MarshallerException('Error marshalling __xmldefaultnamespace__ ("%s") not defined in namespace stack' % (longPrefixNS)) 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 newNS.targetNS = obj.targetNamespace
elif len(self.nsstack) > 0: elif len(self.nsstack) > 0:
newNS.targetNS = self.nsstack[-1].targetNS newNS.targetNS = self.nsstack[-1].targetNS
@@ -749,9 +898,11 @@ class XMLMarshalWorker(object):
def _marshal(self, obj, elementName=None, nameSpacePrefix="", indent=0): def _marshal(self, obj, elementName=None, nameSpacePrefix="", indent=0):
if (obj != None): 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: 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 = []
excludeAttrs.extend(self.xmldeepexclude) excludeAttrs.extend(self.xmldeepexclude)
if hasattr(obj, "__xmlexclude__"): if hasattr(obj, "__xmlexclude__"):
@@ -768,8 +919,8 @@ class XMLMarshalWorker(object):
newline = "" newline = ""
increment = 0 increment = 0
## Determine the XML element name. If it isn"t specified in the ## Determine the XML element name. If it isn"t specified in the
## parameter list, look for it in the __xmlname__ Lang ## parameter list, look for it in the __xmlname__ attribute,
## attribute, else use the default generic BASETYPE_ELEMENT_NAME. ## else use the default generic BASETYPE_ELEMENT_NAME.
nameSpaceAttrs = self.appendNSStack(obj) nameSpaceAttrs = self.appendNSStack(obj)
nameSpacePrefix = self.getNSPrefix() nameSpacePrefix = self.getNSPrefix()
if not elementName: if not elementName:
@@ -779,13 +930,15 @@ class XMLMarshalWorker(object):
elementName = nameSpacePrefix + BASETYPE_ELEMENT_NAME elementName = nameSpacePrefix + BASETYPE_ELEMENT_NAME
else: else:
elementName = nameSpacePrefix + elementName elementName = nameSpacePrefix + elementName
## print '[XMLMarshalWorker._marshal] elementName "%s"; nameSpaceAttrs is "%s"' % (elementName, nameSpaceAttrs)
if (hasattr(obj, "__xmlsequencer__")) and (obj.__xmlsequencer__ != None): if (hasattr(obj, "__xmlsequencer__")) and (obj.__xmlsequencer__ != None):
if (XMLSCHEMA_XSD_URL in self.nsstack[-1].nameSpaces.values()): if (XMLSCHEMA_XSD_URL in self.nsstack[-1].nameSpaces.values()):
for kShort, vLong in self.nsstack[-1].nameSpaces.iteritems(): for kShort, vLong in self.nsstack[-1].nameSpaces.iteritems():
if vLong == XMLSCHEMA_XSD_URL: if vLong == XMLSCHEMA_XSD_URL:
xsdPrefix = kShort + ':' if kShort != DEFAULT_NAMESPACE_KEY:
xsdPrefix = kShort + ':'
else:
xsdPrefix = ''
break break
else: else:
xsdPrefix = 'xs:' xsdPrefix = 'xs:'
@@ -793,7 +946,6 @@ class XMLMarshalWorker(object):
else: else:
elementAdd = None elementAdd = None
## print "marshal: entered with elementName: ", elementName
members_to_skip = [] members_to_skip = []
## Add more members_to_skip based on ones the user has selected ## Add more members_to_skip based on ones the user has selected
## via the __xmlexclude__ and __xmldeepexclude__ attributes. ## via the __xmlexclude__ and __xmldeepexclude__ attributes.
@@ -806,7 +958,6 @@ class XMLMarshalWorker(object):
xmlattributes = obj.__xmlattributes__ xmlattributes = obj.__xmlattributes__
members_to_skip.extend(xmlattributes) members_to_skip.extend(xmlattributes)
for attr in xmlattributes: for attr in xmlattributes:
## print 'Processing element "%s"; attribute "%s"' % (elementName, attr)
internalAttrName = attr internalAttrName = attr
ifDefPy() ifDefPy()
if (attr.startswith("__") and not attr.endswith("__")): if (attr.startswith("__") and not attr.endswith("__")):
@@ -814,7 +965,6 @@ class XMLMarshalWorker(object):
endIfDef() endIfDef()
# Fail silently if a python attribute is specified to be # Fail silently if a python attribute is specified to be
# an XML attribute but is missing. # an XML attribute but is missing.
## print "marshal: processing attribute ", internalAttrName
attrNameSpacePrefix = "" attrNameSpacePrefix = ""
if hasattr(obj, "__xmlattrnamespaces__"): if hasattr(obj, "__xmlattrnamespaces__"):
for nameSpaceKey, nameSpaceAttributes in getattr(obj, "__xmlattrnamespaces__").iteritems(): for nameSpaceKey, nameSpaceAttributes in getattr(obj, "__xmlattrnamespaces__").iteritems():
@@ -856,8 +1006,7 @@ class XMLMarshalWorker(object):
else: else:
value = objutils.toDiffableRepr(value) value = objutils.toDiffableRepr(value)
objattrs += ' %s%s="%s"' % (attrNameSpacePrefix, attr, saxutils.escape(value)) objattrs += ' %s%s="%s"' % (attrNameSpacePrefix, attr, utillang.escape(value))
## print "marshal: new objattrs is: ", objattrs
if (obj == None): if (obj == None):
xmlString = [""] xmlString = [""]
elif isinstance(obj, bool): elif isinstance(obj, bool):
@@ -873,9 +1022,18 @@ class XMLMarshalWorker(object):
objTypeStr = self._genObjTypeStr("float") objTypeStr = self._genObjTypeStr("float")
xmlString = ['%s<%s%s>%s</%s>%s' % (prefix, elementName, objTypeStr, str(obj), elementName, newline)] 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 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): 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): elif isinstance(obj, list):
if len(obj) < 1: if len(obj) < 1:
xmlString = "" xmlString = ""
@@ -910,13 +1068,15 @@ class XMLMarshalWorker(object):
elif hasattr(obj, "__xmlcontent__"): elif hasattr(obj, "__xmlcontent__"):
contentValue = getattr(obj, obj.__xmlcontent__) contentValue = getattr(obj, obj.__xmlcontent__)
if contentValue == None: if contentValue == None:
contentValue = '' xmlString = ["%s<%s%s%s/>%s" % (prefix, elementName, nameSpaceAttrs, objattrs, newline)]
else: else:
contentValue = saxutils.escape(contentValue) contentValue = utillang.escape(contentValue)
xmlString = ["%s<%s%s%s>%s</%s>%s" % (prefix, elementName, nameSpaceAttrs, objattrs, contentValue, elementName, newline)] xmlString = ["%s<%s%s%s>%s</%s>%s" % (prefix, elementName, nameSpaceAttrs, objattrs, contentValue, elementName, newline)]
else: else:
# Only add the objtype if the element tag is unknown to us. # 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 = "" objTypeStr = ""
else: else:
objTypeStr = self._genObjTypeStr("%s.%s" % (obj.__class__.__module__, className)) objTypeStr = self._genObjTypeStr("%s.%s" % (obj.__class__.__module__, className))
@@ -929,7 +1089,7 @@ class XMLMarshalWorker(object):
if hasattr(obj, "__xmlbody__"): if hasattr(obj, "__xmlbody__"):
xmlbody = getattr(obj, obj.__xmlbody__) xmlbody = getattr(obj, obj.__xmlbody__)
if xmlbody != None: if xmlbody != None:
xmlMemberString.append(xmlbody) xmlMemberString.append(utillang.escape(xmlbody))
else: else:
if hasattr(obj, "__xmlattrgroups__"): if hasattr(obj, "__xmlattrgroups__"):
attrGroups = obj.__xmlattrgroups__.copy() attrGroups = obj.__xmlattrgroups__.copy()
@@ -975,21 +1135,17 @@ class XMLMarshalWorker(object):
xmlname = None xmlname = None
if (len(xmlnametuple) == 1): if (len(xmlnametuple) == 1):
xmlname = xmlnametuple[0] xmlname = xmlnametuple[0]
## ix = 0
if not isinstance(value, (list, tuple)): if not isinstance(value, (list, tuple)):
value = [value] value = [value]
for seqitem in 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)) xmlMemberString.extend(self._marshal(seqitem, xmlname, subElementNameSpacePrefix, indent=indent+increment))
else: else:
if (hasattr(obj, "__xmlrename__") and name in asDict(obj.__xmlrename__)): if (hasattr(obj, "__xmlrename__") and name in asDict(obj.__xmlrename__)):
xmlname = obj.__xmlrename__[name] xmlname = obj.__xmlrename__[name]
else: else:
xmlname = name xmlname = name
xmlMemberString.extend(self._marshal(value, xmlname, subElementNameSpacePrefix, indent=indent+increment)) if (value != None):
xmlMemberString.extend(self._marshal(value, xmlname, subElementNameSpacePrefix, indent=indent+increment))
if (eName != "__nogroup__"): if (eName != "__nogroup__"):
xmlMemberString.append("%s</%s>%s" % (prefix, eName, newline)) xmlMemberString.append("%s</%s>%s" % (prefix, eName, newline))
prefix = prefix[:-increment] prefix = prefix[:-increment]
@@ -1022,8 +1178,8 @@ class XMLMarshalWorker(object):
xmlString.append("><![CDATA[%s]]></%s>%s" % (cdataContent, elementName, newline)) xmlString.append("><![CDATA[%s]]></%s>%s" % (cdataContent, elementName, newline))
else: else:
xmlString.append("/>%s" % newline) xmlString.append("/>%s" % newline)
## return xmlString if aglogging.isEnabledForDebug(xmlMarshallerLogger):
xmlMarshallerLogger.debug("<-- _marshal: %s" % str(xmlString)) aglogging.debug(xmlMarshallerLogger, "<-- _marshal: %s", objutils.toDiffableString(xmlString))
#print "<-- _marshal: %s" % str(xmlString) #print "<-- _marshal: %s" % str(xmlString)
self.popNSStack() self.popNSStack()
return xmlString return xmlString

View File

@@ -22,35 +22,44 @@ import activegrid.util.aglogging as aglogging
xmlLogger = logging.getLogger("activegrid.util.xml") xmlLogger = logging.getLogger("activegrid.util.xml")
def load(fileName, knownTypes=None, knownNamespaces=None): def load(fileName, knownTypes=None, knownNamespaces=None, createGenerics=False):
loadedObject = None loadedObject = None
fileObject = file(fileName) fileObject = file(fileName)
timeStart = time.time() timeStart = time.time()
xml = ""
try: try:
xml = fileObject.read() 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) loadedObject.fileName = os.path.abspath(fileName)
if hasattr(loadedObject, 'initialize'): if hasattr(loadedObject, 'initialize'):
loadedObject.initialize() loadedObject.initialize()
finally: finally:
fileObject.close() fileObject.close()
timeDone = time.time() if xmlLogger.isEnabledFor(aglogging.LEVEL_INFO):
aglogging.info(xmlLogger, ('Load statistics for file %s: elapsed time = %f secs' % (fileName, timeDone-timeStart))) timeDone = time.time()
aglogging.info(xmlLogger, ('Load statistics for file %s (%d bytes): elapsed time = %f secs' % (fileName, len(xml), timeDone-timeStart)))
return loadedObject return loadedObject
def loadURI(uri, knownTypes=None, knownNamespaces=None, xmlSource=None): def loadURI(uri, knownTypes=None, knownNamespaces=None, xmlSource=None, createGenerics=False):
loadedObject = None loadedObject = None
xml = urllib.urlopen(uri).read() timeStart = time.time()
loadedObject = unmarshal(xml, knownTypes=knownTypes, knownNamespaces=knownNamespaces, xmlSource=xmlSource) xml = ""
loadedObject.fileName = uri try:
if hasattr(loadedObject, 'initialize'): xml = urllib.urlopen(uri).read()
loadedObject.initialize() 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 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): if (knownTypes == None):
knownTypes, knownNamespaces = getAgKnownTypes() 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'): def save(fileName, objectToSave, prettyPrint=True, marshalType=True, knownTypes=None, knownNamespaces=None, encoding='utf-8'):
if hasattr(objectToSave, '_xmlReadOnly') and objectToSave._xmlReadOnly == True: if hasattr(objectToSave, '_xmlReadOnly') and objectToSave._xmlReadOnly == True:
@@ -155,41 +164,6 @@ def getAgVersion(fileName):
version = xml[i+1:j] version = xml[i+1:j]
return version 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" AG_NS_URL = "http://www.activegrid.com/ag.xsd"
BPEL_NS_URL = "http://schemas.xmlsoap.org/ws/2003/03/business-process" 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/" MIME_WSDL_NS_URL = "http://schemas.xmlsoap.org/wsdl/mime/"
SOAP_NS_URL = "http://schemas.xmlsoap.org/wsdl/soap/" SOAP_NS_URL = "http://schemas.xmlsoap.org/wsdl/soap/"
SOAP12_NS_URL = "http://schemas.xmlsoap.org/wsdl/soap12/" 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/" 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" XFORMS_NS_URL = "http://www.w3c.org/xform.xsd"
XMLSCHEMA_NS_URL = "http://www.w3.org/2001/XMLSchema" XMLSCHEMA_NS_URL = "http://www.w3.org/2001/XMLSchema"
XSI_NS_URL = "http://www.w3.org/2001/XMLSchema-instance" XSI_NS_URL = "http://www.w3.org/2001/XMLSchema-instance"
@@ -209,7 +185,8 @@ KNOWN_NAMESPACES = { AG_NS_URL : "ag",
MIME_WSDL_NS_URL : "mime", MIME_WSDL_NS_URL : "mime",
SOAP_NS_URL : "soap", SOAP_NS_URL : "soap",
SOAP12_NS_URL : "soap12", SOAP12_NS_URL : "soap12",
WSDL_NS_URL : "wsdl", WSDL_NS_URL : "wsdl",
WSSE_NS_URL : "wsse",
XFORMS_NS_URL : "xforms", XFORMS_NS_URL : "xforms",
XMLSCHEMA_NS_URL : "xs", XMLSCHEMA_NS_URL : "xs",
XACML_NS_URL : "xacml", XACML_NS_URL : "xacml",
@@ -226,19 +203,23 @@ def getAgXsdToClassName():
"ag:body" : "activegrid.model.processmodel.Body", "ag:body" : "activegrid.model.processmodel.Body",
"ag:category_substitutions" : "activegrid.server.layoutrenderer.CategorySubstitutions", "ag:category_substitutions" : "activegrid.server.layoutrenderer.CategorySubstitutions",
"ag:command" : "activegrid.model.wsdl.Command", "ag:command" : "activegrid.model.wsdl.Command",
"ag:setElement" : "activegrid.model.processmodel.SetElementOperation",
"ag:css" : "activegrid.server.layoutrenderer.CSS", "ag:css" : "activegrid.server.layoutrenderer.CSS",
"ag:cssRule" : "activegrid.model.processmodel.CssRule",
"ag:databaseService" : "activegrid.server.deployment.DatabaseService", "ag:databaseService" : "activegrid.server.deployment.DatabaseService",
"ag:datasource" : "activegrid.data.dataservice.DataSource", "ag:datasource" : "activegrid.data.dataservice.DataSource",
"ag:dataObjectList" : "activegrid.data.datalang.DataObjectList", "ag:dataObjectList" : "activegrid.data.datalang.DataObjectList",
"ag:debug" : "activegrid.model.processmodel.DebugOperation", "ag:debug" : "activegrid.model.processmodel.DebugOperation",
"ag:deployment" : "activegrid.server.deployment.Deployment", "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:generator" : "activegrid.server.layoutrenderer.SerializableGenerator",
"ag:head" : "activegrid.server.layoutrenderer.Head", "ag:head" : "activegrid.server.layoutrenderer.Head",
"ag:hr" : "activegrid.model.processmodel.HorizontalRow", "ag:hr" : "activegrid.model.processmodel.HorizontalRow",
"ag:identity" : "activegrid.model.identitymodel.Identity", "ag:identity" : "activegrid.model.identitymodel.Identity",
"ag:identityref" : "activegrid.server.deployment.IdentityRef", "ag:identityref" : "activegrid.server.deployment.IdentityRef",
"ag:image" : "activegrid.model.processmodel.Image", "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:label" : "activegrid.model.processmodel.Label",
"ag:layout" : "activegrid.server.layoutrenderer.Layout", "ag:layout" : "activegrid.server.layoutrenderer.Layout",
"ag:layouts" : "activegrid.server.layoutrenderer.Layouts", "ag:layouts" : "activegrid.server.layoutrenderer.Layouts",
@@ -246,9 +227,11 @@ def getAgXsdToClassName():
"ag:localService" : "activegrid.server.deployment.LocalService", "ag:localService" : "activegrid.server.deployment.LocalService",
"ag:parameter" : "activegrid.server.layoutrenderer.Parameter", "ag:parameter" : "activegrid.server.layoutrenderer.Parameter",
"ag:parameters" : "activegrid.server.layoutrenderer.Parameters", "ag:parameters" : "activegrid.server.layoutrenderer.Parameters",
"ag:postInitialize" : "activegrid.model.processmodel.PostInitialize",
"ag:processref" : "activegrid.server.deployment.ProcessRef", "ag:processref" : "activegrid.server.deployment.ProcessRef",
"ag:query" : "activegrid.model.processmodel.Query", "ag:query" : "activegrid.model.processmodel.Query",
"ag:soapService" : "activegrid.server.deployment.SoapService", "ag:soapService" : "activegrid.server.deployment.SoapService",
"ag:redirect" : "activegrid.server.layoutrenderer.Redirect",
"ag:requiredFile" : "activegrid.server.layoutrenderer.RequiredFile", "ag:requiredFile" : "activegrid.server.layoutrenderer.RequiredFile",
"ag:resource" : "activegrid.model.identitymodel.IDResource", "ag:resource" : "activegrid.model.identitymodel.IDResource",
"ag:restService" : "activegrid.server.deployment.RestService", "ag:restService" : "activegrid.server.deployment.RestService",
@@ -355,27 +338,38 @@ def getAgXsdToClassName():
"xforms:xforms" : "activegrid.model.processmodel.XFormsRoot", "xforms:xforms" : "activegrid.model.processmodel.XFormsRoot",
"xs:all" : "activegrid.model.schema.XsdSequence", "xs:all" : "activegrid.model.schema.XsdSequence",
"xs:any" : "activegrid.model.schema.XsdAny", "xs:any" : "activegrid.model.schema.XsdAny",
"xs:anyAttribute" : "activegrid.model.schema.XsdAnyAttribute",
"xs:attribute" : "activegrid.model.schema.XsdAttribute", "xs:attribute" : "activegrid.model.schema.XsdAttribute",
"xs:choice" : "activegrid.model.schema.XsdChoice",
"xs:complexContent" : "activegrid.model.schema.XsdComplexContent", "xs:complexContent" : "activegrid.model.schema.XsdComplexContent",
"xs:complexType" : "activegrid.model.schema.XsdComplexType", "xs:complexType" : "activegrid.model.schema.XsdComplexType",
"xs:documentation" : "activegrid.model.schema.XsdDocumentation",
"xs:element" : "activegrid.model.schema.XsdElement", "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:extension" : "activegrid.model.schema.XsdExtension",
"xs:fractionDigits" : "activegrid.model.schema.XsdFacetFractionDigits",
"xs:field" : "activegrid.model.schema.XsdKeyField", "xs:field" : "activegrid.model.schema.XsdKeyField",
"xs:import" : "activegrid.model.schema.XsdInclude", "xs:import" : "activegrid.model.schema.XsdInclude",
"xs:include" : "activegrid.model.schema.XsdInclude", "xs:include" : "activegrid.model.schema.XsdInclude",
"xs:key" : "activegrid.model.schema.XsdKey", "xs:key" : "activegrid.model.schema.XsdKey",
"xs:keyref" : "activegrid.model.schema.XsdKeyRef", "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: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:restriction" : "activegrid.model.schema.XsdRestriction",
"xs:schema" : "activegrid.model.schema.Schema", "xs:schema" : "activegrid.model.schema.Schema",
"xs:selector" : "activegrid.model.schema.XsdKeySelector", "xs:selector" : "activegrid.model.schema.XsdKeySelector",
"xs:sequence" : "activegrid.model.schema.XsdSequence", "xs:sequence" : "activegrid.model.schema.XsdSequence",
"xs:simpleContent" : "activegrid.model.schema.XsdSimpleContent", "xs:simpleContent" : "activegrid.model.schema.XsdSimpleContent",
"xs:simpleType" : "activegrid.model.schema.XsdSimpleType", "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 return agXsdToClassName

View File

@@ -121,6 +121,7 @@ class FindService(wx.lib.pydocview.DocService):
self._findDialog = None self._findDialog = None
self._replaceDialog = FindReplaceDialog(self.GetDocumentManager().FindSuitableParent(), -1, _("Replace"), size=(320,200), findString=findString) self._replaceDialog = FindReplaceDialog(self.GetDocumentManager().FindSuitableParent(), -1, _("Replace"), size=(320,200), findString=findString)
self._replaceDialog.CenterOnParent()
self._replaceDialog.Show(True) self._replaceDialog.Show(True)
else: else:
if self._replaceDialog != None: if self._replaceDialog != None:
@@ -129,6 +130,7 @@ class FindService(wx.lib.pydocview.DocService):
self._replaceDialog = None self._replaceDialog = None
self._findDialog = FindDialog(self.GetDocumentManager().FindSuitableParent(), -1, _("Find"), size=(320,200), findString=findString) self._findDialog = FindDialog(self.GetDocumentManager().FindSuitableParent(), -1, _("Find"), size=(320,200), findString=findString)
self._findDialog.CenterOnParent()
self._findDialog.Show(True) self._findDialog.Show(True)
@@ -152,6 +154,7 @@ class FindService(wx.lib.pydocview.DocService):
""" Display Goto Line Number dialog box """ """ Display Goto Line Number dialog box """
line = -1 line = -1
dialog = wx.TextEntryDialog(parent, _("Enter line number to go to:"), _("Go to Line")) dialog = wx.TextEntryDialog(parent, _("Enter line number to go to:"), _("Go to Line"))
dialog.CenterOnParent()
if dialog.ShowModal() == wx.ID_OK: if dialog.ShowModal() == wx.ID_OK:
try: try:
line = int(dialog.GetValue()) line = int(dialog.GetValue())
@@ -356,7 +359,10 @@ class FindDialog(wx.Dialog):
wx.EVT_BUTTON(self, FindService.FINDONE_ID, self.OnActionEvent) wx.EVT_BUTTON(self, FindService.FINDONE_ID, self.OnActionEvent)
cancelBtn = wx.Button(self, wx.ID_CANCEL) cancelBtn = wx.Button(self, wx.ID_CANCEL)
wx.EVT_BUTTON(self, wx.ID_CANCEL, self.OnClose) 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) buttonSizer.Add(cancelBtn, 0)
gridSizer.Add(buttonSizer, pos=(0,2), span=(3,1)) 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) wx.EVT_BUTTON(self, FindService.REPLACEONE_ID, self.OnActionEvent)
replaceAllBtn = wx.Button(self, FindService.REPLACEALL_ID, _("Replace All")) replaceAllBtn = wx.Button(self, FindService.REPLACEALL_ID, _("Replace All"))
wx.EVT_BUTTON(self, FindService.REPLACEALL_ID, self.OnActionEvent) 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) BTM_SPACE = HALF_SPACE
buttonSizer.Add(replaceAllBtn, 0, wx.BOTTOM, 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) buttonSizer.Add(cancelBtn, 0)
gridSizer.Add(buttonSizer, pos=(0,2), span=(3,1)) gridSizer.Add(buttonSizer, pos=(0,2), span=(3,1))
@@ -495,12 +506,24 @@ def getFindData():
return \ return \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ '\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\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\ \x00\x01\xb1IDAT8\x8d\xa5\x93=o\xd3P\x14\x86\x1f\xa7\x11\x95<\xdc\xc6\xecN+5\
\x93S\xe5U$\n\xb3$:\xc1e\x17(\x19Z\xb3$\x9e\xf1DD\xe2\x15\x01x\xea\x93\xef\ [\x86B\x99\xacLQ2Zr[\x89\xa1\xfd\x0b%\x95\x90\x00\xf1\x03\x80\x01\x98\x80\
\x04\x989\xea\x1b\xf2U\xc0\xda\xb4\xeb\x11\x1f:\xd8\xb5\xff8\x93\xd4\xa9\xae\ \x19G\xac\x0cm\xff@Y\xd9:\xd9Ck\x94\xd6\xddb\x94\x9b\x98\xc8\xd2e1C\xe5\x8b\
@/S\xaaUwJ3\x85\xc0\x81\xee\xeb.q\x17C\x81\xd5XU \x1a\x93\xc6\x18\x8d\x90\ \xdd\x14\x96\xbe\xdb=\x1f\xefy\xef\xf90\x8c\xda\x12wA\xbd\xfc\x18\xfa\x9fs\
\xe8}\x89\x00\x9a&\x9b_k\x94\x0c\xdf\xd78\xf8\x0b\x99Y\xb4\x08c\x9e\xfe\xc6\ \x80\xf9|\x0e\xc0\x93\xc1\x81\x01\xf0\xe6\xf5\xab\x1c`:\x9d\x02\xf0\xf6\xdd{\
\xe3\x087\xf9\xd0D\x180\xf1#\x8e\x00\x00\x00\x00IEND\xaeB`\x82' \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(): def getFindBitmap():

View File

@@ -17,45 +17,45 @@ import FindService
_ = wx.GetTranslation _ = wx.GetTranslation
class TextDocument(wx.lib.docview.Document): 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() view = self.GetFirstView()
if not view.GetTextCtrl().SaveFile(filename): fileObject.write(view.GetTextCtrl().GetValue())
return False
self.Modify(False)
self.SetDocumentSaved(True)
#if wx.Platform == "__WXMAC__":
# fn = wx.Filename(filename)
# fn.MacSetDefaultTypeAndCreator()
return True return True
def OnOpenDocument(self, filename): def LoadObject(self, fileObject):
view = self.GetFirstView() view = self.GetFirstView()
if not view.GetTextCtrl().LoadFile(filename): data = fileObject.read()
return False view.GetTextCtrl().SetValue(data)
self.SetFilename(filename, True)
self.Modify(False)
self.UpdateAllViews()
self._savedYet = True
return True return True
def IsModified(self): def IsModified(self):
view = self.GetFirstView() view = self.GetFirstView()
if view and view.GetTextCtrl(): if view and view.GetTextCtrl():
return wx.lib.docview.Document.IsModified(self) or view.GetTextCtrl().IsModified() return view.GetTextCtrl().IsModified()
else: return False
return wx.lib.docview.Document.IsModified(self)
def Modify(self, mod): def Modify(self, modify):
if self._inModify:
return
self._inModify = True
view = self.GetFirstView() view = self.GetFirstView()
wx.lib.docview.Document.Modify(self, mod) if not modify and view and view.GetTextCtrl():
if not mod and view and view.GetTextCtrl():
view.GetTextCtrl().DiscardEdits() 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): class TextView(wx.lib.docview.View):
@@ -75,6 +75,7 @@ class TextView(wx.lib.docview.View):
sizer = wx.BoxSizer() sizer = wx.BoxSizer()
font, color = self._GetFontAndColorFromConfig() font, color = self._GetFontAndColorFromConfig()
self._textCtrl = self._BuildTextCtrl(frame, font, color = color) self._textCtrl = self._BuildTextCtrl(frame, font, color = color)
self._textCtrl.Bind(wx.EVT_TEXT, self.OnModify)
sizer.Add(self._textCtrl, 1, wx.EXPAND, 0) sizer.Add(self._textCtrl, 1, wx.EXPAND, 0)
frame.SetSizer(sizer) frame.SetSizer(sizer)
frame.Layout() frame.Layout()
@@ -83,6 +84,10 @@ class TextView(wx.lib.docview.View):
return True return True
def OnModify(self, event):
self.GetDocument().Modify(True)
def _BuildTextCtrl(self, parent, font, color = wx.BLACK, value = "", selection = [0, 0]): def _BuildTextCtrl(self, parent, font, color = wx.BLACK, value = "", selection = [0, 0]):
if self._wordWrap: if self._wordWrap:
wordWrapStyle = wx.TE_WORDWRAP wordWrapStyle = wx.TE_WORDWRAP
@@ -131,6 +136,9 @@ class TextView(wx.lib.docview.View):
def OnUpdate(self, sender = None, hint = None): def OnUpdate(self, sender = None, hint = None):
if wx.lib.docview.View.OnUpdate(self, sender, hint):
return
if hint == "Word Wrap": if hint == "Word Wrap":
self.SetWordWrap(wx.ConfigBase_Get().ReadInt("TextEditorWordWrap", True)) self.SetWordWrap(wx.ConfigBase_Get().ReadInt("TextEditorWordWrap", True))
elif hint == "Font": elif hint == "Font":

View File

@@ -6,7 +6,7 @@
# #
# Created: 5/15/03 # Created: 5/15/03
# CVS-ID: $Id$ # 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 # License: wxWindows license
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------
@@ -214,8 +214,10 @@ class Document(wx.EvtHandler):
false otherwise. You may need to override this if your document view false otherwise. You may need to override this if your document view
maintains its own record of being modified (for example if using maintains its own record of being modified (for example if using
xTextWindow to view and edit the document). 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._documentModified = modify
self.UpdateAllViews(hint=("modify", self, self._documentModified))
def SetDocumentModificationDate(self): def SetDocumentModificationDate(self):
@@ -236,6 +238,16 @@ class Document(wx.EvtHandler):
return self._documentModificationDate 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): def GetViews(self):
""" """
Returns the list whose elements are the views on the document. 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. Destructor. Removes itself from the document manager.
""" """
self.DeleteContents() self.DeleteContents()
self._documentModificationDate = None
if self.GetDocumentManager(): if self.GetDocumentManager():
self.GetDocumentManager().RemoveDocument(self) self.GetDocumentManager().RemoveDocument(self)
wx.EvtHandler.Destroy(self) wx.EvtHandler.Destroy(self)
@@ -364,7 +377,7 @@ class Document(wx.EvtHandler):
return True return True
""" check for file modification outside of application """ """ 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() msgTitle = wx.GetApp().GetAppName()
if not msgTitle: if not msgTitle:
msgTitle = _("Application") msgTitle = _("Application")
@@ -485,9 +498,9 @@ class Document(wx.EvtHandler):
self.GetDocumentWindow()) self.GetDocumentWindow())
return False return False
self.SetDocumentModificationDate()
self.SetFilename(filename, True) self.SetFilename(filename, True)
self.Modify(False) self.Modify(False)
self.SetDocumentModificationDate()
self.SetDocumentSaved(True) self.SetDocumentSaved(True)
#if wx.Platform == '__WXMAC__': # Not yet implemented in wxPython #if wx.Platform == '__WXMAC__': # Not yet implemented in wxPython
# wx.FileName(file).MacSetDefaultTypeAndCreator() # wx.FileName(file).MacSetDefaultTypeAndCreator()
@@ -529,9 +542,9 @@ class Document(wx.EvtHandler):
self.GetDocumentWindow()) self.GetDocumentWindow())
return False return False
self.SetDocumentModificationDate()
self.SetFilename(filename, True) self.SetFilename(filename, True)
self.Modify(False) self.Modify(False)
self.SetDocumentModificationDate()
self.SetDocumentSaved(True) self.SetDocumentSaved(True)
self.UpdateAllViews() self.UpdateAllViews()
return True return True
@@ -614,7 +627,7 @@ class Document(wx.EvtHandler):
return True return True
""" check for file modification outside of application """ """ 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() msgTitle = wx.GetApp().GetAppName()
if not msgTitle: if not msgTitle:
msgTitle = _("Warning") msgTitle = _("Warning")
@@ -844,8 +857,14 @@ class View(wx.EvtHandler):
unused but may in future contain application-specific information for unused but may in future contain application-specific information for
making updating more efficient. 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): def OnChangeFilename(self):
""" """
@@ -916,11 +935,11 @@ class View(wx.EvtHandler):
Call this from your view frame's OnActivate member to tell the Call this from your view frame's OnActivate member to tell the
framework which view is currently active. If your windowing system framework which view is currently active. If your windowing system
doesn't call OnActivate, you may need to call this function from 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 framework will need to get the current view.
The prepackaged view frame wxDocChildFrame calls wxView.Activate from 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(): if self.GetDocument() and self.GetDocumentManager():
self.OnActivateView(activate, self, self.GetDocumentManager().GetCurrentView()) self.OnActivateView(activate, self, self.GetDocumentManager().GetCurrentView())
@@ -1865,7 +1884,7 @@ class DocManager(wx.EvtHandler):
for document in self._docs: for document in self._docs:
if document.GetFilename() and os.path.normcase(document.GetFilename()) == os.path.normcase(path): if document.GetFilename() and os.path.normcase(document.GetFilename()) == os.path.normcase(path):
""" check for file modification outside of application """ """ 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() msgTitle = wx.GetApp().GetAppName()
if not msgTitle: if not msgTitle:
msgTitle = _("Warning") msgTitle = _("Warning")
@@ -2148,7 +2167,7 @@ class DocManager(wx.EvtHandler):
if len(descr) > 0: if len(descr) > 0:
descr = descr + _('|') 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 = 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: else:
descr = _("*.*") descr = _("*.*")
@@ -2791,6 +2810,7 @@ class DocMDIChildFrame(wx.MDIChildFrame):
self._childView.Activate(event.GetActive()) self._childView.Activate(event.GetActive())
self._activated = 0 self._activated = 0
def OnCloseWindow(self, event): def OnCloseWindow(self, event):
""" """
Closes and deletes the current view and document. Closes and deletes the current view and document.
@@ -2846,6 +2866,28 @@ class DocMDIChildFrame(wx.MDIChildFrame):
self._childView = view 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): class DocPrintout(wx.Printout):
""" """
DocPrintout is a default Printout that prints the first page of a document DocPrintout is a default Printout that prints the first page of a document
@@ -2892,15 +2934,6 @@ class DocPrintout(wx.Printout):
return pageNum == 1 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): def GetPageInfo(self):
""" """
Indicates that the DocPrintout only has a single page. Indicates that the DocPrintout only has a single page.

File diff suppressed because it is too large Load Diff