mirror of
https://github.com/wxWidgets/wxWidgets.git
synced 2026-08-18 18:22:01 +08:00
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:
@@ -0,0 +1,20 @@
|
||||
#----------------------------------------------------------------------------
|
||||
# Name: projectmodel.py
|
||||
# Purpose: This file contains project model information
|
||||
#
|
||||
# Author: Morgan Hua
|
||||
#
|
||||
# Created: 4/18/06
|
||||
# CVS-ID: $Id$
|
||||
# Copyright: (c) 2006 ActiveGrid, Inc.
|
||||
# License: wxWindows License
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Constants
|
||||
#----------------------------------------------------------------------------
|
||||
LANGUAGE_PYTHON = "python"
|
||||
LANGUAGE_PHP = "php"
|
||||
LANGUAGE_DEFAULT = LANGUAGE_PYTHON
|
||||
LANGUAGE_LIST = [LANGUAGE_PHP, LANGUAGE_PYTHON]
|
||||
@@ -5,7 +5,7 @@
|
||||
# Author: Morgan Hua
|
||||
#
|
||||
# Created: 3/22/05
|
||||
# Copyright: (c) 2005 ActiveGrid, Inc.
|
||||
# Copyright: (c) 2005-2006 ActiveGrid, Inc.
|
||||
# CVS-ID: $Id$
|
||||
# License: wxWindows License
|
||||
#----------------------------------------------------------------------------
|
||||
@@ -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"),
|
||||
("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"),
|
||||
("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/"),
|
||||
("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
|
||||
licenseData += [
|
||||
("pydb2", "LGPL", "http://sourceforge.net/projects/pydb2"),
|
||||
("pydb2", "LGPL", "http://sourceforge.net/projects/pydb2"),
|
||||
("pysqlite", "Python License (CNRI)", "http://sourceforge.net/projects/pysqlite"),
|
||||
("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"),
|
||||
("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"),
|
||||
("SQLite", "Public Domain", "http://www.sqlite.org/copyright.html"),
|
||||
("PyGreSQL", "BSD", "http://www.pygresql.org"),
|
||||
("pyXML", "CNRI Python License", "http://sourceforge.net/softwaremap/trove_list.php?form_cat=194"),
|
||||
("Zolera Soap Infrastructure", "Zope Public License 2.0", "http://www.zope.org/Resources/License/"),
|
||||
("python-ldap", "Python Software Foundation License", "http://python-ldap.sourceforge.net"),
|
||||
("Sarissa", "LGPL", "http://sourceforge.net/projects/sarissa/"),
|
||||
("Dynarch DHTML Calendar", "LGPL", "http://www.dynarch.com/projects/calendar/"),
|
||||
("python-dateutil", "Python Software Foundation License", "http://labix.org/python-dateutil"),
|
||||
]
|
||||
|
||||
if wx.Platform == '__WXMSW__': # add Windows only licenses
|
||||
@@ -70,7 +72,7 @@ class AboutDialog(wx.Dialog):
|
||||
else:
|
||||
splash_bmp = getIDESplashBitmap()
|
||||
|
||||
# find version number from
|
||||
# find version number from
|
||||
versionFilepath = os.path.join(sysutilslib.mainModuleDir, "version.txt")
|
||||
if os.path.exists(versionFilepath):
|
||||
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()))
|
||||
sizer.Add(image, 0, wx.ALIGN_CENTER|wx.ALL, 0)
|
||||
sizer.Add(wx.StaticText(aboutPage, -1, wx.GetApp().GetAppName() + _("\n%s\n\nCopyright (c) 2003-2005 ActiveGrid Incorporated and Contributors. All rights reserved.") % version), 0, wx.ALIGN_LEFT|wx.ALL, 10)
|
||||
sizer.Add(wx.StaticText(aboutPage, -1, wx.GetApp().GetAppName() + _("\n%s\n\nCopyright (c) 2003-2006 ActiveGrid Incorporated and Contributors. All rights reserved.") % version), 0, wx.ALIGN_LEFT|wx.ALL, 10)
|
||||
sizer.Add(wx.StaticText(aboutPage, -1, _("http://www.activegrid.com")), 0, wx.ALIGN_LEFT|wx.LEFT|wx.BOTTOM, 10)
|
||||
aboutPage.SetSizer(sizer)
|
||||
nb.AddPage(aboutPage, _("Copyright"))
|
||||
@@ -90,15 +92,14 @@ class AboutDialog(wx.Dialog):
|
||||
licensePage = wx.Panel(nb, -1)
|
||||
grid = wx.grid.Grid(licensePage, -1)
|
||||
grid.CreateGrid(len(licenseData), 2)
|
||||
|
||||
|
||||
dc = wx.ClientDC(grid)
|
||||
dc.SetFont(grid.GetLabelFont())
|
||||
grid.SetColLabelValue(0, _("License"))
|
||||
grid.SetColLabelValue(1, _("URL"))
|
||||
w, maxHeight = dc.GetTextExtent(_("License"))
|
||||
w, h = dc.GetTextExtent(_("URL"))
|
||||
if h > maxHeight:
|
||||
maxHeight = h
|
||||
w, h1 = dc.GetTextExtent(_("License"))
|
||||
w, h2 = dc.GetTextExtent(_("URL"))
|
||||
maxHeight = max(h1, h2)
|
||||
grid.SetColLabelSize(maxHeight + 6) # add a 6 pixel margin
|
||||
|
||||
maxW = 0
|
||||
@@ -115,7 +116,7 @@ class AboutDialog(wx.Dialog):
|
||||
grid.SetCellValue(row, 0, license)
|
||||
if url:
|
||||
grid.SetCellValue(row, 1, url)
|
||||
|
||||
|
||||
grid.EnableEditing(False)
|
||||
grid.EnableDragGridSize(False)
|
||||
grid.EnableDragColSize(False)
|
||||
@@ -132,10 +133,10 @@ class AboutDialog(wx.Dialog):
|
||||
|
||||
creditsPage = wx.Panel(nb, -1)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
sizer.Add(wx.StaticText(creditsPage, -1, _("ActiveGrid Development Team:\n\nLarry Abrahams\nLawrence Bruhmuller\nEric Chu\nBeth Fryer\nMatt Fryer\nJoel Hare\nMorgan Hua\nMatt McNulty\nPratik Mehta\nAlan Mullendore\nJeff Norton\nSimon Toens\nKevin Wang\nPeter Yared")), 0, wx.ALIGN_LEFT|wx.ALL, 10)
|
||||
sizer.Add(wx.StaticText(creditsPage, -1, _("ActiveGrid Development Team:\n\nLarry Abrahams\nLawrence Bruhmuller\nEric Chu\nBeth Fryer\nMatt Fryer\nFrankie Fu\nJoel Hare\nMorgan Hua\nMatt McNulty\nPratik Mehta\nAlan Mullendore\nJeff Norton\nKevin Ollivier\nMatt Small\nSimon Toens\nKevin Wang\nPeter Yared\nJeremy Yun")), 0, wx.ALIGN_LEFT|wx.ALL, 10)
|
||||
creditsPage.SetSizer(sizer)
|
||||
nb.AddPage(creditsPage, _("Credits"))
|
||||
|
||||
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
sizer.Add(nb, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
|
||||
btn = wx.Button(self, wx.ID_OK)
|
||||
@@ -145,5 +146,5 @@ class AboutDialog(wx.Dialog):
|
||||
self.Layout()
|
||||
self.Fit()
|
||||
grid.ForceRefresh() # wxBug: Get rid of unnecessary scrollbars
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ PARKING_VERTICAL = 1
|
||||
PARKING_HORIZONTAL = 2
|
||||
PARKING_OFFSET = 30 # space between shapes
|
||||
|
||||
FORCE_REDRAW_METHOD = "ForceRedraw"
|
||||
|
||||
def GetRawModel(model):
|
||||
if hasattr(model, "GetRawModel"):
|
||||
@@ -85,6 +86,7 @@ class CanvasView(wx.lib.docview.View):
|
||||
self._propShape = None
|
||||
self._maxWidth = 2000
|
||||
self._maxHeight = 16000
|
||||
self._valetParking = False
|
||||
|
||||
|
||||
def OnDraw(self, dc):
|
||||
@@ -195,6 +197,16 @@ class CanvasView(wx.lib.docview.View):
|
||||
self.SetPropertyModel(None)
|
||||
|
||||
|
||||
def SetLastRightClick(self, x, y):
|
||||
self._lastRightClick = (x,y)
|
||||
|
||||
|
||||
def GetLastRightClick(self):
|
||||
if hasattr(self, "_lastRightClick"):
|
||||
return self._lastRightClick
|
||||
return (-1,-1)
|
||||
|
||||
|
||||
def OnKeyPressed(self, event):
|
||||
key = event.KeyCode()
|
||||
if key == wx.WXK_DELETE:
|
||||
@@ -211,6 +223,7 @@ class CanvasView(wx.lib.docview.View):
|
||||
dc = wx.ClientDC(self._canvas)
|
||||
self._canvas.PrepareDC(dc)
|
||||
x, y = event.GetLogicalPosition(dc) # this takes into account scrollbar offset
|
||||
self.SetLastRightClick(x, y)
|
||||
shape = self._canvas.FindShape(x, y)[0]
|
||||
|
||||
model = None
|
||||
@@ -260,12 +273,15 @@ class CanvasView(wx.lib.docview.View):
|
||||
pass
|
||||
else:
|
||||
# click on empty part of canvas, deselect everything
|
||||
forceRedrawShapes = []
|
||||
needRefresh = False
|
||||
for shape in self._diagram.GetShapeList():
|
||||
if hasattr(shape, "GetModel"):
|
||||
if shape.Selected():
|
||||
needRefresh = True
|
||||
shape.Select(False, dc)
|
||||
if hasattr(shape, FORCE_REDRAW_METHOD):
|
||||
forceRedrawShapes.append(shape)
|
||||
if needRefresh:
|
||||
self._canvas.Redraw(dc)
|
||||
|
||||
@@ -274,7 +290,8 @@ class CanvasView(wx.lib.docview.View):
|
||||
if len(self.GetSelection()) == 0:
|
||||
self.SetPropertyShape(None)
|
||||
|
||||
|
||||
for shape in forceRedrawShapes:
|
||||
shape.ForceRedraw()
|
||||
|
||||
def OnLeftDoubleClick(self, event):
|
||||
propertyService = wx.GetApp().GetService(PropertyService.PropertyService)
|
||||
@@ -401,8 +418,20 @@ class CanvasView(wx.lib.docview.View):
|
||||
dc.EndDrawing()
|
||||
|
||||
|
||||
def SetValetParking(self, enable=True):
|
||||
""" If valet parking is enabled, remember last parking spot and try for a spot near it """
|
||||
self._valetParking = enable
|
||||
if enable:
|
||||
self._valetPosition = None
|
||||
|
||||
|
||||
def FindParkingSpot(self, width, height, parking=PARKING_HORIZONTAL, x=PARKING_OFFSET, y=PARKING_OFFSET):
|
||||
""" given a width and height, find a upper left corner where shape can be parked without overlapping other shape """
|
||||
"""
|
||||
Given a width and height, find a upper left corner where shape can be parked without overlapping other shape
|
||||
"""
|
||||
if self._valetParking and self._valetPosition:
|
||||
x, y = self._valetPosition
|
||||
|
||||
max = 700 # max distance to the right where we'll place tables
|
||||
noParkingSpot = True
|
||||
|
||||
@@ -422,6 +451,9 @@ class CanvasView(wx.lib.docview.View):
|
||||
else:
|
||||
noParkingSpot = False
|
||||
|
||||
if self._valetParking:
|
||||
self._valetPosition = (x, y)
|
||||
|
||||
return x, y
|
||||
|
||||
|
||||
@@ -518,7 +550,8 @@ class CanvasView(wx.lib.docview.View):
|
||||
self._diagram.RemoveShape(line)
|
||||
line.Delete()
|
||||
|
||||
shape.RemoveFromCanvas(self._canvas)
|
||||
if self._canvas:
|
||||
shape.RemoveFromCanvas(self._canvas)
|
||||
self._diagram.RemoveShape(shape)
|
||||
shape.Delete()
|
||||
|
||||
@@ -698,6 +731,9 @@ class CanvasView(wx.lib.docview.View):
|
||||
self._propShape.SetTextColour("WHITE", 0)
|
||||
self._propShape.Draw(dc)
|
||||
|
||||
if hasattr(self._propShape, FORCE_REDRAW_METHOD):
|
||||
self._propShape.ForceRedraw()
|
||||
|
||||
dc.EndDrawing()
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ import os
|
||||
import re
|
||||
import string
|
||||
import sys
|
||||
import DebuggerService
|
||||
import MarkerService
|
||||
from UICommon import CaseInsensitiveCompare
|
||||
_ = wx.GetTranslation
|
||||
@@ -120,16 +119,27 @@ class CodeView(STCTextEditor.TextView):
|
||||
return False
|
||||
id = event.GetId()
|
||||
if id == EXPAND_TEXT_ID:
|
||||
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
|
||||
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
|
||||
elif (id == EXPAND_TOP_ID
|
||||
or id == COLLAPSE_TOP_ID
|
||||
or id == EXPAND_ALL_ID
|
||||
or id == COLLAPSE_ALL_ID
|
||||
or id == AUTO_COMPLETE_ID
|
||||
or id == COLLAPSE_ALL_ID):
|
||||
if self.GetCtrl().GetViewFolding():
|
||||
event.Enable(self.GetCtrl().GetTextLength() > 0)
|
||||
else:
|
||||
event.Enable(False)
|
||||
return True
|
||||
elif (id == AUTO_COMPLETE_ID
|
||||
or id == CLEAN_WHITESPACE
|
||||
or id == INDENT_LINES_ID
|
||||
or id == DEDENT_LINES_ID
|
||||
@@ -140,10 +150,12 @@ class CodeView(STCTextEditor.TextView):
|
||||
elif id == CHECK_CODE_ID:
|
||||
event.Enable(False)
|
||||
return True
|
||||
elif (id == SET_INDENT_WIDTH_ID
|
||||
or id == FOLDING_ID):
|
||||
elif id == SET_INDENT_WIDTH_ID:
|
||||
event.Enable(True)
|
||||
return True
|
||||
elif id == FOLDING_ID:
|
||||
event.Enable(self.GetCtrl().GetViewFolding())
|
||||
return True
|
||||
elif id == USE_TABS_ID:
|
||||
event.Enable(True)
|
||||
event.Check(self.GetCtrl().GetUseTabs())
|
||||
@@ -210,7 +222,7 @@ class CodeView(STCTextEditor.TextView):
|
||||
filename = document.GetFilename()
|
||||
if filename:
|
||||
rootItem = treeCtrl.AddRoot(os.path.basename(filename))
|
||||
treeCtrl.SetDoSelectCallback(rootItem, self, None)
|
||||
treeCtrl.SetDoSelectCallback(rootItem, self, (0,0))
|
||||
else:
|
||||
return True
|
||||
|
||||
@@ -232,11 +244,13 @@ class CodeView(STCTextEditor.TextView):
|
||||
if classLine:
|
||||
indent = classLine.start(0)
|
||||
itemStr = classLine.string[classLine.start(0):classLine.end(0)-1] # don't take the closing ':'
|
||||
itemStr = itemStr.replace("\n", "").replace("\r", "").replace(",\\", ",").replace(" ", "") # remove line continuations and spaces from outline view
|
||||
else:
|
||||
defLine = defPat.search(line)
|
||||
if defLine:
|
||||
indent = defLine.start(0)
|
||||
itemStr = defLine.string[defLine.start(0):defLine.end(0)]
|
||||
itemStr = itemStr.replace("\n", "").replace("\r", "").replace(",\\", ",").replace(" ", "") # remove line continuations and spaces from outline view
|
||||
|
||||
if indent == 0:
|
||||
parentItem = rootItem
|
||||
@@ -467,6 +481,9 @@ class CodeView(STCTextEditor.TextView):
|
||||
|
||||
|
||||
def OnUpdate(self, sender = None, hint = None):
|
||||
if wx.lib.docview.View.OnUpdate(self, sender, hint):
|
||||
return
|
||||
|
||||
if hint == "ViewStuff":
|
||||
self.GetCtrl().SetViewDefaults()
|
||||
elif hint == "Font":
|
||||
@@ -474,6 +491,7 @@ class CodeView(STCTextEditor.TextView):
|
||||
self.GetCtrl().SetFont(font)
|
||||
self.GetCtrl().SetFontColor(color)
|
||||
else:
|
||||
import DebuggerService
|
||||
dbg_service = wx.GetApp().GetService(DebuggerService.DebuggerService)
|
||||
if dbg_service:
|
||||
dbg_service.SetCurrentBreakpointMarkers(self)
|
||||
@@ -623,7 +641,7 @@ class CodeCtrl(STCTextEditor.TextCtrl):
|
||||
BREAKPOINT_MARKER_MASK = 0x2
|
||||
|
||||
|
||||
def __init__(self, parent, id=-1, style = wx.NO_FULL_REPAINT_ON_RESIZE):
|
||||
def __init__(self, parent, id=-1, style = wx.NO_FULL_REPAINT_ON_RESIZE, clearTab=True):
|
||||
STCTextEditor.TextCtrl.__init__(self, parent, id, style)
|
||||
|
||||
self.UsePopUp(False)
|
||||
@@ -635,7 +653,6 @@ class CodeCtrl(STCTextEditor.TextCtrl):
|
||||
self.SetMarginType(2, wx.stc.STC_MARGIN_SYMBOL)
|
||||
self.SetMarginMask(2, wx.stc.STC_MASK_FOLDERS)
|
||||
self.SetMarginSensitive(2, True)
|
||||
self.SetMarginWidth(2, 12)
|
||||
|
||||
self.SetMarginSensitive(1, False)
|
||||
self.SetMarginMask(1, 0x4)
|
||||
@@ -657,7 +674,7 @@ class CodeCtrl(STCTextEditor.TextCtrl):
|
||||
# Define the breakpoint marker
|
||||
self.MarkerDefine(CodeCtrl.BREAKPOINT_MARKER_NUM, wx.stc.STC_MARK_CIRCLE, wx.BLACK, (255,0,0))
|
||||
|
||||
if _WINDOWS: # should test to see if menu item exists, if it does, add this workaround
|
||||
if _WINDOWS and clearTab: # should test to see if menu item exists, if it does, add this workaround
|
||||
self.CmdKeyClear(wx.stc.STC_KEY_TAB, 0) # menu item "Indent Lines" from CodeService.InstallControls() generates another INDENT_LINES_ID event, so we'll explicitly disable the tab processing in the editor
|
||||
|
||||
wx.stc.EVT_STC_MARGINCLICK(self, self.GetId(), self.OnMarginClick)
|
||||
@@ -693,7 +710,7 @@ class CodeCtrl(STCTextEditor.TextCtrl):
|
||||
item = wx.MenuItem(menu, TOGGLEBREAKPOINT_ID, _("Toggle Breakpoint"))
|
||||
menu.AppendItem(item)
|
||||
self.Bind(wx.EVT_MENU, self.OnPopToggleMarker, id=TOGGLEMARKER_ID)
|
||||
item = wx.MenuItem(menu, TOGGLEMARKER_ID, _("Toggle Marker"))
|
||||
item = wx.MenuItem(menu, TOGGLEMARKER_ID, _("Toggle Bookmark"))
|
||||
menu.AppendItem(item)
|
||||
menu.AppendSeparator()
|
||||
|
||||
@@ -715,6 +732,7 @@ class CodeCtrl(STCTextEditor.TextCtrl):
|
||||
|
||||
def OnPopToggleBP(self, event):
|
||||
""" Toggle break point on right click line, not current line """
|
||||
import DebuggerService
|
||||
wx.GetApp().GetService(DebuggerService.DebuggerService).OnToggleBreakpoint(event, line=self._rightClickLine)
|
||||
|
||||
|
||||
@@ -859,6 +877,7 @@ class CodeCtrl(STCTextEditor.TextCtrl):
|
||||
|
||||
elif evt.GetMargin() == 0:
|
||||
#This is used to toggle breakpoints via the debugger service.
|
||||
import DebuggerService
|
||||
db_service = wx.GetApp().GetService(DebuggerService.DebuggerService)
|
||||
if db_service:
|
||||
db_service.OnToggleBreakpoint(evt, line=self.LineFromPosition(evt.GetPosition()))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@
|
||||
#
|
||||
# Created: 5/23/05
|
||||
# CVS-ID: $ID:$
|
||||
# Copyright: (c) 2005 ActiveGrid, Inc.
|
||||
# Copyright: (c) 2005-2006 ActiveGrid, Inc.
|
||||
# License: wxWindows License
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
@@ -17,27 +17,22 @@ import ProjectEditor
|
||||
import os
|
||||
import os.path
|
||||
import activegrid.util.xmlutils as xmlutils
|
||||
|
||||
_ = wx.GetTranslation
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Constants
|
||||
#----------------------------------------------------------------------------
|
||||
SPACE = 10
|
||||
HALF_SPACE = 5
|
||||
|
||||
|
||||
EXTENSIONS_CONFIG_STRING = "Extensions"
|
||||
|
||||
|
||||
|
||||
# TODO: Redo extensions menu on OK, or provide alert that it won't happen until restart
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Classes
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
class Extension:
|
||||
|
||||
|
||||
|
||||
def __init__(self, menuItemName=None):
|
||||
self.menuItemName = menuItemName
|
||||
@@ -48,7 +43,7 @@ class Extension:
|
||||
self.commandPostArgs = ''
|
||||
self.fileExt = None
|
||||
self.opOnSelectedFile = True
|
||||
|
||||
|
||||
|
||||
class ExtensionService(wx.lib.pydocview.DocService):
|
||||
|
||||
@@ -60,8 +55,8 @@ class ExtensionService(wx.lib.pydocview.DocService):
|
||||
|
||||
def __getExtensionKeyName(extensionName):
|
||||
return "%s/%s" % (ExtensionService.EXTENSIONS_KEY, extensionName)
|
||||
|
||||
|
||||
|
||||
|
||||
__getExtensionKeyName = staticmethod(__getExtensionKeyName)
|
||||
|
||||
|
||||
@@ -79,7 +74,7 @@ class ExtensionService(wx.lib.pydocview.DocService):
|
||||
cont, value, index = config.GetNextEntry(index)
|
||||
finally:
|
||||
config.SetPath(path)
|
||||
|
||||
|
||||
for extensionName in extensionNames:
|
||||
extensionData = config.Read(self.__getExtensionKeyName(extensionName))
|
||||
if extensionData:
|
||||
@@ -112,10 +107,10 @@ class ExtensionService(wx.lib.pydocview.DocService):
|
||||
toolsMenu = menuBar.GetMenu(toolsMenuIndex)
|
||||
else:
|
||||
toolsMenu = wx.Menu()
|
||||
|
||||
|
||||
if self._extensions:
|
||||
if toolsMenu.GetMenuItems():
|
||||
toolsMenu.AppendSeparator()
|
||||
toolsMenu.AppendSeparator()
|
||||
for ext in self._extensions:
|
||||
# Append a tool menu item for each extension
|
||||
ext.id = wx.NewId()
|
||||
@@ -192,7 +187,7 @@ class ExtensionService(wx.lib.pydocview.DocService):
|
||||
if extension.commandPostArgs:
|
||||
cmds.append(extension.commandPostArgs)
|
||||
os.spawnv(os.P_NOWAIT, extension.command, cmds)
|
||||
|
||||
|
||||
else:
|
||||
cmd = extension.command
|
||||
if extension.commandPreArgs:
|
||||
@@ -207,24 +202,24 @@ class ExtensionService(wx.lib.pydocview.DocService):
|
||||
view.AddLines(line)
|
||||
view.GetControl().EnsureCaretVisible()
|
||||
f.close()
|
||||
|
||||
|
||||
|
||||
class ExtensionOptionsPanel(wx.Panel):
|
||||
|
||||
|
||||
def __init__(self, parent, id):
|
||||
wx.Panel.__init__(self, parent, id)
|
||||
|
||||
|
||||
extOptionsPanelBorderSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
|
||||
extOptionsPanelSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
|
||||
extCtrlSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
extCtrlSizer.Add(wx.StaticText(self, -1, _("External Tools:")), 0, wx.BOTTOM, HALF_SPACE)
|
||||
self._extListBox = wx.ListBox(self, -1, size=(-1,160), style=wx.LB_SINGLE)
|
||||
self._extListBox = wx.ListBox(self, -1, style=wx.LB_SINGLE)
|
||||
self.Bind(wx.EVT_LISTBOX, self.OnListBoxSelect, self._extListBox)
|
||||
extCtrlSizer.Add(self._extListBox, 1, wx.BOTTOM | wx.EXPAND, SPACE)
|
||||
buttonSizer = wx.GridSizer(cols=2, vgap=5, hgap=10)
|
||||
extCtrlSizer.Add(self._extListBox, 1, wx.BOTTOM | wx.EXPAND, SPACE)
|
||||
buttonSizer = wx.GridSizer(cols=2, vgap=HALF_SPACE, hgap=HALF_SPACE)
|
||||
self._moveUpButton = wx.Button(self, -1, _("Move Up"))
|
||||
self.Bind(wx.EVT_BUTTON, self.OnMoveUp, self._moveUpButton)
|
||||
buttonSizer.Add(self._moveUpButton, 1, wx.EXPAND)
|
||||
@@ -243,21 +238,21 @@ class ExtensionOptionsPanel(wx.Panel):
|
||||
self._extDetailPanel = wx.Panel(self)
|
||||
staticBox = wx.StaticBox(self, label=_("Selected External Tool"))
|
||||
staticBoxSizer = wx.StaticBoxSizer(staticBox, wx.VERTICAL)
|
||||
|
||||
extDetailSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=3)
|
||||
|
||||
extDetailSizer = wx.FlexGridSizer(cols=2, vgap=5, hgap=5)
|
||||
extDetailSizer.AddGrowableCol(1,1)
|
||||
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Menu Item Name:")))
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Menu Item Name:")), flag=wx.ALIGN_CENTER_VERTICAL)
|
||||
self._menuItemNameTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1))
|
||||
extDetailSizer.Add(self._menuItemNameTextCtrl, 0, wx.EXPAND)
|
||||
self.Bind(wx.EVT_TEXT, self.SaveCurrentItem, self._menuItemNameTextCtrl)
|
||||
self.Bind(wx.EVT_TEXT, self.SaveCurrentItem, self._menuItemNameTextCtrl)
|
||||
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Menu Item Description:")))
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Menu Item Description:")), flag=wx.ALIGN_CENTER_VERTICAL)
|
||||
self._menuItemDescTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1))
|
||||
extDetailSizer.Add(self._menuItemDescTextCtrl, 0, wx.EXPAND)
|
||||
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Command Path:")))
|
||||
self._commandTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1))
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Command Path:")), flag=wx.ALIGN_CENTER_VERTICAL)
|
||||
self._commandTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1))
|
||||
findFileButton = wx.Button(self._extDetailPanel, -1, _("Browse..."))
|
||||
def OnBrowseButton(event):
|
||||
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)
|
||||
extDetailSizer.Add(hsizer, 0, wx.EXPAND)
|
||||
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Command Pre Args:")))
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Command Pre Args:")), flag=wx.ALIGN_CENTER_VERTICAL)
|
||||
self._commandPreArgsTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1))
|
||||
extDetailSizer.Add(self._commandPreArgsTextCtrl, 0, wx.EXPAND)
|
||||
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Command Post Args:")))
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("Command Post Args:")), flag=wx.ALIGN_CENTER_VERTICAL)
|
||||
self._commandPostArgsTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1))
|
||||
extDetailSizer.Add(self._commandPostArgsTextCtrl, 0, wx.EXPAND)
|
||||
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("File Extensions:")))
|
||||
extDetailSizer.Add(wx.StaticText(self._extDetailPanel, -1, _("File Extensions:")), flag=wx.ALIGN_CENTER_VERTICAL)
|
||||
self._fileExtTextCtrl = wx.TextCtrl(self._extDetailPanel, -1, size = (-1, -1))
|
||||
self._fileExtTextCtrl.SetToolTipString(_("""For example: "txt, text" (comma separated) or "*" for all files"""))
|
||||
extDetailSizer.Add(self._fileExtTextCtrl, 0, wx.EXPAND)
|
||||
|
||||
self._selFileCtrl = wx.CheckBox(self._extDetailPanel, -1, _("Operate on Selected File"))
|
||||
extDetailSizer.Add(self._selFileCtrl)
|
||||
extDetailSizer.Add(self._selFileCtrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.TOP, SPACE)
|
||||
self._selFileCtrl.SetToolTipString(_("If focus is in the project, instead of operating on the project file, operate on the selected file."))
|
||||
|
||||
self._extDetailPanel.SetSizer(extDetailSizer)
|
||||
staticBoxSizer.Add(self._extDetailPanel, 1, wx.ALL|wx.EXPAND, SPACE)
|
||||
|
||||
|
||||
extOptionsPanelSizer.Add(staticBoxSizer, 1, wx.LEFT|wx.EXPAND, SPACE)
|
||||
|
||||
extOptionsPanelBorderSizer.Add(extOptionsPanelSizer, 1, wx.ALL|wx.EXPAND, SPACE)
|
||||
@@ -306,8 +301,8 @@ class ExtensionOptionsPanel(wx.Panel):
|
||||
self.OnListBoxSelect()
|
||||
|
||||
self.Layout()
|
||||
|
||||
parent.AddPage(self, _("External Tools"))
|
||||
|
||||
parent.AddPage(self, _("External Tools"))
|
||||
|
||||
|
||||
def OnOK(self, optionsDialog):
|
||||
@@ -323,7 +318,7 @@ class ExtensionOptionsPanel(wx.Panel):
|
||||
msgTitle,
|
||||
wx.OK | wx.ICON_INFORMATION,
|
||||
self.GetParent())
|
||||
|
||||
|
||||
|
||||
def PopulateItems(self):
|
||||
extensionsService = wx.GetApp().GetService(ExtensionService)
|
||||
@@ -335,7 +330,7 @@ class ExtensionOptionsPanel(wx.Panel):
|
||||
self._currentItem = None
|
||||
self._currentItemIndex = -1
|
||||
return len(self._extensions)
|
||||
|
||||
|
||||
|
||||
def OnListBoxSelect(self, event=None):
|
||||
self.SaveCurrentItem()
|
||||
@@ -370,7 +365,7 @@ class ExtensionOptionsPanel(wx.Panel):
|
||||
else:
|
||||
extension.fileExt = fileExt.split(',')
|
||||
extension.opOnSelectedFile = self._selFileCtrl.GetValue()
|
||||
|
||||
|
||||
|
||||
def LoadItem(self, extension):
|
||||
if extension:
|
||||
@@ -401,8 +396,8 @@ class ExtensionOptionsPanel(wx.Panel):
|
||||
self._fileExtTextCtrl.SetValue('')
|
||||
self._selFileCtrl.SetValue(True)
|
||||
self._extDetailPanel.Enable(False)
|
||||
|
||||
|
||||
|
||||
|
||||
def OnAdd(self, event):
|
||||
self.SaveCurrentItem()
|
||||
name = _("Untitled")
|
||||
@@ -417,11 +412,11 @@ class ExtensionOptionsPanel(wx.Panel):
|
||||
self.OnListBoxSelect()
|
||||
self._menuItemNameTextCtrl.SetFocus()
|
||||
self._menuItemNameTextCtrl.SetSelection(-1, -1)
|
||||
|
||||
|
||||
|
||||
def OnDelete(self, event):
|
||||
self._extListBox.Delete(self._currentItemIndex)
|
||||
self._extensions.remove(self._currentItem)
|
||||
self._extensions.remove(self._currentItem)
|
||||
self._currentItemIndex = min(self._currentItemIndex, self._extListBox.GetCount() - 1)
|
||||
if self._currentItemIndex > -1:
|
||||
self._extListBox.SetSelection(self._currentItemIndex)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -119,7 +119,7 @@ class HtmlCtrl(CodeEditor.CodeCtrl):
|
||||
|
||||
|
||||
def SetViewDefaults(self):
|
||||
CodeEditor.CodeCtrl.SetViewDefaults(self, configPrefix = "Html", hasWordWrap = True, hasTabs = True)
|
||||
CodeEditor.CodeCtrl.SetViewDefaults(self, configPrefix = "Html", hasWordWrap = True, hasTabs = True, hasFolding=True)
|
||||
|
||||
|
||||
def GetFontAndColorFromConfig(self):
|
||||
@@ -156,7 +156,7 @@ class HtmlCtrl(CodeEditor.CodeCtrl):
|
||||
class HtmlOptionsPanel(STCTextEditor.TextOptionsPanel):
|
||||
|
||||
def __init__(self, parent, id):
|
||||
STCTextEditor.TextOptionsPanel.__init__(self, parent, id, configPrefix = "Html", label = "HTML", hasWordWrap = True, hasTabs = True)
|
||||
STCTextEditor.TextOptionsPanel.__init__(self, parent, id, configPrefix = "Html", label = "HTML", hasWordWrap = True, hasTabs = True, hasFolding=True)
|
||||
|
||||
|
||||
def GetIcon(self):
|
||||
|
||||
+1451
-1373
File diff suppressed because it is too large
Load Diff
@@ -36,16 +36,16 @@ class MarkerService(wx.lib.pydocview.DocService):
|
||||
|
||||
editMenu = menuBar.GetMenu(menuBar.FindMenu(_("&Edit")))
|
||||
editMenu.AppendSeparator()
|
||||
editMenu.Append(MarkerService.MARKERTOGGLE_ID, _("Toggle &Marker\tCtrl+M"), _("Toggles a jump marker to text line"))
|
||||
editMenu.Append(MarkerService.MARKERTOGGLE_ID, _("Toggle &Bookmark\tCtrl+M"), _("Toggles a bookmark at text line"))
|
||||
wx.EVT_MENU(frame, MarkerService.MARKERTOGGLE_ID, frame.ProcessEvent)
|
||||
wx.EVT_UPDATE_UI(frame, MarkerService.MARKERTOGGLE_ID, frame.ProcessUpdateUIEvent)
|
||||
editMenu.Append(MarkerService.MARKERDELALL_ID, _("Clear Markers"), _("Removes all jump markers from selected file"))
|
||||
editMenu.Append(MarkerService.MARKERDELALL_ID, _("Clear Bookmarks"), _("Removes all jump bookmarks from selected file"))
|
||||
wx.EVT_MENU(frame, MarkerService.MARKERDELALL_ID, frame.ProcessEvent)
|
||||
wx.EVT_UPDATE_UI(frame, MarkerService.MARKERDELALL_ID, frame.ProcessUpdateUIEvent)
|
||||
editMenu.Append(MarkerService.MARKERNEXT_ID, _("Marker Next\tF4"), _("Moves to next marker in selected file"))
|
||||
editMenu.Append(MarkerService.MARKERNEXT_ID, _("Bookmark Next\tF4"), _("Moves to next bookmark in selected file"))
|
||||
wx.EVT_MENU(frame, MarkerService.MARKERNEXT_ID, frame.ProcessEvent)
|
||||
wx.EVT_UPDATE_UI(frame, MarkerService.MARKERNEXT_ID, frame.ProcessUpdateUIEvent)
|
||||
editMenu.Append(MarkerService.MARKERPREV_ID, _("Marker Previous\tShift+F4"), _("Moves to previous marker in selected file"))
|
||||
editMenu.Append(MarkerService.MARKERPREV_ID, _("Bookmark Previous\tShift+F4"), _("Moves to previous bookmark in selected file"))
|
||||
wx.EVT_MENU(frame, MarkerService.MARKERPREV_ID, frame.ProcessEvent)
|
||||
wx.EVT_UPDATE_UI(frame, MarkerService.MARKERPREV_ID, frame.ProcessUpdateUIEvent)
|
||||
|
||||
|
||||
@@ -124,6 +124,7 @@ class MessageView(Service.ServiceView):
|
||||
|
||||
|
||||
def AddLines(self, text):
|
||||
self.GetControl().SetCurrentPos(self.GetControl().GetTextLength())
|
||||
self.GetControl().SetReadOnly(False)
|
||||
self.GetControl().AddText(text)
|
||||
self.GetControl().SetReadOnly(True)
|
||||
|
||||
@@ -147,7 +147,11 @@ class OutlineView(Service.ServiceView):
|
||||
return
|
||||
|
||||
treeCtrl = self.GetControl()
|
||||
|
||||
parentItem = treeCtrl.GetRootItem()
|
||||
if not parentItem:
|
||||
return
|
||||
|
||||
if expanded[0] != treeCtrl.GetItemText(parentItem):
|
||||
return
|
||||
|
||||
@@ -157,8 +161,7 @@ class OutlineView(Service.ServiceView):
|
||||
treeCtrl.Expand(child)
|
||||
(child, cookie) = treeCtrl.GetNextChild(parentItem, cookie)
|
||||
|
||||
if parentItem:
|
||||
treeCtrl.EnsureVisible(parentItem)
|
||||
treeCtrl.EnsureVisible(parentItem)
|
||||
|
||||
|
||||
class OutlineTreeCtrl(wx.TreeCtrl):
|
||||
@@ -267,7 +270,7 @@ class OutlineTreeCtrl(wx.TreeCtrl):
|
||||
|
||||
if self.ItemHasChildren(item):
|
||||
child, cookie = self.GetFirstChild(item)
|
||||
while child and child.IsOk():
|
||||
while child.IsOk():
|
||||
self.FindDistanceToTreeItems(child, position, distances, items)
|
||||
child, cookie = self.GetNextChild(item, cookie)
|
||||
return False
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,10 @@ import CodeEditor
|
||||
import OutlineService
|
||||
import os
|
||||
import re
|
||||
import FindInDirService
|
||||
import activegrid.util.appdirs as appdirs
|
||||
import activegrid.util.sysutils as sysutils
|
||||
_ = wx.GetTranslation
|
||||
|
||||
|
||||
class PHPDocument(CodeEditor.CodeDocument):
|
||||
@@ -153,18 +157,52 @@ class PHPCtrl(CodeEditor.CodeCtrl):
|
||||
|
||||
def __init__(self, parent, id=-1, style=wx.NO_FULL_REPAINT_ON_RESIZE):
|
||||
CodeEditor.CodeCtrl.__init__(self, parent, id, style)
|
||||
self.SetLexer(wx.stc.STC_LEX_PHP)
|
||||
self.SetLexer(wx.stc.STC_LEX_HTML)
|
||||
self.SetStyleBits(7)
|
||||
self.SetKeyWords(4, string.join(PHPKEYWORDS))
|
||||
self.SetProperty("fold.html", "1")
|
||||
|
||||
|
||||
def CreatePopupMenu(self):
|
||||
FINDCLASS_ID = wx.NewId()
|
||||
FINDDEF_ID = wx.NewId()
|
||||
|
||||
menu = CodeEditor.CodeCtrl.CreatePopupMenu(self)
|
||||
|
||||
self.Bind(wx.EVT_MENU, self.OnPopFindDefinition, id=FINDDEF_ID)
|
||||
menu.Insert(1, FINDDEF_ID, _("Find 'function'"))
|
||||
|
||||
self.Bind(wx.EVT_MENU, self.OnPopFindClass, id=FINDCLASS_ID)
|
||||
menu.Insert(2, FINDCLASS_ID, _("Find 'class'"))
|
||||
|
||||
return menu
|
||||
|
||||
|
||||
def OnPopFindDefinition(self, event):
|
||||
view = wx.GetApp().GetDocumentManager().GetCurrentView()
|
||||
if hasattr(view, "GetCtrl") and view.GetCtrl() and hasattr(view.GetCtrl(), "GetSelectedText"):
|
||||
pattern = view.GetCtrl().GetSelectedText().strip()
|
||||
if pattern:
|
||||
searchPattern = "function\s+%s" % pattern
|
||||
wx.GetApp().GetService(FindInDirService.FindInDirService).FindInProject(searchPattern)
|
||||
|
||||
|
||||
def OnPopFindClass(self, event):
|
||||
view = wx.GetApp().GetDocumentManager().GetCurrentView()
|
||||
if hasattr(view, "GetCtrl") and view.GetCtrl() and hasattr(view.GetCtrl(), "GetSelectedText"):
|
||||
definition = "class\s+%s"
|
||||
pattern = view.GetCtrl().GetSelectedText().strip()
|
||||
if pattern:
|
||||
searchPattern = definition % pattern
|
||||
wx.GetApp().GetService(FindInDirService.FindInDirService).FindInProject(searchPattern)
|
||||
|
||||
|
||||
def CanWordWrap(self):
|
||||
return True
|
||||
|
||||
|
||||
def SetViewDefaults(self):
|
||||
CodeEditor.CodeCtrl.SetViewDefaults(self, configPrefix = "PHP", hasWordWrap = True, hasTabs = True)
|
||||
CodeEditor.CodeCtrl.SetViewDefaults(self, configPrefix = "PHP", hasWordWrap = True, hasTabs = True, hasFolding=True)
|
||||
|
||||
|
||||
def GetFontAndColorFromConfig(self):
|
||||
@@ -216,8 +254,110 @@ class PHPCtrl(CodeEditor.CodeCtrl):
|
||||
class PHPOptionsPanel(STCTextEditor.TextOptionsPanel):
|
||||
|
||||
def __init__(self, parent, id):
|
||||
STCTextEditor.TextOptionsPanel.__init__(self, parent, id, configPrefix = "PHP", label = "PHP", hasWordWrap = True, hasTabs = True)
|
||||
wx.Panel.__init__(self, parent, id)
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
config = wx.ConfigBase_Get()
|
||||
|
||||
pathLabel = wx.StaticText(self, -1, _("PHP Executable Path:"))
|
||||
path = config.Read("ActiveGridPHPLocation")
|
||||
self._pathTextCtrl = wx.TextCtrl(self, -1, path, size = (150, -1))
|
||||
self._pathTextCtrl.SetToolTipString(self._pathTextCtrl.GetValue())
|
||||
self._pathTextCtrl.SetInsertionPointEnd()
|
||||
choosePathButton = wx.Button(self, -1, _("Browse..."))
|
||||
pathSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
HALF_SPACE = 5
|
||||
SPACE = 10
|
||||
pathSizer.Add(pathLabel, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.TOP, HALF_SPACE)
|
||||
pathSizer.Add(self._pathTextCtrl, 1, wx.EXPAND|wx.LEFT|wx.TOP, HALF_SPACE)
|
||||
pathSizer.Add(choosePathButton, 0, wx.ALIGN_RIGHT|wx.LEFT|wx.RIGHT|wx.TOP, HALF_SPACE)
|
||||
wx.EVT_BUTTON(self, choosePathButton.GetId(), self.OnChoosePath)
|
||||
mainSizer.Add(pathSizer, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, SPACE)
|
||||
|
||||
iniLabel = wx.StaticText(self, -1, _("php.ini Path:"))
|
||||
ini = config.Read("ActiveGridPHPINILocation")
|
||||
if not ini:
|
||||
if sysutils.isRelease():
|
||||
ini = os.path.normpath(os.path.join(appdirs.getSystemDir(), "php.ini"))
|
||||
else:
|
||||
tmp = self._pathTextCtrl.GetValue().strip()
|
||||
if tmp and len(tmp) > 0:
|
||||
ini = os.path.normpath(os.path.join(os.path.dirname(tmp), "php.ini"))
|
||||
|
||||
self._iniTextCtrl = wx.TextCtrl(self, -1, ini, size = (150, -1))
|
||||
self._iniTextCtrl.SetToolTipString(self._iniTextCtrl.GetValue())
|
||||
self._iniTextCtrl.SetInsertionPointEnd()
|
||||
chooseIniButton = wx.Button(self, -1, _("Browse..."))
|
||||
iniSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
HALF_SPACE = 5
|
||||
SPACE = 10
|
||||
iniSizer.Add(iniLabel, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.TOP, HALF_SPACE)
|
||||
iniSizer.Add(self._iniTextCtrl, 1, wx.EXPAND|wx.LEFT|wx.TOP, HALF_SPACE)
|
||||
iniSizer.Add(chooseIniButton, 0, wx.ALIGN_RIGHT|wx.LEFT|wx.RIGHT|wx.TOP, HALF_SPACE)
|
||||
wx.EVT_BUTTON(self, chooseIniButton.GetId(), self.OnChooseIni)
|
||||
mainSizer.Add(iniSizer, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, SPACE)
|
||||
|
||||
self._otherOptions = STCTextEditor.TextOptionsPanel(self, -1, configPrefix = "PHP", label = "PHP", hasWordWrap = True, hasTabs = True, addPage=False, hasFolding=False)
|
||||
#STCTextEditor.TextOptionsPanel.__init__(self, parent, id, configPrefix = "PHP", label = "PHP", hasWordWrap = True, hasTabs = True)
|
||||
mainSizer.Add(self._otherOptions, 0, wx.EXPAND|wx.BOTTOM, SPACE)
|
||||
|
||||
self.SetSizer(mainSizer)
|
||||
parent.AddPage(self, _("PHP"))
|
||||
|
||||
def OnChoosePath(self, event):
|
||||
defaultDir = os.path.dirname(self._pathTextCtrl.GetValue().strip())
|
||||
defaultFile = os.path.basename(self._pathTextCtrl.GetValue().strip())
|
||||
if wx.Platform == '__WXMSW__':
|
||||
wildcard = _("Executable (*.exe)|*.exe|All|*.*")
|
||||
if not defaultFile:
|
||||
defaultFile = "php-cgi.exe"
|
||||
else:
|
||||
wildcard = _("*")
|
||||
dlg = wx.FileDialog(wx.GetApp().GetTopWindow(),
|
||||
_("Select a File"),
|
||||
defaultDir=defaultDir,
|
||||
defaultFile=defaultFile,
|
||||
wildcard=wildcard,
|
||||
style=wx.OPEN|wx.FILE_MUST_EXIST|wx.HIDE_READONLY)
|
||||
# dlg.CenterOnParent() # wxBug: caused crash with wx.FileDialog
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
path = dlg.GetPath()
|
||||
if path:
|
||||
self._pathTextCtrl.SetValue(path)
|
||||
self._pathTextCtrl.SetToolTipString(self._pathTextCtrl.GetValue())
|
||||
self._pathTextCtrl.SetInsertionPointEnd()
|
||||
dlg.Destroy()
|
||||
|
||||
def OnChooseIni(self, event):
|
||||
defaultDir = os.path.dirname(self._iniTextCtrl.GetValue().strip())
|
||||
defaultFile = os.path.basename(self._iniTextCtrl.GetValue().strip())
|
||||
if wx.Platform == '__WXMSW__':
|
||||
wildcard = _("Ini (*.ini)|*.ini|All|*.*")
|
||||
if not defaultFile:
|
||||
defaultFile = "php.ini"
|
||||
else:
|
||||
wildcard = _("*")
|
||||
dlg = wx.FileDialog(wx.GetApp().GetTopWindow(),
|
||||
_("Select a File"),
|
||||
defaultDir=defaultDir,
|
||||
defaultFile=defaultFile,
|
||||
wildcard=wildcard,
|
||||
style=wx.OPEN|wx.FILE_MUST_EXIST|wx.HIDE_READONLY)
|
||||
# dlg.CenterOnParent() # wxBug: caused crash with wx.FileDialog
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
ini = dlg.GetPath()
|
||||
if ini:
|
||||
self._iniTextCtrl.SetValue(ini)
|
||||
self._iniTextCtrl.SetToolTipString(self._iniTextCtrl.GetValue())
|
||||
self._iniTextCtrl.SetInsertionPointEnd()
|
||||
dlg.Destroy()
|
||||
|
||||
def OnOK(self, optionsDialog):
|
||||
config = wx.ConfigBase_Get()
|
||||
config.Write("ActiveGridPHPLocation", self._pathTextCtrl.GetValue().strip())
|
||||
config.Write("ActiveGridPHPINILocation", self._iniTextCtrl.GetValue().strip())
|
||||
|
||||
self._otherOptions.OnOK(optionsDialog)
|
||||
|
||||
def GetIcon(self):
|
||||
return getPHPIcon()
|
||||
|
||||
@@ -73,7 +73,7 @@ class PerlCtrl(CodeEditor.CodeCtrl):
|
||||
|
||||
|
||||
def SetViewDefaults(self):
|
||||
CodeEditor.CodeCtrl.SetViewDefaults(self, configPrefix = "Perl", hasWordWrap = True, hasTabs = True)
|
||||
CodeEditor.CodeCtrl.SetViewDefaults(self, configPrefix = "Perl", hasWordWrap = True, hasTabs = True, hasFolding=True)
|
||||
|
||||
|
||||
def GetFontAndColorFromConfig(self):
|
||||
@@ -130,7 +130,7 @@ class PerlCtrl(CodeEditor.CodeCtrl):
|
||||
class PerlOptionsPanel(STCTextEditor.TextOptionsPanel):
|
||||
|
||||
def __init__(self, parent, id):
|
||||
STCTextEditor.TextOptionsPanel.__init__(self, parent, id, configPrefix = "Perl", label = "Perl", hasWordWrap = True, hasTabs = True)
|
||||
STCTextEditor.TextOptionsPanel.__init__(self, parent, id, configPrefix = "Perl", label = "Perl", hasWordWrap = True, hasTabs = True, hasFolding=True)
|
||||
|
||||
|
||||
def GetIcon(self):
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -25,6 +25,7 @@ import keyword # for GetAutoCompleteKeywordList
|
||||
import sys # for GetAutoCompleteKeywordList
|
||||
import MessageService # for OnCheckCode
|
||||
import OutlineService
|
||||
import FindInDirService
|
||||
from UICommon import CaseInsensitiveCompare
|
||||
try:
|
||||
import checker # for pychecker
|
||||
@@ -143,11 +144,13 @@ class PythonView(CodeEditor.CodeView):
|
||||
# Set cursor to Wait cursor
|
||||
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
|
||||
|
||||
# This takes a while for involved code
|
||||
checker.checkSyntax(self.GetDocument().GetFilename(), view)
|
||||
try:
|
||||
# This takes a while for involved code
|
||||
checker.checkSyntax(self.GetDocument().GetFilename(), view)
|
||||
|
||||
# Set cursor to Default cursor
|
||||
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
|
||||
finally:
|
||||
# Set cursor to Default cursor
|
||||
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
|
||||
|
||||
|
||||
def OnJumpToFoundLine(self, event):
|
||||
@@ -369,8 +372,42 @@ class PythonCtrl(CodeEditor.CodeCtrl):
|
||||
self.SetKeyWords(0, string.join(keyword.kwlist))
|
||||
|
||||
|
||||
def CreatePopupMenu(self):
|
||||
FINDCLASS_ID = wx.NewId()
|
||||
FINDDEF_ID = wx.NewId()
|
||||
|
||||
menu = CodeEditor.CodeCtrl.CreatePopupMenu(self)
|
||||
|
||||
self.Bind(wx.EVT_MENU, self.OnPopFindDefinition, id=FINDDEF_ID)
|
||||
menu.Insert(1, FINDDEF_ID, _("Find 'def'"))
|
||||
|
||||
self.Bind(wx.EVT_MENU, self.OnPopFindClass, id=FINDCLASS_ID)
|
||||
menu.Insert(2, FINDCLASS_ID, _("Find 'class'"))
|
||||
|
||||
return menu
|
||||
|
||||
|
||||
def OnPopFindDefinition(self, event):
|
||||
view = wx.GetApp().GetDocumentManager().GetCurrentView()
|
||||
if hasattr(view, "GetCtrl") and view.GetCtrl() and hasattr(view.GetCtrl(), "GetSelectedText"):
|
||||
pattern = view.GetCtrl().GetSelectedText().strip()
|
||||
if pattern:
|
||||
searchPattern = "def\s+%s" % pattern
|
||||
wx.GetApp().GetService(FindInDirService.FindInDirService).FindInProject(searchPattern)
|
||||
|
||||
|
||||
def OnPopFindClass(self, event):
|
||||
view = wx.GetApp().GetDocumentManager().GetCurrentView()
|
||||
if hasattr(view, "GetCtrl") and view.GetCtrl() and hasattr(view.GetCtrl(), "GetSelectedText"):
|
||||
definition = "class\s+%s"
|
||||
pattern = view.GetCtrl().GetSelectedText().strip()
|
||||
if pattern:
|
||||
searchPattern = definition % pattern
|
||||
wx.GetApp().GetService(FindInDirService.FindInDirService).FindInProject(searchPattern)
|
||||
|
||||
|
||||
def SetViewDefaults(self):
|
||||
CodeEditor.CodeCtrl.SetViewDefaults(self, configPrefix = "Python", hasWordWrap = True, hasTabs = True)
|
||||
CodeEditor.CodeCtrl.SetViewDefaults(self, configPrefix="Python", hasWordWrap=True, hasTabs=True, hasFolding=True)
|
||||
|
||||
|
||||
def GetFontAndColorFromConfig(self):
|
||||
@@ -567,7 +604,7 @@ class PythonOptionsPanel(wx.Panel):
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
mainSizer.Add(pathSizer, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, SPACE)
|
||||
|
||||
self._otherOptions = STCTextEditor.TextOptionsPanel(self, -1, configPrefix = "Python", label = "Python", hasWordWrap = True, hasTabs = True, addPage=False)
|
||||
self._otherOptions = STCTextEditor.TextOptionsPanel(self, -1, configPrefix = "Python", label = "Python", hasWordWrap = True, hasTabs = True, addPage=False, hasFolding=True)
|
||||
mainSizer.Add(self._otherOptions, 0, wx.EXPAND|wx.BOTTOM, SPACE)
|
||||
self.SetSizer(mainSizer)
|
||||
parent.AddPage(self, _("Python"))
|
||||
@@ -577,7 +614,7 @@ class PythonOptionsPanel(wx.Panel):
|
||||
defaultDir = os.path.dirname(self._pathTextCtrl.GetValue().strip())
|
||||
defaultFile = os.path.basename(self._pathTextCtrl.GetValue().strip())
|
||||
if _WINDOWS:
|
||||
wildcard = _("Executable (*.exe)|*.exe|All (*.*)|*.*")
|
||||
wildcard = _("Executable (*.exe)|*.exe|All|*.*")
|
||||
if not defaultFile:
|
||||
defaultFile = "python.exe"
|
||||
else:
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#
|
||||
# Created: 8/10/03
|
||||
# CVS-ID: $Id$
|
||||
# Copyright: (c) 2003-2005 ActiveGrid, Inc.
|
||||
# Copyright: (c) 2003-2006 ActiveGrid, Inc.
|
||||
# License: wxWindows License
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
@@ -47,9 +47,15 @@ TEXT_STATUS_BAR_ID = wx.NewId()
|
||||
class TextDocument(wx.lib.docview.Document):
|
||||
|
||||
|
||||
def __init__(self):
|
||||
wx.lib.docview.Document .__init__(self)
|
||||
self._inModify = False
|
||||
|
||||
|
||||
def SaveObject(self, fileObject):
|
||||
view = self.GetFirstView()
|
||||
fileObject.write(view.GetValue())
|
||||
view.SetModifyFalse()
|
||||
return True
|
||||
|
||||
|
||||
@@ -57,24 +63,31 @@ class TextDocument(wx.lib.docview.Document):
|
||||
view = self.GetFirstView()
|
||||
data = fileObject.read()
|
||||
view.SetValue(data)
|
||||
view.SetModifyFalse()
|
||||
return True
|
||||
|
||||
|
||||
def IsModified(self):
|
||||
view = self.GetFirstView()
|
||||
if view:
|
||||
return wx.lib.docview.Document.IsModified(self) or view.IsModified()
|
||||
else:
|
||||
return wx.lib.docview.Document.IsModified(self)
|
||||
return view.IsModified()
|
||||
return False
|
||||
|
||||
|
||||
def Modify(self, mod):
|
||||
def Modify(self, modify):
|
||||
if self._inModify:
|
||||
return
|
||||
self._inModify = True
|
||||
|
||||
view = self.GetFirstView()
|
||||
wx.lib.docview.Document.Modify(self, mod)
|
||||
if not mod and view:
|
||||
if not modify and view:
|
||||
view.SetModifyFalse()
|
||||
|
||||
wx.lib.docview.Document.Modify(self, modify) # this must called be after the SetModifyFalse call above.
|
||||
|
||||
self._inModify = False
|
||||
|
||||
|
||||
def OnCreateCommandProcessor(self):
|
||||
# Don't create a command processor, it has its own
|
||||
pass
|
||||
@@ -142,6 +155,8 @@ class TextView(wx.lib.docview.View):
|
||||
self._dynSash._view = self
|
||||
self._textEditor = self.GetCtrlClass()(self._dynSash, -1, style=wx.NO_BORDER)
|
||||
wx.EVT_LEFT_DOWN(self._textEditor, self.OnLeftClick)
|
||||
self._textEditor.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModify)
|
||||
|
||||
self._CreateSizer(frame)
|
||||
self.Activate()
|
||||
frame.Show(True)
|
||||
@@ -149,6 +164,10 @@ class TextView(wx.lib.docview.View):
|
||||
return True
|
||||
|
||||
|
||||
def OnModify(self, event):
|
||||
self.GetDocument().Modify(self._textEditor.GetModify())
|
||||
|
||||
|
||||
def _CreateSizer(self, frame):
|
||||
sizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
sizer.Add(self._dynSash, 1, wx.EXPAND)
|
||||
@@ -161,6 +180,9 @@ class TextView(wx.lib.docview.View):
|
||||
|
||||
|
||||
def OnUpdate(self, sender = None, hint = None):
|
||||
if wx.lib.docview.View.OnUpdate(self, sender, hint):
|
||||
return
|
||||
|
||||
if hint == "ViewStuff":
|
||||
self.GetCtrl().SetViewDefaults()
|
||||
elif hint == "Font":
|
||||
@@ -571,9 +593,11 @@ class TextView(wx.lib.docview.View):
|
||||
def EnsureVisible(self, line):
|
||||
self.GetCtrl().EnsureVisible(line-1) # line numbering for editor is 0 based, we are 1 based.
|
||||
|
||||
|
||||
def EnsureVisibleEnforcePolicy(self, line):
|
||||
self.GetCtrl().EnsureVisibleEnforcePolicy(line-1) # line numbering for editor is 0 based, we are 1 based.
|
||||
|
||||
|
||||
def LineFromPosition(self, pos):
|
||||
return self.GetCtrl().LineFromPosition(pos)+1 # line numbering for editor is 0 based, we are 1 based.
|
||||
|
||||
@@ -813,11 +837,12 @@ class TextStatusBar(wx.StatusBar):
|
||||
class TextOptionsPanel(wx.Panel):
|
||||
|
||||
|
||||
def __init__(self, parent, id, configPrefix = "Text", label = "Text", hasWordWrap = True, hasTabs = False, addPage=True):
|
||||
def __init__(self, parent, id, configPrefix = "Text", label = "Text", hasWordWrap = True, hasTabs = False, addPage=True, hasFolding=False):
|
||||
wx.Panel.__init__(self, parent, id)
|
||||
self._configPrefix = configPrefix
|
||||
self._hasWordWrap = hasWordWrap
|
||||
self._hasTabs = hasTabs
|
||||
self._hasFolding = hasFolding
|
||||
SPACE = 10
|
||||
HALF_SPACE = 5
|
||||
config = wx.ConfigBase_Get()
|
||||
@@ -854,6 +879,9 @@ class TextOptionsPanel(wx.Panel):
|
||||
self._viewRightEdgeCheckBox.SetValue(config.ReadInt(self._configPrefix + "EditorViewRightEdge", False))
|
||||
self._viewLineNumbersCheckBox = wx.CheckBox(self, -1, _("Show line numbers"))
|
||||
self._viewLineNumbersCheckBox.SetValue(config.ReadInt(self._configPrefix + "EditorViewLineNumbers", True))
|
||||
if self._hasFolding:
|
||||
self._viewFoldingCheckBox = wx.CheckBox(self, -1, _("Show folding"))
|
||||
self._viewFoldingCheckBox.SetValue(config.ReadInt(self._configPrefix + "EditorViewFolding", True))
|
||||
if self._hasTabs:
|
||||
self._hasTabsCheckBox = wx.CheckBox(self, -1, _("Use spaces instead of tabs"))
|
||||
self._hasTabsCheckBox.SetValue(not wx.ConfigBase_Get().ReadInt(self._configPrefix + "EditorUseTabs", False))
|
||||
@@ -874,6 +902,8 @@ class TextOptionsPanel(wx.Panel):
|
||||
textPanelSizer.Add(self._viewIndentationGuideCheckBox, 0, wx.ALL, HALF_SPACE)
|
||||
textPanelSizer.Add(self._viewRightEdgeCheckBox, 0, wx.ALL, HALF_SPACE)
|
||||
textPanelSizer.Add(self._viewLineNumbersCheckBox, 0, wx.ALL, HALF_SPACE)
|
||||
if self._hasFolding:
|
||||
textPanelSizer.Add(self._viewFoldingCheckBox, 0, wx.ALL, HALF_SPACE)
|
||||
if self._hasTabs:
|
||||
textPanelSizer.Add(self._hasTabsCheckBox, 0, wx.ALL, HALF_SPACE)
|
||||
textIndentWidthSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
@@ -947,6 +977,9 @@ class TextOptionsPanel(wx.Panel):
|
||||
config.WriteInt(self._configPrefix + "EditorViewRightEdge", self._viewRightEdgeCheckBox.GetValue())
|
||||
doViewStuffUpdate = doViewStuffUpdate or config.ReadInt(self._configPrefix + "EditorViewLineNumbers", True) != self._viewLineNumbersCheckBox.GetValue()
|
||||
config.WriteInt(self._configPrefix + "EditorViewLineNumbers", self._viewLineNumbersCheckBox.GetValue())
|
||||
if self._hasFolding:
|
||||
doViewStuffUpdate = doViewStuffUpdate or config.ReadInt(self._configPrefix + "EditorViewFolding", True) != self._viewFoldingCheckBox.GetValue()
|
||||
config.WriteInt(self._configPrefix + "EditorViewFolding", self._viewFoldingCheckBox.GetValue())
|
||||
if self._hasWordWrap:
|
||||
doViewStuffUpdate = doViewStuffUpdate or config.ReadInt(self._configPrefix + "EditorWordWrap", False) != self._wordWrapCheckBox.GetValue()
|
||||
config.WriteInt(self._configPrefix + "EditorWordWrap", self._wordWrapCheckBox.GetValue())
|
||||
@@ -1062,13 +1095,15 @@ class TextCtrl(wx.stc.StyledTextCtrl):
|
||||
event.Skip()
|
||||
|
||||
|
||||
def SetViewDefaults(self, configPrefix = "Text", hasWordWrap = True, hasTabs = False):
|
||||
def SetViewDefaults(self, configPrefix="Text", hasWordWrap=True, hasTabs=False, hasFolding=False):
|
||||
config = wx.ConfigBase_Get()
|
||||
self.SetViewWhiteSpace(config.ReadInt(configPrefix + "EditorViewWhitespace", False))
|
||||
self.SetViewEOL(config.ReadInt(configPrefix + "EditorViewEOL", False))
|
||||
self.SetIndentationGuides(config.ReadInt(configPrefix + "EditorViewIndentationGuides", False))
|
||||
self.SetViewRightEdge(config.ReadInt(configPrefix + "EditorViewRightEdge", False))
|
||||
self.SetViewLineNumbers(config.ReadInt(configPrefix + "EditorViewLineNumbers", True))
|
||||
if hasFolding:
|
||||
self.SetViewFolding(config.ReadInt(configPrefix + "EditorViewFolding", True))
|
||||
if hasWordWrap:
|
||||
self.SetWordWrap(config.ReadInt(configPrefix + "EditorWordWrap", False))
|
||||
if hasTabs: # These methods do not exist in STCTextEditor and are meant for subclasses
|
||||
@@ -1237,6 +1272,17 @@ class TextCtrl(wx.stc.StyledTextCtrl):
|
||||
self.SetMarginWidth(1, 0)
|
||||
|
||||
|
||||
def GetViewFolding(self):
|
||||
return self.GetMarginWidth(2) > 0
|
||||
|
||||
|
||||
def SetViewFolding(self, viewFolding = True):
|
||||
if viewFolding:
|
||||
self.SetMarginWidth(2, 12)
|
||||
else:
|
||||
self.SetMarginWidth(2, 0)
|
||||
|
||||
|
||||
def CanWordWrap(self):
|
||||
return True
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@
|
||||
#
|
||||
# Created: 3/10/05
|
||||
# CVS-ID: $Id$
|
||||
# Copyright: (c) 2005 ActiveGrid, Inc.
|
||||
# Copyright: (c) 2005-2006 ActiveGrid, Inc.
|
||||
# License: wxWindows License
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
@@ -15,12 +15,14 @@ import os.path
|
||||
import wx
|
||||
import string
|
||||
import ProjectEditor
|
||||
import activegrid.util.sysutils as sysutils
|
||||
import activegrid.util.strutils as strutils
|
||||
import activegrid.util.appdirs as appdirs
|
||||
import activegrid.util.fileutils as fileutils
|
||||
import activegrid.util.strutils as strutils
|
||||
import activegrid.util.sysutils as sysutils
|
||||
import activegrid.util.xmlutils as xmlutils
|
||||
_ = wx.GetTranslation
|
||||
|
||||
def CreateDirectoryControl( parent, fileLabel=_("File Name:"), dirLabel=_("Directory"), fileExtension="*", startingName="", startingDirectory=None, choiceDirs=None, appDirDefaultStartDir=False, returnAll=False):
|
||||
def CreateDirectoryControl( parent, fileLabel=_("File Name:"), dirLabel=_("Directory:"), fileExtension="*", startingName="", startingDirectory=None, choiceDirs=None, appDirDefaultStartDir=False, returnAll=False, useDirDialog=False):
|
||||
|
||||
if not choiceDirs:
|
||||
choiceDirs = []
|
||||
@@ -61,8 +63,8 @@ def CreateDirectoryControl( parent, fileLabel=_("File Name:"), dirLabel=_("Direc
|
||||
|
||||
if os.getcwd() not in choiceDirs:
|
||||
choiceDirs.append(os.getcwd())
|
||||
if appdirs.documents_folder not in choiceDirs:
|
||||
choiceDirs.append(appdirs.documents_folder)
|
||||
if appdirs.getSystemDir() not in choiceDirs:
|
||||
choiceDirs.append(appdirs.getSystemDir())
|
||||
|
||||
if not startingDirectory:
|
||||
startingDirectory = os.getcwd()
|
||||
@@ -85,12 +87,18 @@ def CreateDirectoryControl( parent, fileLabel=_("File Name:"), dirLabel=_("Direc
|
||||
else:
|
||||
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(),
|
||||
defaultFile = name,
|
||||
wildcard= "*.%s" % fileExtension,
|
||||
style=wx.SAVE|wx.CHANGE_DIR)
|
||||
|
||||
else:
|
||||
dlg = wx.DirDialog(wx.GetApp().GetTopWindow(),
|
||||
_("Choose a directory:"),
|
||||
defaultPath=dirControl.GetValue().strip(),
|
||||
style=wx.DD_DEFAULT_STYLE|wx.DD_NEW_DIR_BUTTON)
|
||||
|
||||
if dlg.ShowModal() != wx.ID_OK:
|
||||
dlg.Destroy()
|
||||
return
|
||||
@@ -98,49 +106,78 @@ def CreateDirectoryControl( parent, fileLabel=_("File Name:"), dirLabel=_("Direc
|
||||
dlg.Destroy()
|
||||
|
||||
if path:
|
||||
dir, filename = os.path.split(path)
|
||||
if dirControl.FindString(dir) == wx.NOT_FOUND:
|
||||
dirControl.Insert(dir, 0)
|
||||
dirControl.SetValue(dir)
|
||||
dirControl.SetToolTipString(dir)
|
||||
nameControl.SetValue(filename)
|
||||
if not useDirDialog:
|
||||
dir, filename = os.path.split(path)
|
||||
if dirControl.FindString(dir) == wx.NOT_FOUND:
|
||||
dirControl.Insert(dir, 0)
|
||||
dirControl.SetValue(dir)
|
||||
dirControl.SetToolTipString(dir)
|
||||
nameControl.SetValue(filename)
|
||||
else:
|
||||
dirControl.SetValue(path)
|
||||
dirControl.SetToolTipString(path)
|
||||
|
||||
parent.Bind(wx.EVT_BUTTON, OnFindDirClick, button)
|
||||
|
||||
def Validate(allowOverwriteOnPrompt=False, infoString='', noFirstCharDigit=False):
|
||||
def Validate(allowOverwriteOnPrompt=False, infoString='', validClassName=False, ignoreFileConflicts=False):
|
||||
projName = nameControl.GetValue().strip()
|
||||
if projName == "":
|
||||
wx.MessageBox(_("Please provide a %sfile name.") % infoString, _("Provide a File Name"))
|
||||
return False
|
||||
if noFirstCharDigit and projName[0].isdigit():
|
||||
wx.MessageBox(_("File name cannot start with a number. Please enter a different name."), _("Invalid File Name"))
|
||||
return False
|
||||
if projName.find(' ') != -1:
|
||||
wx.MessageBox(_("Please provide a %sfile name that does not contains spaces.") % infoString, _("Spaces in File Name"))
|
||||
return False
|
||||
if not os.path.exists(dirControl.GetValue()):
|
||||
wx.MessageBox(_("That %sdirectory does not exist. Please choose an existing directory.") % infoString, _("Provide a Valid Directory"))
|
||||
if validClassName:
|
||||
if projName[0].isdigit():
|
||||
wx.MessageBox(_("File name cannot start with a number. Please enter a different name."), _("Invalid File Name"))
|
||||
return False
|
||||
if projName.endswith(".agp"):
|
||||
projName2 = projName[:-4]
|
||||
else:
|
||||
projName2 = projName
|
||||
if not projName2.replace("_", "a").isalnum(): # [a-zA-Z0-9_] note '_' is allowed and ending '.agp'.
|
||||
wx.MessageBox(_("Name must be alphanumeric ('_' allowed). Please enter a valid name."), _("Project Name"))
|
||||
return False
|
||||
|
||||
dirName = dirControl.GetValue().strip()
|
||||
if dirName == "":
|
||||
wx.MessageBox(_("No directory. Please provide a directory."), _("Provide a Directory"))
|
||||
return False
|
||||
|
||||
filePath = os.path.join(dirControl.GetValue(), MakeNameEndInExtension(projName, "." + fileExtension))
|
||||
if os.path.exists(filePath):
|
||||
if allowOverwriteOnPrompt:
|
||||
res = wx.MessageBox(_("That %sfile already exists. Would you like to overwrite it.") % infoString, "File Exists", style=wx.YES_NO|wx.NO_DEFAULT)
|
||||
return (res == wx.YES)
|
||||
else:
|
||||
wx.MessageBox(_("That %sfile already exists. Please choose a different name.") % infoString, "File Exists")
|
||||
return False
|
||||
if os.sep == "\\" and dirName.find("/") != -1:
|
||||
wx.MessageBox(_("Wrong delimiter '/' found in directory path. Use '%s' as delimiter.") % os.sep, _("Provide a Valid Directory"))
|
||||
return False
|
||||
if not os.path.exists(dirName):
|
||||
wx.MessageBox(_("That %sdirectory does not exist. Please choose an existing directory.") % infoString, _("Provide a Valid Directory"))
|
||||
return False
|
||||
if not ignoreFileConflicts:
|
||||
filePath = os.path.join(dirName, MakeNameEndInExtension(projName, "." + fileExtension))
|
||||
if os.path.exists(filePath):
|
||||
if allowOverwriteOnPrompt:
|
||||
res = wx.MessageBox(_("That %sfile already exists. Would you like to overwrite it.") % infoString, "File Exists", style=wx.YES_NO|wx.NO_DEFAULT)
|
||||
return (res == wx.YES)
|
||||
else:
|
||||
wx.MessageBox(_("That %sfile already exists. Please choose a different name.") % infoString, "File Exists")
|
||||
return False
|
||||
|
||||
return True
|
||||
HALF_SPACE = 5
|
||||
flexGridSizer = wx.FlexGridSizer(cols = 3, vgap = HALF_SPACE, hgap = HALF_SPACE)
|
||||
flexGridSizer.AddGrowableCol(1,1)
|
||||
flexGridSizer.Add(nameLabelText, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)
|
||||
flexGridSizer.Add(nameControl, 2, flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
|
||||
flexGridSizer.Add(button, flag=wx.ALIGN_RIGHT|wx.LEFT, border=HALF_SPACE)
|
||||
if not useDirDialog:
|
||||
flexGridSizer.Add(nameLabelText, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)
|
||||
flexGridSizer.Add(nameControl, 2, flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
|
||||
flexGridSizer.Add(button, flag=wx.ALIGN_RIGHT|wx.LEFT, border=HALF_SPACE)
|
||||
flexGridSizer.Add(dirLabelText, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)
|
||||
flexGridSizer.Add(dirControl, 2, flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
|
||||
flexGridSizer.Add(wx.StaticText(parent, -1, ""), 0)
|
||||
else:
|
||||
flexGridSizer.Add(nameLabelText, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)
|
||||
flexGridSizer.Add(nameControl, 2, flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
|
||||
flexGridSizer.Add(wx.StaticText(parent, -1, ""), 0)
|
||||
flexGridSizer.Add(dirLabelText, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)
|
||||
flexGridSizer.Add(dirControl, 2, flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
|
||||
flexGridSizer.Add(button, flag=wx.ALIGN_RIGHT|wx.LEFT, border=HALF_SPACE)
|
||||
|
||||
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:
|
||||
return nameControl, dirControl, flexGridSizer, Validate, allControls
|
||||
else:
|
||||
@@ -188,8 +225,8 @@ def CreateDirectoryOnlyControl( parent, dirLabel=_("Location:"), startingDirecto
|
||||
|
||||
if os.getcwd() not in choiceDirs:
|
||||
choiceDirs.append(os.getcwd())
|
||||
if appdirs.documents_folder not in choiceDirs:
|
||||
choiceDirs.append(appdirs.documents_folder)
|
||||
if appdirs.getSystemDir() not in choiceDirs:
|
||||
choiceDirs.append(appdirs.getSystemDir())
|
||||
|
||||
|
||||
if not startingDirectory:
|
||||
@@ -221,6 +258,9 @@ def CreateDirectoryOnlyControl( parent, dirLabel=_("Location:"), startingDirecto
|
||||
if dirName == "":
|
||||
wx.MessageBox(_("Please provide a directory."), _("Provide a Directory"))
|
||||
return False
|
||||
if os.sep == "\\" and dirName.find("/") != -1:
|
||||
wx.MessageBox(_("Wrong delimiter '/' found in directory path. Use '%s' as delimiter.") % os.sep, _("Provide a Valid Directory"))
|
||||
return False
|
||||
if not os.path.exists(dirName):
|
||||
wx.MessageBox(_("That directory does not exist. Please choose an existing directory."), _("Provide a Valid Directory"))
|
||||
return False
|
||||
@@ -241,17 +281,25 @@ def CreateNameOnlyControl( parent, fileLabel, startingName="", startingDirectory
|
||||
fileLabelText = wx.StaticText(parent, -1, fileLabel)
|
||||
nameControl = wx.TextCtrl(parent, -1, startingName, size=(-1,-1))
|
||||
|
||||
def Validate(allowOverwriteOnPrompt=False, noFirstCharDigit=False):
|
||||
def Validate(allowOverwriteOnPrompt=False, validClassName=False):
|
||||
projName = nameControl.GetValue().strip()
|
||||
if projName == "":
|
||||
wx.MessageBox(_("Blank name. Please enter a valid name."), _("Project Name"))
|
||||
return False
|
||||
if noFirstCharDigit and projName[0].isdigit():
|
||||
wx.MessageBox(_("Name cannot start with a number. Please enter a valid name."), _("Project Name"))
|
||||
return False
|
||||
if projName.find(' ') != -1:
|
||||
wx.MessageBox(_("Spaces in name. Name cannot have spaces.") % infoString, _("Project Name"))
|
||||
wx.MessageBox(_("Spaces in name. Name cannot have spaces."), _("Project Name"))
|
||||
return False
|
||||
if validClassName:
|
||||
if projName[0].isdigit():
|
||||
wx.MessageBox(_("Name cannot start with a number. Please enter a valid name."), _("Project Name"))
|
||||
return False
|
||||
if projName.endswith(".agp"):
|
||||
projName2 = projName[:-4]
|
||||
else:
|
||||
projName2 = projName
|
||||
if not projName2.replace("_", "a").isalnum(): # [a-zA-Z0-9_] note '_' is allowed and ending '.agp'.
|
||||
wx.MessageBox(_("Name must be alphanumeric ('_' allowed). Please enter a valid name."), _("Project Name"))
|
||||
return False
|
||||
path = os.path.join(startingDirectoryControl.GetValue().strip(), projName)
|
||||
if os.path.exists(path):
|
||||
if os.path.isdir(path):
|
||||
@@ -280,6 +328,29 @@ def CreateNameOnlyControl( parent, fileLabel, startingName="", startingDirectory
|
||||
return nameControl, flexGridSizer, Validate
|
||||
|
||||
|
||||
def ValidateName(name, ext=None, hint="name"):
|
||||
""" Returns an error string if there is something wrong with the name.
|
||||
Otherwise it returns None
|
||||
"""
|
||||
if name == "":
|
||||
return _("Blank %s. Please enter a valid %s.") % (hint, hint)
|
||||
|
||||
if name.find(' ') != -1:
|
||||
return _("Spaces in %s. %s cannot have spaces.") % (hint, hint.title())
|
||||
|
||||
if name[0].isdigit():
|
||||
return _("%s cannot start with a number. Please enter a valid %s.") % (hint.title(), hint)
|
||||
|
||||
if ext and name.endswith(ext): # strip extension if provided
|
||||
lenExt = len(ext)
|
||||
name = name[:-lenExt]
|
||||
|
||||
if not name.replace("_", "a").isalnum(): # [a-zA-Z0-9_] note '_' is allowed and ext ending.
|
||||
return _("%s must be alphanumeric ('_' allowed). Please enter a valid %s.") % (hint.title(), hint)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def GetCurrentProject():
|
||||
projectDocument = None
|
||||
projectService = wx.GetApp().GetService(ProjectEditor.ProjectService)
|
||||
@@ -330,6 +401,16 @@ def GetPythonExecPath():
|
||||
return pythonExecPath
|
||||
|
||||
|
||||
def GetPHPExecPath():
|
||||
PHPExecPath = wx.ConfigBase_Get().Read("ActiveGridPHPLocation")
|
||||
return PHPExecPath
|
||||
|
||||
|
||||
def GetPHPINIPath():
|
||||
PHPINIPath = wx.ConfigBase_Get().Read("ActiveGridPHPINILocation")
|
||||
return PHPINIPath
|
||||
|
||||
|
||||
def _DoRemoveRecursive(path, skipFile=None, skipped=False):
|
||||
if path == skipFile:
|
||||
skipped = True
|
||||
@@ -362,16 +443,62 @@ def CaseInsensitiveCompare(s1, s2):
|
||||
|
||||
def GetAnnotation(model, elementName):
|
||||
""" Get an object's annotation used for tooltips """
|
||||
if hasattr(model, "__xsdcomplextype__"):
|
||||
if hasattr(model, "_complexType"):
|
||||
ct = model._complexType
|
||||
elif hasattr(model, "__xsdcomplextype__"):
|
||||
ct = model.__xsdcomplextype__
|
||||
if ct:
|
||||
el = ct.findElement(elementName)
|
||||
if el and el.annotation:
|
||||
return el.annotation
|
||||
else:
|
||||
ct = None
|
||||
|
||||
if ct:
|
||||
el = ct.findElement(elementName)
|
||||
if el and el.annotation:
|
||||
return el.annotation
|
||||
|
||||
return ""
|
||||
|
||||
|
||||
def GetDisplayName(doc, name):
|
||||
if name:
|
||||
appDocMgr = doc.GetAppDocMgr()
|
||||
if appDocMgr:
|
||||
name = appDocMgr.toDisplayTypeName(name)
|
||||
else:
|
||||
namespace, name = xmlutils.splitType(name)
|
||||
if namespace and hasattr(doc.GetModel(), "getXmlNamespaces"):
|
||||
for xmlkey, xmlval in doc.GetModel().getXmlNamespaces().iteritems():
|
||||
if xmlval == namespace:
|
||||
name = "%s:%s" % (xmlkey, name)
|
||||
break
|
||||
|
||||
if name:
|
||||
import activegrid.model.schema as schemalib
|
||||
baseTypeName = schemalib.mapXsdType(name)
|
||||
if baseTypeName:
|
||||
name = baseTypeName
|
||||
|
||||
return name
|
||||
|
||||
|
||||
def GetInternalName(doc, name):
|
||||
if name:
|
||||
appDocMgr = doc.GetAppDocMgr()
|
||||
if appDocMgr:
|
||||
name = appDocMgr.toInternalTypeName(name)
|
||||
else:
|
||||
namespace, name = xmlutils.splitType(name)
|
||||
if namespace and hasattr(doc.GetModel(), "getXmlNamespaces"):
|
||||
for xmlkey, xmlval in doc.GetModel().getXmlNamespaces().iteritems():
|
||||
if xmlkey == namespace:
|
||||
name = "%s:%s" % (xmlval, name)
|
||||
break
|
||||
|
||||
import activegrid.model.schema as schemalib
|
||||
name = schemalib.mapAGType(name)
|
||||
|
||||
return name
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Methods for finding application level info
|
||||
#----------------------------------------------------------------------------
|
||||
@@ -435,7 +562,8 @@ def GetAppDocMgrForDoc(doc):
|
||||
|
||||
|
||||
def GetAppInfoLanguage(doc=None):
|
||||
from activegrid.server.deployment import LANGUAGE_DEFAULT
|
||||
from activegrid.server.projectmodel import LANGUAGE_DEFAULT
|
||||
|
||||
if doc:
|
||||
language = doc.GetAppInfo().language
|
||||
else:
|
||||
@@ -449,3 +577,159 @@ def GetAppInfoLanguage(doc=None):
|
||||
doc.GetAppInfo().language = language # once it is selected, it must be set.
|
||||
|
||||
return language
|
||||
|
||||
def AddWsdlAgToProjectFromWsdlRegistration(wsdlRegistration):
|
||||
"""Add wsdl ag for registry entry."""
|
||||
|
||||
wsdlPath = wsdlRegistration.path
|
||||
rootPath = None
|
||||
serviceRefName = wsdlRegistration.name
|
||||
|
||||
agwsDoc = _InitWsdlAg(wsdlPath, rootPath, serviceRefName)
|
||||
|
||||
if (agwsDoc == None):
|
||||
return
|
||||
|
||||
serviceRef = agwsDoc.GetModel()
|
||||
|
||||
serviceRef.serviceType = wsdlRegistration.type
|
||||
|
||||
import activegrid.server.deployment as deployment
|
||||
|
||||
if (serviceRef.serviceType == deployment.SERVICE_LOCAL):
|
||||
serviceRef.localService = deployment.LocalService(
|
||||
wsdlRegistration.codeFile)
|
||||
|
||||
elif (serviceRef.serviceType == deployment.SERVICE_DATABASE):
|
||||
serviceRef.databaseService = deployment.DatabaseService(
|
||||
wsdlRegistration.datasourceName)
|
||||
|
||||
elif (serviceRef.serviceType == deployment.SERVICE_SOAP):
|
||||
pass
|
||||
|
||||
elif (serviceRef.serviceType == deployment.SERVICE_RSS):
|
||||
serviceRef.rssService = deployment.RssService(wsdlRegistration.feedUrl)
|
||||
|
||||
elif (serviceRef.serviceType == deployment.SERVICE_REST):
|
||||
serviceRef.restService = deployment.RestService(
|
||||
wsdlRegistration.baseUrl)
|
||||
else:
|
||||
raise AssertionError("Unknown service type")
|
||||
|
||||
_AddToProject(agwsDoc, addWsdl=True)
|
||||
|
||||
|
||||
def AddWsdlAgToProject(wsdlPath, rootPath=fileutils.AG_SYSTEM_STATIC_VAR_REF,
|
||||
serviceRefName=None, className=None, serviceType=None,
|
||||
dataSourceName=None):
|
||||
"""
|
||||
wsdlPath: path to wsdl from rootPath. If wsdlPath is absolute, rootPath
|
||||
is ignored. rootPath is also ignored when rootPath is set to None.
|
||||
rootPath: defaults to ${AG_SYSTEM_STATIC}.
|
||||
serviceRefName: If None, it will be set to the wsdl file name without
|
||||
the .wsdl file extension.
|
||||
className: if not None, will be used for the the wsdlag's ClassName.
|
||||
serviceType: defaults to local.
|
||||
dataSourceName: if serviceType is deployment.DATABASE, the ds must be
|
||||
provided.
|
||||
"""
|
||||
import WsdlAgEditor
|
||||
import XFormWizard
|
||||
import activegrid.model.basedocmgr as basedocmgr
|
||||
import activegrid.server.deployment as deployment
|
||||
|
||||
if (serviceType == None):
|
||||
serviceType = deployment.SERVICE_LOCAL
|
||||
|
||||
|
||||
agwsDoc = _InitWsdlAg(wsdlPath, rootPath, serviceRefName)
|
||||
|
||||
if (agwsDoc == None):
|
||||
return
|
||||
|
||||
serviceRef = agwsDoc.GetModel()
|
||||
|
||||
serviceRef.serviceType = serviceType
|
||||
|
||||
if (serviceType == deployment.SERVICE_DATABASE and dataSourceName != None):
|
||||
serviceRef.databaseService = deployment.DatabaseService(dataSourceName)
|
||||
else:
|
||||
serviceRef.localService = deployment.LocalService(className=className)
|
||||
|
||||
_AddToProject(agwsDoc)
|
||||
|
||||
|
||||
def _AddToProject(agwsDoc, addWsdl=False):
|
||||
import activegrid.model.basedocmgr as basedocmgr
|
||||
projectDoc = GetCurrentProject()
|
||||
agwsDoc.OnSaveDocument(agwsDoc.GetFilename())
|
||||
|
||||
files = [agwsDoc.fileName]
|
||||
types = [basedocmgr.FILE_TYPE_SERVICE]
|
||||
names = [agwsDoc.GetModel().name]
|
||||
if (addWsdl):
|
||||
m = agwsDoc.GetModel()
|
||||
wsdlName = os.path.splitext(os.path.basename(m.filePath))[0]
|
||||
appDocMgr = projectDoc.GetAppDocMgr()
|
||||
if (appDocMgr.findService(wsdlName) == None):
|
||||
m = agwsDoc.GetModel()
|
||||
files.append(m.filePath)
|
||||
types.append(None)
|
||||
names.append(wsdlName)
|
||||
|
||||
ProjectEditor.ProjectAddFilesCommand(projectDoc, files, types=types,
|
||||
names=names).Do()
|
||||
|
||||
|
||||
def _InitWsdlAg(wsdlPath, rootPath=fileutils.AG_SYSTEM_STATIC_VAR_REF,
|
||||
serviceRefName=None):
|
||||
|
||||
projectDoc = GetCurrentProject()
|
||||
appDocMgr = projectDoc.GetAppDocMgr()
|
||||
|
||||
if (serviceRefName == None):
|
||||
serviceRefName = os.path.splitext(os.path.basename(wsdlPath))[0]
|
||||
|
||||
if (appDocMgr.findServiceRef(serviceRefName) != None):
|
||||
return None
|
||||
|
||||
import WsdlAgEditor
|
||||
import XFormWizard
|
||||
import activegrid.server.deployment as deployment
|
||||
|
||||
template = XFormWizard.GetTemplate(WsdlAgEditor.WsdlAgDocument)
|
||||
ext = template.GetDefaultExtension()
|
||||
fullPath = os.path.join(appDocMgr.homeDir, serviceRefName + ext)
|
||||
|
||||
agwsDoc = template.CreateDocument(
|
||||
fullPath, flags=(wx.lib.docview.DOC_NO_VIEW|wx.lib.docview.DOC_NEW|
|
||||
wx.lib.docview.DOC_OPEN_ONCE))
|
||||
|
||||
serviceRef = agwsDoc.GetModel()
|
||||
serviceRef.name = serviceRefName
|
||||
|
||||
if (rootPath == None or os.path.isabs(wsdlPath)):
|
||||
serviceRef.filePath = wsdlPath
|
||||
else:
|
||||
# make sure to use forward slashes for the path to the .wsdl
|
||||
wsdlPath = wsdlPath.replace("\\", "/")
|
||||
|
||||
if not wsdlPath.startswith("/"):
|
||||
wsdlPath = "/%s" % wsdlPath
|
||||
serviceRef.filePath = "%s%s" % (rootPath, wsdlPath)
|
||||
|
||||
agwsDoc.fileName = fullPath
|
||||
|
||||
return agwsDoc
|
||||
|
||||
|
||||
def GetSchemaName(schema):
|
||||
return os.path.basename(schema.fileName)
|
||||
|
||||
|
||||
class AGChoice(wx.Choice):
|
||||
"""Extension to wx.Choice that fixes linux bug where first item of choices
|
||||
passed into ctor would be visible, but not selected."""
|
||||
def __init__(self, parent, id, choices=[]):
|
||||
super(AGChoice, self).__init__(parent=parent, id=id)
|
||||
self.AppendItems(choices)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -78,7 +78,7 @@ class XmlCtrl(CodeEditor.CodeCtrl):
|
||||
|
||||
|
||||
def SetViewDefaults(self):
|
||||
CodeEditor.CodeCtrl.SetViewDefaults(self, configPrefix = "Xml", hasWordWrap = True, hasTabs = True)
|
||||
CodeEditor.CodeCtrl.SetViewDefaults(self, configPrefix = "Xml", hasWordWrap = True, hasTabs = True, hasFolding=True)
|
||||
|
||||
|
||||
def GetFontAndColorFromConfig(self):
|
||||
@@ -115,7 +115,7 @@ class XmlCtrl(CodeEditor.CodeCtrl):
|
||||
class XmlOptionsPanel(STCTextEditor.TextOptionsPanel):
|
||||
|
||||
def __init__(self, parent, id):
|
||||
STCTextEditor.TextOptionsPanel.__init__(self, parent, id, configPrefix = "Xml", label = "XML", hasWordWrap = True, hasTabs = True)
|
||||
STCTextEditor.TextOptionsPanel.__init__(self, parent, id, configPrefix = "Xml", label = "XML", hasWordWrap = True, hasTabs = True, hasFolding=True)
|
||||
|
||||
|
||||
def GetIcon(self):
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 170 KiB |
@@ -1,7 +1,7 @@
|
||||
Middle-Mouse-Click on the tab for an open file will close the file.
|
||||
Ctrl-Space in any editor does code completion.
|
||||
Right-clicking on something in the 'Thing' column of the debugger's frame tab may allow you to introspect it for more information.
|
||||
Right-Mouse-Click in Outline window allows you to change display sorting.
|
||||
In an editor, you can add line markers via Ctrl-M and jump to the next marker with F4 or previous marker with Shift-F4.
|
||||
In an editor. you can use the numpad + and - keys to toggle folding.
|
||||
In 'Find in Directory', if you specify a file, it will display all matches in the Message Window.
|
||||
Breakpoints for the debugger can be set while the process is running
|
||||
Breakpoints for the debugger can be set while the process is running.
|
||||
A split window can be closed by dragging the sash to one of its borders.
|
||||
@@ -407,7 +407,13 @@ _SaferCreateProcess(appName=%r,
|
||||
elif env:
|
||||
uenv = {}
|
||||
for key, val in env.items():
|
||||
uenv[unicode(key)] = unicode(val)
|
||||
try:
|
||||
uenv[unicode(key)] = unicode(val) # default encoding
|
||||
except UnicodeError:
|
||||
try:
|
||||
uenv[unicode(key, 'iso-8859-1')] = unicode(val, 'iso-8859-1') # backup encoding
|
||||
except UnicodeError:
|
||||
log.warn('Skipping environment variable "%s" in execution process: unable to convert to unicode using either the default encoding or ISO-8859-1' % (key))
|
||||
env = uenv
|
||||
hProcess, hThread, processId, threadId\
|
||||
= win32process.CreateProcess(appName, cmd, processSA,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,7 @@ import logging.config
|
||||
from activegrid.util.lang import *
|
||||
import activegrid.util.objutils as objutils
|
||||
import activegrid.util.sysutils as sysutils
|
||||
import activegrid.util.appdirs as appdirs
|
||||
|
||||
LEVEL_FATAL = logging.FATAL
|
||||
LEVEL_ERROR = logging.ERROR
|
||||
@@ -27,38 +28,47 @@ LEVEL_INFO = logging.INFO
|
||||
LEVEL_DEBUG = logging.DEBUG
|
||||
|
||||
EXCEPTION_INFO = 'exceptionInfo'
|
||||
loggingInitialized = False
|
||||
|
||||
LOG_MODE_IDE = 1
|
||||
LOG_MODE_TESTRUN = 2
|
||||
LOG_MODE_RUN = 3
|
||||
def initLogging(mode):
|
||||
configFile = None
|
||||
if (mode == LOG_MODE_IDE):
|
||||
configFile = os.getenv("AG_LOGCONFIG_IDE")
|
||||
elif (mode == LOG_MODE_TESTRUN):
|
||||
configFile = os.getenv("AG_LOGCONFIG_TESTRUN")
|
||||
else:
|
||||
configFile = os.getenv("AG_LOGCONFIG_RUN")
|
||||
if ((configFile == None) or not os.path.exists(configFile)):
|
||||
def initLogging(mode, force=False):
|
||||
global ag_debugLogger, loggingInitialized
|
||||
if (force or not loggingInitialized):
|
||||
loggingInitialized = True
|
||||
configFile = None
|
||||
if (mode == LOG_MODE_IDE):
|
||||
configFile = "IDELog"
|
||||
configFile = os.getenv("AG_LOGCONFIG_IDE")
|
||||
elif (mode == LOG_MODE_TESTRUN):
|
||||
configFile = "TestRunLog"
|
||||
configFile = os.getenv("AG_LOGCONFIG_PYTESTRUN")
|
||||
else:
|
||||
configFile = "RunLog"
|
||||
configFile = sysutils.mainModuleDir + "/py" + configFile + ".ini"
|
||||
if (os.path.exists(configFile)):
|
||||
fileConfig(configFile)
|
||||
else:
|
||||
defaultStream = sys.stderr
|
||||
if (mode == LOG_MODE_RUN):
|
||||
defaultStream = sys.stdout
|
||||
handler = logging.StreamHandler(defaultStream)
|
||||
handler.setLevel(logging.INFO)
|
||||
handler.setFormatter(logging.Formatter("%(asctime)s %(name)s %(levelname)s: %(message)s"))
|
||||
logging.getLogger().addHandler(handler)
|
||||
return configFile
|
||||
|
||||
configFile = os.getenv("AG_LOGCONFIG_RUN")
|
||||
if ((configFile == None) or not os.path.exists(configFile)):
|
||||
if (mode == LOG_MODE_IDE):
|
||||
configFile = "IDELog"
|
||||
elif (mode == LOG_MODE_TESTRUN):
|
||||
configFile = "TestRunLog"
|
||||
else:
|
||||
configFile = "RunLog"
|
||||
configFile = os.path.join(appdirs.getSystemDir(appdirs.AG_LOGS_DIR), "py" + configFile + ".ini")
|
||||
if (os.path.exists(configFile)):
|
||||
print "Using logging configuration file: %s" % configFile
|
||||
fileConfig(configFile)
|
||||
else:
|
||||
print "*** Cannot find logging configuration file (%s) -- setting default logging level to WARN ***" % (configFile)
|
||||
defaultStream = sys.stderr
|
||||
if (mode == LOG_MODE_RUN):
|
||||
defaultStream = sys.stdout
|
||||
handler = logging.StreamHandler(defaultStream)
|
||||
handler.setLevel(logging.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")
|
||||
|
||||
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
|
||||
e.exceptionInfo[key] = value
|
||||
|
||||
def reportException(out=None, stacktrace=False, diffable=False, exception=None):
|
||||
def reportException(exception, out=None, stacktrace=False, diffable=False):
|
||||
exstr = exceptionToString(exception, stacktrace, diffable)
|
||||
if (out == None):
|
||||
print exstr
|
||||
else:
|
||||
print >> out, exstr
|
||||
|
||||
def exceptionToString(exception=None, stacktrace=False, diffable=False):
|
||||
if (exception == None):
|
||||
extype, val, t = sys.exc_info()
|
||||
else:
|
||||
extype = objutils.typeToString(exception)
|
||||
val = exception
|
||||
if (stacktrace):
|
||||
e,v,t = sys.exc_info()
|
||||
def exceptionToString(exception, stacktrace=False, diffable=False):
|
||||
extype = objutils.typeToString(exception)
|
||||
val = exception
|
||||
if (stacktrace):
|
||||
e,v,t = sys.exc_info()
|
||||
if (diffable):
|
||||
exstr = removeFileRefs(str(val))
|
||||
else:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Name: appdirs.py
|
||||
# Purpose: Utilities for retrieving special application dirs
|
||||
#
|
||||
# Author: Kevin Ollivier
|
||||
# Author: Kevin Ollivier, Jeff Norton
|
||||
#
|
||||
# Created: 8/27/05
|
||||
# CVS-ID: $Id$
|
||||
@@ -10,50 +10,117 @@
|
||||
# License: wxWindows License
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
# NOTE: This was made a separate file because it depends upon the
|
||||
# wx.StandardPaths module, and thus, on wxWidgets, unlike other
|
||||
# utils modules. I wanted to ensure this module is never loaded
|
||||
# from the web server, etc.
|
||||
|
||||
from activegrid.util.lang import *
|
||||
import sys
|
||||
import os
|
||||
import string
|
||||
import wx
|
||||
import activegrid.util.sysutils as sysutils
|
||||
|
||||
def isWindows():
|
||||
return os.name == 'nt'
|
||||
|
||||
def _generateDocumentsDir():
|
||||
path = ""
|
||||
if sys.platform == "win32":
|
||||
from win32com.shell import shell, shellcon
|
||||
path=shell.SHGetFolderPath(0, shellcon.CSIDL_PERSONAL, None, 0)
|
||||
elif sys.platform == "darwin":
|
||||
import macfs, MACFS
|
||||
fsspec_disk, fsspec_desktop = macfs.FindFolder( MACFS.kOnSystemDisk, MACFS.kDocumentsFolderType, 0)
|
||||
path = macfs.FSSpec((fsspec_disk, fsspec_desktop, '')).as_pathname()
|
||||
|
||||
if path == "":
|
||||
path = os.path.expanduser("~")
|
||||
|
||||
return path
|
||||
def _getSystemDir(kind):
|
||||
if (kind == AG_LOGS_DIR):
|
||||
return os.path.join(getSystemDir(AG_SYSTEM_DIR) , "logs")
|
||||
elif (kind == AG_DEMOS_DIR):
|
||||
return os.path.join(getSystemDir(AG_SYSTEM_DIR), "demos")
|
||||
else:
|
||||
path = ""
|
||||
if (sysutils.isServer()):
|
||||
path = os.getenv("ACTIVEGRID_SERVER_HOME")
|
||||
if ((path is None) or (len(path) < 1)):
|
||||
path = sysutils.mainModuleDir
|
||||
else:
|
||||
path = os.getenv("AG_DOCUMENTS_DIR")
|
||||
if ((path is None) or (len(path) < 1)):
|
||||
if sysutils.isWindows():
|
||||
ifDefPy()
|
||||
try:
|
||||
from win32com.shell import shell, shellcon
|
||||
path = shell.SHGetFolderPath(0, shellcon.CSIDL_PERSONAL, None, 0)
|
||||
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
|
||||
# application object. This makes sure the wxApp will always be created when
|
||||
# we get the folder.
|
||||
ifDefPy()
|
||||
def getAppDataFolder():
|
||||
# wxStandardPaths requires a running app
|
||||
if wx.GetApp() and wx.Platform != "__WXGTK__":
|
||||
data_folder = wx.StandardPaths.Get().GetUserDataDir()
|
||||
if not os.path.exists(data_folder):
|
||||
os.mkdir(data_folder)
|
||||
return data_folder
|
||||
else:
|
||||
# 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")
|
||||
try:
|
||||
# NOTE: cannot import wx from the server
|
||||
import wx
|
||||
# wxStandardPaths requires a running app
|
||||
if wx.GetApp() and wx.Platform != "__WXGTK__":
|
||||
data_folder = wx.StandardPaths.Get().GetUserDataDir()
|
||||
if not os.path.exists(data_folder):
|
||||
os.mkdir(data_folder)
|
||||
return data_folder
|
||||
except:
|
||||
pass
|
||||
# wxBug: on *nix, it wants to point to ~/.appname, but
|
||||
# so does wxConfig... For now, redirect this to ~/.appbuilder
|
||||
# when this is fixed, we'll migrate settings to the correct place
|
||||
return os.path.join(os.path.expanduser("~"), ".appbuilder")
|
||||
endIfDef()
|
||||
|
||||
return ""
|
||||
ifDefPy()
|
||||
def createSystemDirs():
|
||||
if (not os.path.exists(getSystemDir())):
|
||||
os.mkdir(getSystemDir())
|
||||
if (not os.path.exists(getSystemDir(AG_LOGS_DIR))):
|
||||
os.mkdir(getSystemDir(AG_LOGS_DIR))
|
||||
if (not os.path.exists(getSystemDir(AG_DEMOS_DIR))):
|
||||
os.mkdir(getSystemDir(AG_DEMOS_DIR))
|
||||
endIfDef()
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
#----------------------------------------------------------------------------
|
||||
# Name: datetimeparser.py
|
||||
#
|
||||
# Purpose: - Instantiate datetime.datetime/date instance from a string
|
||||
# date representation.
|
||||
# Uses dateutil from http://labix.org/python-dateutil.
|
||||
#
|
||||
# - Creates string representation of datetime/date instance.
|
||||
#
|
||||
#
|
||||
# Author: Simon Toens
|
||||
#
|
||||
# Created: 28-Feb-06
|
||||
# CVS-ID:
|
||||
# Copyright: (c) 2005 ActiveGrid, Inc.
|
||||
# License: wxWindows License
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
import datetime
|
||||
|
||||
try:
|
||||
import dateutil.parser
|
||||
DATEUTIL_INSTALLED = True
|
||||
except ImportError:
|
||||
DATEUTIL_INSTALLED = False
|
||||
|
||||
ISO_8601_DATE_FORMAT = "%Y-%m-%d"
|
||||
ISO_8601_TIME_FORMAT = "%H:%M:%S"
|
||||
ISO_8601_DATETIME_FORMAT = "%s %s" %(ISO_8601_DATE_FORMAT,
|
||||
ISO_8601_TIME_FORMAT)
|
||||
|
||||
DEFAULT_DATETIME = datetime.datetime(1, 1, 1, 0, 0, 0, 0)
|
||||
|
||||
|
||||
def format(dateobj, formatstr=None):
|
||||
if (formatstr != None and _isDateTimeObject(dateobj)):
|
||||
return dateobj.strftime(str(formatstr))
|
||||
return str(dateobj)
|
||||
|
||||
|
||||
def parse(datestr, formatstr=None, asdate=False, astime=False):
|
||||
"""Instantiates and returns a datetime instance from the datestr datetime
|
||||
representation.
|
||||
|
||||
Optionally, a format string may be used. The format is only loosely
|
||||
interpreted, its only purpose beeing to determine if the year is first
|
||||
or last in datestr, and whether the day is in front or follows the
|
||||
month. If no formatstr is passed in, dateutil tries its best to parse
|
||||
the datestr. The default date format is YYYY-mm-dd HH:SS.
|
||||
|
||||
If asdate is True, returns a date instance instead of a datetime
|
||||
instance, if astime is True, returns a time instance instead of a
|
||||
datetime instance."""
|
||||
|
||||
|
||||
dayfirst, yearfirst = _getDayFirstAndYearFirst(formatstr)
|
||||
|
||||
rtn = None
|
||||
|
||||
try:
|
||||
if DATEUTIL_INSTALLED:
|
||||
rtn = dateutil.parser.parse(str(datestr), fuzzy=True,
|
||||
dayfirst=dayfirst, yearfirst=yearfirst,
|
||||
default=DEFAULT_DATETIME)
|
||||
else:
|
||||
rtn = DEFAULT_DATETIME
|
||||
except:
|
||||
rtn = DEFAULT_DATETIME
|
||||
|
||||
if (asdate and isinstance(rtn, datetime.datetime)):
|
||||
rtn = datetime.date(rtn.year, rtn.month, rtn.day)
|
||||
elif (astime and isinstance(rtn, datetime.datetime)):
|
||||
rtn = datetime.time(rtn.hour, rtn.minute, rtn.second, rtn.microsecond)
|
||||
|
||||
return rtn
|
||||
|
||||
|
||||
def _isDateTimeObject(obj):
|
||||
return (isinstance(obj, datetime.datetime) or
|
||||
isinstance(obj, datetime.date) or
|
||||
isinstance(obj, datetime.time))
|
||||
|
||||
|
||||
def _getDayFirstAndYearFirst(formatstr):
|
||||
dayFirst = False
|
||||
yearFirst = False
|
||||
|
||||
gotYear = False
|
||||
gotMonth = False
|
||||
gotDay = False
|
||||
|
||||
if (formatstr == None):
|
||||
formatstr = ""
|
||||
|
||||
for c in formatstr:
|
||||
if (c.lower() == "y"):
|
||||
if (gotYear):
|
||||
continue
|
||||
if (not gotDay and not gotMonth):
|
||||
yearFirst = True
|
||||
gotYear = True
|
||||
|
||||
elif (c.lower() == "m"):
|
||||
if (gotMonth):
|
||||
continue
|
||||
if (not gotDay):
|
||||
dayFirst = False
|
||||
gotMonth = True
|
||||
|
||||
elif (c.lower() == "d"):
|
||||
if (gotDay):
|
||||
continue
|
||||
if (not gotMonth):
|
||||
dayFirst = True
|
||||
gotDay = True
|
||||
|
||||
|
||||
return dayFirst, yearFirst
|
||||
@@ -19,6 +19,7 @@ import zipfile
|
||||
|
||||
import activegrid.util.aglogging as aglogging
|
||||
import activegrid.util.sysutils as sysutils
|
||||
import activegrid.util.utillang as utillang
|
||||
from activegrid.util.lang import *
|
||||
|
||||
global fileutilsLogger
|
||||
@@ -31,6 +32,65 @@ fileutilsLogger = logging.getLogger("activegrid.util.fileutils")
|
||||
aglogging.setLevelFatal(fileutilsLogger)
|
||||
#logging.getLogger().addHandler(logging.StreamHandler(sys.stderr))
|
||||
|
||||
def addRef(varname):
|
||||
return "${%s}" % varname
|
||||
|
||||
AG_SYSTEM_VAR_NAMES = [] # all AG System vars, with ${} syntax
|
||||
|
||||
AG_SYSTEM_VAR = "AG_SYSTEM"
|
||||
AG_SYSTEM_VAR_REF = addRef(AG_SYSTEM_VAR)
|
||||
AG_SYSTEM_VAR_NAMES.append(AG_SYSTEM_VAR_REF)
|
||||
|
||||
AG_SYSTEM_STATIC_VAR = "AG_SYSTEM_STATIC"
|
||||
AG_SYSTEM_STATIC_VAR_REF = addRef(AG_SYSTEM_STATIC_VAR)
|
||||
AG_SYSTEM_VAR_NAMES.append(AG_SYSTEM_STATIC_VAR_REF)
|
||||
|
||||
AG_APP_VAR = "AG_APP"
|
||||
AG_APP_STATIC_VAR = "AG_APP_STATIC"
|
||||
|
||||
# _initAGSystemVars needs to be called to initialize the following two
|
||||
# containers:
|
||||
EXPANDED_AG_SYSTEM_VARS = {} # ${varname} -> value (path)
|
||||
# ${varname}, ordered from longest to shortest path value
|
||||
AG_SYSTEM_VARS_LENGTH_ORDER = []
|
||||
|
||||
def _initAGSystemVars():
|
||||
if (len(EXPANDED_AG_SYSTEM_VARS) > 0):
|
||||
return
|
||||
|
||||
for v in AG_SYSTEM_VAR_NAMES:
|
||||
EXPANDED_AG_SYSTEM_VARS[v] = os.path.abspath(expandVars(v))
|
||||
AG_SYSTEM_VARS_LENGTH_ORDER.append(v)
|
||||
|
||||
AG_SYSTEM_VARS_LENGTH_ORDER.sort(_sortByValLength)
|
||||
|
||||
|
||||
def parameterizePathWithAGSystemVar(inpath):
|
||||
"""Returns parameterized path if path starts with a known AG directory. Otherwise returns path as it was passed in."""
|
||||
_initAGSystemVars()
|
||||
path = inpath
|
||||
if not sysutils.isWindows():
|
||||
# ensure we have forward slashes
|
||||
path = path.replace("\\", "/")
|
||||
|
||||
path = os.path.abspath(path)
|
||||
|
||||
for varname in AG_SYSTEM_VARS_LENGTH_ORDER:
|
||||
varval = EXPANDED_AG_SYSTEM_VARS[varname]
|
||||
if path.startswith(varval):
|
||||
return path.replace(varval, varname)
|
||||
|
||||
return inpath
|
||||
|
||||
def startsWithAgSystemVar(path):
|
||||
"""Returns True if path starts with a known AG system env var, False otherwise."""
|
||||
for varname in AG_SYSTEM_VAR_NAMES:
|
||||
if path.startswith(varname):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _sortByValLength(v1, v2):
|
||||
return len(EXPANDED_AG_SYSTEM_VARS[v2]) - len(EXPANDED_AG_SYSTEM_VARS[v1])
|
||||
|
||||
def makeDirsForFile(filename):
|
||||
d = os.path.dirname(filename)
|
||||
@@ -44,7 +104,7 @@ def createFile(filename, mode='w'):
|
||||
f = file(filename, mode)
|
||||
return f
|
||||
|
||||
def compareFiles(file1, file2):
|
||||
def compareFiles(file1, file2, ignore=None):
|
||||
## result = filecmp.cmp(file1, file2)
|
||||
## if result:
|
||||
## return 0
|
||||
@@ -62,6 +122,9 @@ def compareFiles(file1, file2):
|
||||
elif (len(line2) == 0):
|
||||
return -1
|
||||
elif (line1 != line2):
|
||||
if (ignore != None):
|
||||
if (line1.startswith(ignore) or line2.startswith(ignore)):
|
||||
continue
|
||||
line1 = line1.replace(" ", "")
|
||||
line2 = line2.replace(" ", "")
|
||||
if (line1 != line2):
|
||||
@@ -81,7 +144,10 @@ def compareFiles(file1, file2):
|
||||
continue
|
||||
return -1
|
||||
|
||||
def expandVars(value):
|
||||
def expandKnownAGVars(value):
|
||||
return expandVars(value, includeEnv=False)
|
||||
|
||||
def expandVars(value, includeEnv=True):
|
||||
"""Syntax: ${myvar,default="default value"}"""
|
||||
import activegrid.runtime as runtime
|
||||
sx = value.find("${")
|
||||
@@ -97,16 +163,19 @@ def expandVars(value):
|
||||
defaultValue = value[defsx+10:endx-1]
|
||||
if (defaultValue == None):
|
||||
varname = value[sx+2:endx]
|
||||
if (varname == "AG_SYSTEM"):
|
||||
if (varname == AG_SYSTEM_VAR):
|
||||
varval = runtime.appInfo.getSystemDir()
|
||||
elif (varname == "AG_SYSTEM_STATIC"):
|
||||
elif (varname == AG_SYSTEM_STATIC_VAR):
|
||||
varval = runtime.appInfo.getSystemStaticDir()
|
||||
elif (varname == "AG_APP"):
|
||||
elif (varname == AG_APP_VAR):
|
||||
varval = runtime.appInfo.getAppDir()
|
||||
elif (varname == "AG_APP_STATIC"):
|
||||
elif (varname == AG_APP_STATIC_VAR):
|
||||
varval = runtime.appInfo.getAppStaticDir()
|
||||
else:
|
||||
varval = os.getenv(varname)
|
||||
if (includeEnv):
|
||||
varval = os.getenv(varname)
|
||||
else:
|
||||
varval = None
|
||||
if ((varval == None) and (defaultValue != None)):
|
||||
varval = defaultValue
|
||||
if (varval == None):
|
||||
@@ -148,22 +217,21 @@ def convertSourcePath(path, to, otherdir=None):
|
||||
return otherdir + path[ix+7:]
|
||||
|
||||
|
||||
def visit(directory, files, extension):
|
||||
def visit(directory, files, extension, maxLevel=None, level=1):
|
||||
testdirs = os.listdir(directory)
|
||||
for thing in testdirs:
|
||||
fullpath = os.path.join(directory, thing)
|
||||
if (os.path.isdir(fullpath)):
|
||||
visit(fullpath, files, extension)
|
||||
if (os.path.isdir(fullpath) and (maxLevel == None or level < maxLevel)):
|
||||
visit(fullpath, files, extension, maxLevel, level+1)
|
||||
elif thing.endswith(extension):
|
||||
fullname = os.path.normpath(os.path.join(directory, thing))
|
||||
if not fullname in files:
|
||||
files.append(fullname)
|
||||
|
||||
def listFilesByExtensionInPath(path=[], extension='.lyt'):
|
||||
#Collect input and output arguments into one bunch
|
||||
def listFilesByExtensionInPath(path=[], extension='.lyt', maxLevel=None):
|
||||
retval = []
|
||||
for directory in path:
|
||||
visit(directory, retval, extension)
|
||||
visit(directory, retval, extension, maxLevel)
|
||||
return retval
|
||||
|
||||
def getFileLastModificationTime(fileName):
|
||||
@@ -311,6 +379,21 @@ def remove(file):
|
||||
shutil.rmtree(file)
|
||||
endIfDef()
|
||||
|
||||
def getUserTempDir():
|
||||
systemTempDir = utillang.getSystemTempDir()
|
||||
userName = sysutils.getUserName()
|
||||
userNameNoSpace = userName.replace('_','__').replace(' ','_')
|
||||
userTempDir = systemTempDir + os.sep + "activegrid_" + userNameNoSpace
|
||||
return userTempDir
|
||||
|
||||
def createUserTempDir():
|
||||
userTempDir = getUserTempDir()
|
||||
if not os.path.exists(userTempDir):
|
||||
os.makedirs(userTempDir)
|
||||
os.chmod(userTempDir, 0700)
|
||||
|
||||
createUserTempDir()
|
||||
|
||||
ifDefPy()
|
||||
import warnings
|
||||
warnings.filterwarnings("ignore", message="tmpnam is a potential security risk to your program")
|
||||
|
||||
@@ -16,7 +16,8 @@ import sys
|
||||
import os
|
||||
import __builtin__
|
||||
import types
|
||||
import xml.sax.saxutils as saxutils
|
||||
import activegrid.util.utillang as utillang
|
||||
import activegrid.util.datetimeparser as datetimeparser
|
||||
from types import *
|
||||
from activegrid.util.lang import *
|
||||
|
||||
@@ -65,6 +66,18 @@ def setStaticAttr(obj, attr, value):
|
||||
classDesc = obj.__class__
|
||||
setattr(classDesc, attr, value)
|
||||
|
||||
def hasAttrFast(obj, name):
|
||||
if hasRawAttr(obj, name):
|
||||
return True
|
||||
if hasattr(obj, '_complexType'):
|
||||
complexType=obj._complexType
|
||||
element=complexType.findElement(name)
|
||||
if element:
|
||||
return True
|
||||
if hasattr(obj, name):
|
||||
return True
|
||||
return False
|
||||
|
||||
def moduleForName(moduleName):
|
||||
module = None
|
||||
pathList = moduleName.split('.')
|
||||
@@ -114,15 +127,22 @@ def newInstance(className, objargs=None):
|
||||
if ((len(objargs) < 1) or (objargs[0].lower() == "false") or (not objargs[0])):
|
||||
return False
|
||||
return True
|
||||
if className == "str" or className == "unicode": # don"t strip: blanks are significant
|
||||
if className == "str" or className == "unicode": # don't strip: blanks are significant
|
||||
if len(objargs) > 0:
|
||||
try:
|
||||
return saxutils.unescape(objargs[0]).encode()
|
||||
return utillang.unescape(objargs[0]).encode()
|
||||
except:
|
||||
return "?"
|
||||
else:
|
||||
return ""
|
||||
|
||||
|
||||
if className == "date":
|
||||
return datetimeparser.parse(objargs[0], asdate=True)
|
||||
if className == "datetime":
|
||||
return datetimeparser.parse(objargs[0])
|
||||
if className == "time":
|
||||
return datetimeparser.parse(objargs[0], astime=True)
|
||||
|
||||
classtype = classForName(className)
|
||||
if (classtype == None):
|
||||
raise Exception("Could not find class %s" % className)
|
||||
@@ -135,23 +155,35 @@ def newInstance(className, objargs=None):
|
||||
def getClassProperty(classType, propertyName):
|
||||
return getattr(classType, propertyName)
|
||||
|
||||
def toDiffableRepr(value, exclude=None):
|
||||
def toDiffableRepr(value, maxLevel=None):
|
||||
if (value == None):
|
||||
return "None"
|
||||
if (maxLevel == None):
|
||||
maxLevel = 8
|
||||
maxLevel -= 1
|
||||
if (maxLevel < 0):
|
||||
return typeToString(value, PRINT_OBJ_DIFFABLE)
|
||||
## if ((exclude != None) and not isinstance(value, (basestring, int))):
|
||||
## for v in exclude:
|
||||
## if (v is value):
|
||||
## return "<recursive reference>"
|
||||
## exclude.append(value)
|
||||
## elif (isinstance(value, ObjectType) and hasattr(value, "__dict__")):
|
||||
## if (exclude == None):
|
||||
## exclude = []
|
||||
## s = "%s(%s)" % (type(value), toDiffableString(value.__dict__, exclude))
|
||||
elif (not isinstance(value, (BooleanType, ClassType, ComplexType, DictType, DictionaryType,
|
||||
if (not isinstance(value, (BooleanType, ClassType, ComplexType, DictType, DictionaryType,
|
||||
FloatType, IntType, ListType, LongType, StringType, TupleType,
|
||||
UnicodeType, BufferType, BuiltinFunctionType, BuiltinMethodType,
|
||||
CodeType, FrameType, FunctionType, GeneratorType, InstanceType,
|
||||
LambdaType, MethodType, ModuleType, SliceType, TracebackType,
|
||||
TypeType, XRangeType))):
|
||||
if (hasattr(value, "__str__")):
|
||||
if (hasattr(value, "_toDiffableString")):
|
||||
s = value._toDiffableString(maxLevel)
|
||||
elif (hasattr(value, "__str__")):
|
||||
s = str(value)
|
||||
elif (hasattr(value, "__dict__")):
|
||||
s = "%s(%s)" % (type(value), toDiffableString(value.__dict__, exclude))
|
||||
s = "%s(%s)" % (type(value), toDiffableString(value.__dict__, maxLevel))
|
||||
else:
|
||||
s = str(type(value))
|
||||
ix2 = s.find(" object at 0x")
|
||||
@@ -173,33 +205,31 @@ def toDiffableRepr(value, exclude=None):
|
||||
else:
|
||||
items.append("'%s'" % v)
|
||||
else:
|
||||
items.append(toDiffableString(v, exclude))
|
||||
items.append(toDiffableString(v, maxLevel))
|
||||
s = "[" + ", ".join(items) + "]"
|
||||
elif (isinstance(value, dict)):
|
||||
if (exclude == None):
|
||||
exclude = []
|
||||
items = []
|
||||
for key, val in value.iteritems():
|
||||
if (isinstance(val, UnicodeType)):
|
||||
items.append("'%s': u'%s'" % (key, toDiffableString(val, exclude)))
|
||||
items.append("'%s': u'%s'" % (key, toDiffableString(val, maxLevel)))
|
||||
elif (isinstance(val, basestring)):
|
||||
items.append("'%s': '%s'" % (key, toDiffableString(val, exclude)))
|
||||
items.append("'%s': '%s'" % (key, toDiffableString(val, maxLevel)))
|
||||
else:
|
||||
items.append("'%s': %s" % (key, toDiffableString(val, exclude)))
|
||||
items.append("'%s': %s" % (key, toDiffableString(val, maxLevel)))
|
||||
s = "{" + ", ".join(items) + "}"
|
||||
else:
|
||||
s = str(value)
|
||||
return s
|
||||
|
||||
def toDiffableString(value, exclude=None):
|
||||
if (value == None):
|
||||
return "None"
|
||||
if ((exclude != None) and not isinstance(value, (basestring, int))):
|
||||
for v in exclude:
|
||||
if (v is value):
|
||||
return "<recursive reference>"
|
||||
exclude.append(value)
|
||||
s = toDiffableRepr(value)
|
||||
def toDiffableString(value, maxLevel=None):
|
||||
## if (value == None):
|
||||
## return "None"
|
||||
## if ((exclude != None) and not isinstance(value, (basestring, int))):
|
||||
## for v in exclude:
|
||||
## if (v is value):
|
||||
## return "<recursive reference>"
|
||||
## exclude.append(value)
|
||||
s = toDiffableRepr(value, maxLevel)
|
||||
ds = ""
|
||||
i = s.find(" at 0x")
|
||||
start = 0
|
||||
|
||||
@@ -0,0 +1,380 @@
|
||||
#----------------------------------------------------------------------------
|
||||
# Name: parser.py
|
||||
# Purpose: parsing utilities
|
||||
#
|
||||
# Author: Jeff Norton
|
||||
#
|
||||
# Created: 8/9/05
|
||||
# CVS-ID: $Id$
|
||||
# Copyright: (c) 2004-2005 ActiveGrid, Inc.
|
||||
# License: wxWindows License
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
import re
|
||||
from activegrid.util.lang import *
|
||||
ifDefPy()
|
||||
import string
|
||||
import array
|
||||
endIfDef()
|
||||
|
||||
XPATH_ROOT_VAR = '__rootObj__'
|
||||
GETOBJECTPARTNAMES = ["primaryRef", "ref", "orderings", "limit"]
|
||||
|
||||
class Tokenizer(object):
|
||||
|
||||
TOKEN_IDENT = 1
|
||||
TOKEN_STRING = 2
|
||||
TOKEN_OP = 3
|
||||
TOKEN_WS = 4
|
||||
## TOKEN_PLACEHOLDER = 5
|
||||
|
||||
def __init__(self, text, identStart=None, tokenSep=None, ignoreWhitespace=True):
|
||||
"""
|
||||
Turn a string into individual tokens. Three types of tokens are recognized:
|
||||
TOKEN_IDENT: identifiers (those that start with the identStart pattern)
|
||||
TOKEN_STRING: quoted string
|
||||
TOKEN_OP: everything else
|
||||
Tokens are separated by white space or the tokenSep pattern.
|
||||
Constructor parameters:
|
||||
text: The string to tokenize
|
||||
identStart: A regular expression describing characters which start an identifier
|
||||
The default expression accepts letters, "_", and "/".
|
||||
tokenSep: A regular expression describing the characters which end a token
|
||||
(in addition to whitespace). The default expression accepts
|
||||
anything except alpha-numerics, "_", "/", and ":".
|
||||
Usage:
|
||||
Invoke getNextToken (or next) to get the next token. The instance variables
|
||||
token, and tokenVal will be populated with the current token type (TOKEN_IDENT,
|
||||
TOKEN_STRING, or TOEKN_OP) and value respectively. nextToken and nextTokenVal
|
||||
will also be available for lookahead. The next method is similar to
|
||||
getNextToken but also returns the token value. A value of None signals end
|
||||
of stream.
|
||||
"""
|
||||
self.ignoreWhitespace=ignoreWhitespace
|
||||
ifDefPy()
|
||||
if (isinstance(text, array.array)):
|
||||
text = text.tostring()
|
||||
endIfDef()
|
||||
self.text = asString(text)
|
||||
self.textIndex = 0
|
||||
self.textLen = len(self.text)
|
||||
self.token = None
|
||||
self.tokenVal = None
|
||||
self.nextToken = None
|
||||
self.nextTokenVal = None
|
||||
if (identStart == None):
|
||||
identStart = "[a-zA-Z_/]"
|
||||
if (tokenSep == None):
|
||||
tokenSep = "[^a-zA-Z0-9_/:]"
|
||||
self.identStart = re.compile(identStart)
|
||||
self.tokenSep = re.compile(tokenSep)
|
||||
self.getNextToken() # Prime the pump
|
||||
|
||||
def isEscaped(text, index):
|
||||
if ((index > 0) and (text[index-1] == '\\') and ((index < 2) or (text[index-2] != '\\'))):
|
||||
return True
|
||||
return False
|
||||
isEscaped = staticmethod(isEscaped)
|
||||
|
||||
def findClosingQuote(text, index, char):
|
||||
index = index + 1
|
||||
while True:
|
||||
endIndex = text.find(char, index)
|
||||
if (endIndex < 1):
|
||||
return -1
|
||||
if (Tokenizer.isEscaped(text, endIndex)):
|
||||
index = endIndex+1
|
||||
else:
|
||||
break
|
||||
return endIndex + 1
|
||||
findClosingQuote = staticmethod(findClosingQuote)
|
||||
|
||||
def _findClosing(self, char):
|
||||
if (self.textIndex >= self.textLen):
|
||||
raise Exception("The text \"%s\" has an unmatched string starting at %d" % (self.text, self.textIndex))
|
||||
index = Tokenizer.findClosingQuote(self.text, self.textIndex, char)
|
||||
if (index < 0):
|
||||
raise Exception("The text \"%s\" has an unmatched string starting at %d" % (self.text, self.textIndex-1))
|
||||
return index
|
||||
|
||||
def next(self):
|
||||
self.getNextToken()
|
||||
if (self.token == None):
|
||||
raise StopIteration()
|
||||
return self.tokenVal
|
||||
|
||||
def getNextToken(self):
|
||||
self.token = self.nextToken
|
||||
self.tokenVal = self.nextTokenVal
|
||||
while (self.textIndex < self.textLen):
|
||||
c = self.text[self.textIndex]
|
||||
if (c not in string.whitespace):
|
||||
if (c == '"' or c == "'" or c == '`'):
|
||||
endIndex = self._findClosing(c)
|
||||
self.nextToken = self.TOKEN_STRING
|
||||
self.nextTokenVal = self.text[self.textIndex:endIndex]
|
||||
self.textIndex = endIndex
|
||||
return
|
||||
elif (self.identStart.search(c)):
|
||||
endMatch = self.tokenSep.search(self.text, self.textIndex+1)
|
||||
if (endMatch):
|
||||
endIndex = endMatch.start()
|
||||
else:
|
||||
endIndex = self.textLen
|
||||
self.nextToken = self.TOKEN_IDENT
|
||||
self.nextTokenVal = self.text[self.textIndex:endIndex]
|
||||
self.textIndex = endIndex
|
||||
return
|
||||
else:
|
||||
self.nextToken = self.TOKEN_OP
|
||||
endIndex = self.textIndex + 1
|
||||
if (c == '<' or c == '>' or c == '!' or c == '='):
|
||||
if ((endIndex < self.textLen) and (self.text[endIndex] == '=')):
|
||||
endIndex += 1
|
||||
elif ((c == '%') and (endIndex < self.textLen)):
|
||||
c = self.text[endIndex]
|
||||
if (c in ['d', 'i', 'o', 'u', 'x', 'X', 'e', 'E', 'f', 'F', 'g', 'G', 'c', 'r', 's', '%']):
|
||||
endIndex += 1
|
||||
## self.nextToken = self.TOKEN_PLACEHOLDER # Should really be this but no one can handle it yet
|
||||
self.nextTokenVal = self.text[self.textIndex:endIndex]
|
||||
self.textIndex = endIndex
|
||||
return
|
||||
elif not self.ignoreWhitespace:
|
||||
self.nextToken=self.TOKEN_WS
|
||||
self.nextTokenVal=""
|
||||
while c in string.whitespace:
|
||||
self.nextTokenVal+=c
|
||||
self.textIndex+=1
|
||||
if self.textIndex==len(self.text):
|
||||
break
|
||||
c=self.text[self.textIndex]
|
||||
return
|
||||
self.textIndex += 1
|
||||
self.nextToken = None
|
||||
self.nextTokenVal = None
|
||||
|
||||
def isXPathNonVar(var):
|
||||
"""Returns true iff var is a string ("foo" or 'foo') or a number."""
|
||||
if (var.startswith("'") and var.endswith("'")) or \
|
||||
(var.startswith('"') and var.endswith('"')):
|
||||
return True
|
||||
|
||||
# list from XPathToCode, below
|
||||
if var.lower() in ["count", "empty", "true", "false", "null", "and", "or", \
|
||||
"like", "not"]:
|
||||
return True
|
||||
|
||||
try:
|
||||
t=int(var)
|
||||
return True
|
||||
except TypeError, e:
|
||||
pass
|
||||
except ValueError, e:
|
||||
pass
|
||||
|
||||
return False
|
||||
|
||||
def xpathToCode(xpaths, convertBracket=True):
|
||||
if ((xpaths == None) or (len(xpaths) < 1)):
|
||||
return "True"
|
||||
if (not isinstance(xpaths, (list, tuple))):
|
||||
xpaths = [xpaths]
|
||||
result = []
|
||||
for xpath in xpaths:
|
||||
t = Tokenizer(xpath, "[a-zA-Z0-9_/:\.]", "[^a-zA-Z0-9_/:\.]", ignoreWhitespace=False)
|
||||
expr = []
|
||||
lastToken=None
|
||||
while t.nextToken != None:
|
||||
t.getNextToken()
|
||||
if (t.token == Tokenizer.TOKEN_WS):
|
||||
expr.append(" ")
|
||||
elif (t.token == Tokenizer.TOKEN_OP):
|
||||
if (t.tokenVal == "="):
|
||||
expr.append("==")
|
||||
elif (t.tokenVal == "[" and convertBracket):
|
||||
expr.append("(")
|
||||
elif (t.tokenVal == "]" and convertBracket):
|
||||
expr.append(")")
|
||||
else:
|
||||
expr.append(t.tokenVal)
|
||||
elif (t.token == Tokenizer.TOKEN_IDENT):
|
||||
if (t.tokenVal == "and"):
|
||||
expr.append(" and ")
|
||||
elif (t.tokenVal == "or"):
|
||||
expr.append(" or ")
|
||||
elif (t.tokenVal == "not"):
|
||||
expr.append(" not ")
|
||||
elif (t.tokenVal == "like"):
|
||||
# REVIEW stoens@activegrid.com 02-Nov-05 --
|
||||
# This is very limited support for like:
|
||||
# typically like queries look like this: "foo like 'blah%'".
|
||||
# So translate this into "foo.startswith(blah)".
|
||||
# We should use a regular expression to support '%'s in
|
||||
# arbitrary places in the string. After 1.1.
|
||||
if t.nextToken and t.nextTokenVal.endswith("%'"):
|
||||
t.getNextToken() # throw away the "like" token
|
||||
last = len(expr) - 1
|
||||
expr[last] = "%s.startswith(%s')"\
|
||||
% (expr[last], t.tokenVal[:-2])
|
||||
else:
|
||||
# old behavior
|
||||
expr.append(t.tokenVal)
|
||||
|
||||
elif (t.tokenVal == "count"):
|
||||
expr.append("len")
|
||||
elif (t.tokenVal == 'empty'):
|
||||
expr.append('ctx.isEmptyPath')
|
||||
elif (t.tokenVal == 'true'):
|
||||
expr.append(_parseConstantFunction(t, 'True'))
|
||||
elif (t.tokenVal == 'false'):
|
||||
expr.append(_parseConstantFunction(t, 'False'))
|
||||
elif (t.tokenVal == 'null'):
|
||||
expr.append(_parseConstantFunction(t, 'None'))
|
||||
elif (-1!=t.tokenVal.find(':')):
|
||||
serviceDef, args=_parseServiceFunction(t)
|
||||
|
||||
# XXX handle serviceDef, args being None
|
||||
|
||||
for i in range(len(args)):
|
||||
args[i]=xpathToCode(args[i], False)
|
||||
jargs="[%s]" % (",".join(args))
|
||||
|
||||
# XXX should be processmodel.DATASERVICE_PROCESS_NAME, not "dataservice"
|
||||
if serviceDef[0]=='dataservice':
|
||||
expr.append("runtimesupport.invokeDataServiceWrapper(%s, %s, ctx, locals())" % \
|
||||
(serviceDef, jargs))
|
||||
else:
|
||||
expr.append("runtimesupport.invokeServiceWrapper(%s, %s, ctx)" % \
|
||||
(serviceDef, jargs))
|
||||
else:
|
||||
if (lastToken==')' or lastToken==']'):
|
||||
wasFunc=True
|
||||
else:
|
||||
wasFunc=False
|
||||
if (t.tokenVal.startswith('/')) and not wasFunc:
|
||||
expr.append(XPATH_ROOT_VAR)
|
||||
expr.append(t.tokenVal.replace('/','.'))
|
||||
lastToken=t.tokenVal
|
||||
else:
|
||||
expr.append(t.tokenVal)
|
||||
|
||||
|
||||
if (len(expr) == 2 and expr[0]==" "):
|
||||
expr = "".join(expr)
|
||||
result.append(expr)
|
||||
elif (len(expr) > 1):
|
||||
expr = "".join(expr)
|
||||
result.append("(%s)" % expr)
|
||||
elif (len(expr) > 0):
|
||||
result.append(expr[0])
|
||||
|
||||
return " and ".join(result)
|
||||
|
||||
def _parseArgs(t):
|
||||
args=[]
|
||||
argcon=""
|
||||
|
||||
if t.tokenVal!='(':
|
||||
return []
|
||||
if t.nextTokenVal==')':
|
||||
t.getNextToken()
|
||||
return []
|
||||
|
||||
depth=1
|
||||
|
||||
while(depth!=0):
|
||||
if not t.nextToken:
|
||||
raise Exception("parameters list with no closing ) after token: %s" % t.tokenVal)
|
||||
t.getNextToken()
|
||||
|
||||
if t.tokenVal=='(':
|
||||
depth+=1
|
||||
if t.tokenVal==')':
|
||||
depth-=1
|
||||
|
||||
if depth==0 or (depth==1 and t.tokenVal==','):
|
||||
args.append(argcon)
|
||||
argcon=""
|
||||
else:
|
||||
argcon+=t.tokenVal
|
||||
return args
|
||||
|
||||
def _parseServiceFunction(t):
|
||||
"""Parses what appears to be a service function call into serviceDefs and args lists.
|
||||
|
||||
Returns None, None if the serviceFunction appears to be invalid.
|
||||
"""
|
||||
if t.nextTokenVal!='(':
|
||||
return t.tokenVal, None
|
||||
|
||||
serviceDef=t.tokenVal.split(':')
|
||||
t.getNextToken()
|
||||
args=_parseArgs(t)
|
||||
|
||||
return serviceDef, args
|
||||
|
||||
def _parseConstantFunction(t, outputValue):
|
||||
firstVal = t.tokenVal
|
||||
if t.nextTokenVal != '(':
|
||||
return firstVal
|
||||
t.getNextToken()
|
||||
if t.nextTokenVal != ')':
|
||||
return "%s%s" % (firstVal, '(')
|
||||
t.getNextToken()
|
||||
return outputValue
|
||||
|
||||
def parseDSPredicate(ctx, str, vars, valueList=None):
|
||||
from activegrid.util.utillang import evalCode
|
||||
from activegrid.util.utillang import ObjAsDict
|
||||
|
||||
if valueList == None:
|
||||
valueList = []
|
||||
indexVar=0
|
||||
oldIndexVar=0
|
||||
sourceStr=str
|
||||
inlinedPredicate=[]
|
||||
qualifications=[]
|
||||
while True:
|
||||
oldIndexVar = indexVar
|
||||
dollarCurlForm = False
|
||||
quoted = False
|
||||
indexVar = sourceStr.find("bpws:getVariableData", indexVar)
|
||||
if indexVar == -1:
|
||||
indexVar = sourceStr.find("${", oldIndexVar)
|
||||
if indexVar == -1:
|
||||
break
|
||||
dollarCurlForm = True
|
||||
if indexVar > 0 and sourceStr[indexVar-1] in ('"',"'"):
|
||||
quoted = True
|
||||
if not dollarCurlForm:
|
||||
openParen = sourceStr.find("(", indexVar)
|
||||
if openParen == -1:
|
||||
break
|
||||
closeParen = sourceStr.find(")", openParen)
|
||||
if closeParen == -1:
|
||||
break
|
||||
else:
|
||||
openParen = indexVar+1
|
||||
closeParen = sourceStr.find("}", openParen)
|
||||
if closeParen == -1:
|
||||
break
|
||||
varRef = sourceStr[openParen+1: closeParen]
|
||||
if varRef.startswith('"') or varRef.startswith("'"):
|
||||
varRef = varRef[1:]
|
||||
if varRef.endswith('"') or varRef.endswith("'"):
|
||||
varRef = varRef[:-1]
|
||||
if isinstance(vars, dict) or isinstance(vars, ObjAsDict):
|
||||
varRefCode = xpathToCode(varRef)
|
||||
value = evalCode(varRefCode, vars)
|
||||
else:
|
||||
value = ctx.evalPath(vars, varRef)
|
||||
inlinedPredicate.append(sourceStr[oldIndexVar:indexVar])
|
||||
if quoted:
|
||||
inlinedPredicate.append("%s" % value)
|
||||
else:
|
||||
inlinedPredicate.append('%s')
|
||||
valueList.append(value)
|
||||
indexVar = closeParen+1
|
||||
inlinedPredicate.append(sourceStr[oldIndexVar:])
|
||||
qualifications.append(''.join(inlinedPredicate))
|
||||
return qualifications, valueList
|
||||
@@ -21,3 +21,91 @@ def caseInsensitiveCompare(s1, s2):
|
||||
return -1
|
||||
else:
|
||||
return 1
|
||||
|
||||
def multiSplit(stringList, tokenList=[" "]):
|
||||
"""Splits strings in stringList by tokens, returns list of string."""
|
||||
if not stringList: return []
|
||||
if isinstance(tokenList, basestring):
|
||||
tokenList = [tokenList]
|
||||
if isinstance(stringList, basestring):
|
||||
stringList = [stringList]
|
||||
rtnList = stringList
|
||||
for token in tokenList:
|
||||
rtnList = rtnList[:]
|
||||
for string in rtnList:
|
||||
if string.find(token) > -1:
|
||||
rtnList.remove(string)
|
||||
names = string.split(token)
|
||||
for name in names:
|
||||
name = name.strip()
|
||||
if name:
|
||||
rtnList.append(name)
|
||||
return rtnList
|
||||
|
||||
QUOTES = ("\"", "'")
|
||||
|
||||
def _findArgStart(argStr):
|
||||
i = -1
|
||||
for c in argStr:
|
||||
i += 1
|
||||
if (c == " "):
|
||||
continue
|
||||
elif (c == ","):
|
||||
continue
|
||||
return i
|
||||
return None
|
||||
|
||||
def _findArgEnd(argStr):
|
||||
quotedArg = True
|
||||
argEndChar = argStr[0]
|
||||
if (not argEndChar in QUOTES):
|
||||
argEndChar = ","
|
||||
quotedArg = False
|
||||
i = -1
|
||||
firstChar = True
|
||||
for c in argStr:
|
||||
i+= 1
|
||||
if (firstChar):
|
||||
firstChar = False
|
||||
if (quotedArg):
|
||||
continue
|
||||
if (c == argEndChar):
|
||||
if (quotedArg):
|
||||
return min(i+1, len(argStr))
|
||||
else:
|
||||
return i
|
||||
return i
|
||||
|
||||
def parseArgs(argStr, stripQuotes=False):
|
||||
"""
|
||||
Given a str representation of method arguments, returns list arguments (as
|
||||
strings).
|
||||
|
||||
Input: "('[a,b]', 'c', 1)" -> Output: ["'[a,b]'", "'c'", "1"].
|
||||
|
||||
If stripQuotes, removes quotes from quoted arg.
|
||||
"""
|
||||
if (argStr.startswith("(")):
|
||||
argStr = argStr[1:]
|
||||
if (argStr.endswith(")")):
|
||||
argStr = argStr[:-1]
|
||||
else:
|
||||
raise AssertionError("Expected argStr to end with ')'")
|
||||
|
||||
rtn = []
|
||||
argsStr = argStr.strip()
|
||||
while (True):
|
||||
startIndex = _findArgStart(argStr)
|
||||
if (startIndex == None):
|
||||
break
|
||||
argStr = argStr[startIndex:]
|
||||
endIndex = _findArgEnd(argStr)
|
||||
if (endIndex == len(argStr) - 1):
|
||||
rtn.append(argStr.strip())
|
||||
break
|
||||
t = argStr[:endIndex].strip()
|
||||
if (stripQuotes and t[0] in QUOTES and t[-1] in QUOTES):
|
||||
t = t[1:-1]
|
||||
rtn.append(t)
|
||||
argStr = argStr[endIndex:]
|
||||
return rtn
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
|
||||
# this will be set to true in IDE.py when we are running release builds.
|
||||
isRelease = False
|
||||
@@ -26,6 +27,12 @@ isRelease = False
|
||||
|
||||
MAINMODULE_DIR = "AG_MAINMODULE_DIR"
|
||||
IS_RELEASE = "AG_IS_RELEASE"
|
||||
IS_COMMERCIAL = "AG_IS_COMMERCIAL"
|
||||
AG_SYSTEM_START_TIME_ENV_NAME = "AG_SYSTEM_START_TIME"
|
||||
|
||||
def isCommercial():
|
||||
|
||||
return os.path.exists(os.path.join(mainModuleDir,"commercial.txt")) or 'true' == (str(os.getenv(IS_COMMERCIAL)).lower())
|
||||
|
||||
def isRelease():
|
||||
return 'true' == (str(os.getenv(IS_RELEASE)).lower())
|
||||
@@ -39,7 +46,16 @@ def setRelease(value):
|
||||
def isWindows():
|
||||
return os.name == 'nt'
|
||||
|
||||
__isServer = False
|
||||
|
||||
def setServerMode(isServer):
|
||||
global __isServer
|
||||
__isServer = isServer
|
||||
|
||||
def isServer():
|
||||
global __isServer
|
||||
return __isServer
|
||||
|
||||
def _generateMainModuleDir():
|
||||
mainModuleDir = os.getenv(MAINMODULE_DIR)
|
||||
if mainModuleDir: # if environment variable set, return it
|
||||
@@ -85,3 +101,16 @@ def getCommandNameForExecPath(execPath):
|
||||
return '"%s"' % execPath
|
||||
return execPath
|
||||
|
||||
def getUserName():
|
||||
if isWindows():
|
||||
return os.getenv('USERNAME')
|
||||
else:
|
||||
# 06-Feb-06 stoens@activegrid.com --
|
||||
# this blows up the linux cc runs with "Inappropriate ioctl for device"
|
||||
#return os.getlogin()
|
||||
return os.getenv('USER')
|
||||
|
||||
def getCurrentTimeAsFloat():
|
||||
return time.time()
|
||||
|
||||
systemStartTime = getCurrentTimeAsFloat()
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
#----------------------------------------------------------------------------
|
||||
# Name: utillang.py
|
||||
# Purpose: Provide language specific utilities
|
||||
#
|
||||
# Author: Joel Hare
|
||||
#
|
||||
# Created: 8/23/05
|
||||
# CVS-ID: $Id$
|
||||
# Copyright: (c) 2004-2005 ActiveGrid, Inc.
|
||||
# License: wxWindows License
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
import os
|
||||
import sys
|
||||
import UserDict
|
||||
import tempfile
|
||||
import xml.sax.saxutils as saxutils
|
||||
|
||||
import activegrid.util.parser as parser
|
||||
|
||||
PY2WEB_codepages = {
|
||||
'cp1251' : 'CP-1251',
|
||||
'koi8_r' : 'KOI8-R',
|
||||
}
|
||||
|
||||
def evalXPath(xpath, data, specialEntries=None):
|
||||
codeStr = parser.xpathToCode(xpath)
|
||||
return evalCode(codeStr, data, specialEntries)
|
||||
|
||||
def evalCode(codeStr, data, specialEntries=None):
|
||||
if isinstance(data, ObjAsDict):
|
||||
namespace = data
|
||||
elif isinstance(data, dict):
|
||||
namespace = dict(data)
|
||||
else:
|
||||
namespace = ObjAsDict(data)
|
||||
if specialEntries:
|
||||
for key, value in specialEntries.items():
|
||||
namespace.addSpecialEntry(key, value)
|
||||
return eval(codeStr, {}, namespace)
|
||||
|
||||
def deriveCharset():
|
||||
charset = None
|
||||
encodingString = sys.getdefaultencoding()
|
||||
if encodingString != 'ascii':
|
||||
charset = PY2WEB_codepages.get(encodingString.lower())
|
||||
if charset == None:
|
||||
charset = encodingString
|
||||
return charset
|
||||
|
||||
def toUTF8(value):
|
||||
"""
|
||||
Converts all unicode and non-string values to utf-8.
|
||||
This assumes string instances are already encoded in utf-8.
|
||||
Note that us-ascii is a subset of utf-8.
|
||||
"""
|
||||
if isinstance(value, unicode):
|
||||
return value.encode('utf-8')
|
||||
return str(value)
|
||||
|
||||
def toUnicode(value):
|
||||
"""
|
||||
Converts all strings non-string values to unicode.
|
||||
This assumes string instances are encoded in utf-8.
|
||||
Note that us-ascii is a subset of utf-8.
|
||||
"""
|
||||
if not isinstance(value, unicode):
|
||||
if not isinstance(value, str):
|
||||
return unicode(value)
|
||||
return unicode(value, 'utf-8')
|
||||
return value
|
||||
|
||||
|
||||
def getSystemTempDir():
|
||||
return tempfile.gettempdir()
|
||||
|
||||
def getEnvVar(name, defaultVal=None):
|
||||
if os.environ.has_key(name):
|
||||
return os.environ[name]
|
||||
return defaultVal
|
||||
|
||||
class ObjAsDict(UserDict.DictMixin):
|
||||
"""
|
||||
Passing this to eval as the local variables dictionary allows the
|
||||
evaluated code to access properties in the wrapped object
|
||||
"""
|
||||
def __init__(self, obj):
|
||||
self.obj = obj
|
||||
self.specialEntries = {}
|
||||
|
||||
def __getitem__(self, key):
|
||||
try:
|
||||
return getattr(self.obj, key)
|
||||
except AttributeError, e:
|
||||
if self.specialEntries.has_key(key):
|
||||
return self.specialEntries[key]
|
||||
raise KeyError(e.args)
|
||||
def __setitem__(self, key, item): setattr(self.obj, key, item)
|
||||
def __delitem__(self, key): delattr(self.obj, key)
|
||||
def keys(self):
|
||||
ret=[]
|
||||
for i in list(dir(self.obj)+self.specialEntries.keys()):
|
||||
if i=="__doc__" or i=="__module__":
|
||||
pass
|
||||
elif i not in ret:
|
||||
ret.append(i)
|
||||
return ret
|
||||
|
||||
def addSpecialEntry(self, key, value):
|
||||
self.specialEntries[key] = value
|
||||
|
||||
global saxXMLescapeDoubleQuote
|
||||
saxXMLescapeDoubleQuote = {'"':'"'}
|
||||
|
||||
global saxXMLescapesAllQuotes
|
||||
# IE doesn't support ' but it doesn't seem like we should need this escaped at all so I took it out.
|
||||
saxXMLescapesAllQuotes = {'"':'"', "'":"'"}
|
||||
|
||||
global saxXMLunescapes
|
||||
saxXMLunescapes = {'"':'"', "'":"'"}
|
||||
|
||||
def escape(data, extraEscapes=None):
|
||||
"""Escape ', ", &, <, and > in a string of data.
|
||||
|
||||
Basically, everything that saxutils.escape does (and this calls that, at
|
||||
least for now), but with " and ' added as well.
|
||||
|
||||
TODO: make this faster; saxutils.escape() is really slow
|
||||
"""
|
||||
|
||||
global saxXMLescapeDoubleQuote
|
||||
if (extraEscapes == None):
|
||||
extraEscapes = saxXMLescapeDoubleQuote
|
||||
return saxutils.escape(data, extraEscapes)
|
||||
|
||||
def unescape(data):
|
||||
"""Unescape ', ", &, <, and > in a string of data.
|
||||
|
||||
Basically, everything that saxutils.unescape does (and this calls that, at
|
||||
least for now), but with " and ' added as well.
|
||||
|
||||
TODO: make this faster; saxutils.unescape() is really slow
|
||||
"""
|
||||
|
||||
global saxXMLunescapes
|
||||
return saxutils.unescape(data, saxXMLunescapes)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,35 +22,44 @@ import activegrid.util.aglogging as aglogging
|
||||
|
||||
xmlLogger = logging.getLogger("activegrid.util.xml")
|
||||
|
||||
def load(fileName, knownTypes=None, knownNamespaces=None):
|
||||
def load(fileName, knownTypes=None, knownNamespaces=None, createGenerics=False):
|
||||
loadedObject = None
|
||||
fileObject = file(fileName)
|
||||
timeStart = time.time()
|
||||
xml = ""
|
||||
try:
|
||||
xml = fileObject.read()
|
||||
loadedObject = unmarshal(xml, knownTypes=knownTypes, knownNamespaces=knownNamespaces, xmlSource=fileName)
|
||||
loadedObject = unmarshal(xml, knownTypes=knownTypes, knownNamespaces=knownNamespaces, xmlSource=fileName, createGenerics=createGenerics)
|
||||
loadedObject.fileName = os.path.abspath(fileName)
|
||||
if hasattr(loadedObject, 'initialize'):
|
||||
loadedObject.initialize()
|
||||
finally:
|
||||
fileObject.close()
|
||||
timeDone = time.time()
|
||||
aglogging.info(xmlLogger, ('Load statistics for file %s: elapsed time = %f secs' % (fileName, timeDone-timeStart)))
|
||||
if xmlLogger.isEnabledFor(aglogging.LEVEL_INFO):
|
||||
timeDone = time.time()
|
||||
aglogging.info(xmlLogger, ('Load statistics for file %s (%d bytes): elapsed time = %f secs' % (fileName, len(xml), timeDone-timeStart)))
|
||||
return loadedObject
|
||||
|
||||
def loadURI(uri, knownTypes=None, knownNamespaces=None, xmlSource=None):
|
||||
def loadURI(uri, knownTypes=None, knownNamespaces=None, xmlSource=None, createGenerics=False):
|
||||
loadedObject = None
|
||||
xml = urllib.urlopen(uri).read()
|
||||
loadedObject = unmarshal(xml, knownTypes=knownTypes, knownNamespaces=knownNamespaces, xmlSource=xmlSource)
|
||||
loadedObject.fileName = uri
|
||||
if hasattr(loadedObject, 'initialize'):
|
||||
loadedObject.initialize()
|
||||
timeStart = time.time()
|
||||
xml = ""
|
||||
try:
|
||||
xml = urllib.urlopen(uri).read()
|
||||
loadedObject = unmarshal(xml, knownTypes=knownTypes, knownNamespaces=knownNamespaces, xmlSource=xmlSource, createGenerics=createGenerics)
|
||||
loadedObject.fileName = uri
|
||||
if hasattr(loadedObject, 'initialize'):
|
||||
loadedObject.initialize()
|
||||
finally:
|
||||
if xmlLogger.isEnabledFor(aglogging.LEVEL_INFO):
|
||||
timeDone = time.time()
|
||||
aglogging.info(xmlLogger, ('Load statistics for URI %s (%d bytes): elapsed time = %f secs' % (uri, len(xml), timeDone-timeStart)))
|
||||
return loadedObject
|
||||
|
||||
def unmarshal(xml, knownTypes=None, knownNamespaces=None, xmlSource=None):
|
||||
def unmarshal(xml, knownTypes=None, knownNamespaces=None, xmlSource=None, createGenerics=False):
|
||||
if (knownTypes == None):
|
||||
knownTypes, knownNamespaces = getAgKnownTypes()
|
||||
return xmlmarshaller.unmarshal(xml, knownTypes=knownTypes, knownNamespaces=knownNamespaces, xmlSource=xmlSource)
|
||||
return xmlmarshaller.unmarshal(xml, knownTypes=knownTypes, knownNamespaces=knownNamespaces, xmlSource=xmlSource, createGenerics=createGenerics)
|
||||
|
||||
def save(fileName, objectToSave, prettyPrint=True, marshalType=True, knownTypes=None, knownNamespaces=None, encoding='utf-8'):
|
||||
if hasattr(objectToSave, '_xmlReadOnly') and objectToSave._xmlReadOnly == True:
|
||||
@@ -155,41 +164,6 @@ def getAgVersion(fileName):
|
||||
version = xml[i+1:j]
|
||||
return version
|
||||
|
||||
def escape(data):
|
||||
"""Escape ', ", &, <, and > in a string of data.
|
||||
|
||||
Basically, everything that saxutils.escape does (and this calls that, at
|
||||
least for now), but with " added as well.
|
||||
|
||||
XXX TODO make this faster; saxutils.escape() is really slow
|
||||
"""
|
||||
|
||||
import xml.sax.saxutils as saxutils
|
||||
|
||||
data=saxutils.escape(data)
|
||||
data=data.replace("\"", """)
|
||||
|
||||
# IE doesn't support '
|
||||
# data=data.replace("\'", "'")
|
||||
data=data.replace("\'", "'")
|
||||
|
||||
return data
|
||||
|
||||
def unescape(data):
|
||||
"""Unescape ', ", &, <, and > in a string of data.
|
||||
|
||||
Basically, everything that saxutils.unescape does (and this calls that, at
|
||||
least for now), but with " added as well.
|
||||
|
||||
XXX TODO make this faster; saxutils.unescape() is really slow
|
||||
"""
|
||||
|
||||
import xml.sax.saxutils as saxutils
|
||||
|
||||
data=data.replace(""", "\"")
|
||||
data=data.replace("'", "\'")
|
||||
return saxutils.unescape(data)
|
||||
|
||||
|
||||
AG_NS_URL = "http://www.activegrid.com/ag.xsd"
|
||||
BPEL_NS_URL = "http://schemas.xmlsoap.org/ws/2003/03/business-process"
|
||||
@@ -197,7 +171,9 @@ HTTP_WSDL_NS_URL = "http://schemas.xmlsoap.org/wsdl/http/"
|
||||
MIME_WSDL_NS_URL = "http://schemas.xmlsoap.org/wsdl/mime/"
|
||||
SOAP_NS_URL = "http://schemas.xmlsoap.org/wsdl/soap/"
|
||||
SOAP12_NS_URL = "http://schemas.xmlsoap.org/wsdl/soap12/"
|
||||
SOAP_NS_ENCODING = "http://schemas.xmlsoap.org/soap/encoding/"
|
||||
WSDL_NS_URL = "http://schemas.xmlsoap.org/wsdl/"
|
||||
WSSE_NS_URL = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
|
||||
XFORMS_NS_URL = "http://www.w3c.org/xform.xsd"
|
||||
XMLSCHEMA_NS_URL = "http://www.w3.org/2001/XMLSchema"
|
||||
XSI_NS_URL = "http://www.w3.org/2001/XMLSchema-instance"
|
||||
@@ -209,7 +185,8 @@ KNOWN_NAMESPACES = { AG_NS_URL : "ag",
|
||||
MIME_WSDL_NS_URL : "mime",
|
||||
SOAP_NS_URL : "soap",
|
||||
SOAP12_NS_URL : "soap12",
|
||||
WSDL_NS_URL : "wsdl",
|
||||
WSDL_NS_URL : "wsdl",
|
||||
WSSE_NS_URL : "wsse",
|
||||
XFORMS_NS_URL : "xforms",
|
||||
XMLSCHEMA_NS_URL : "xs",
|
||||
XACML_NS_URL : "xacml",
|
||||
@@ -226,19 +203,23 @@ def getAgXsdToClassName():
|
||||
"ag:body" : "activegrid.model.processmodel.Body",
|
||||
"ag:category_substitutions" : "activegrid.server.layoutrenderer.CategorySubstitutions",
|
||||
"ag:command" : "activegrid.model.wsdl.Command",
|
||||
"ag:setElement" : "activegrid.model.processmodel.SetElementOperation",
|
||||
"ag:css" : "activegrid.server.layoutrenderer.CSS",
|
||||
"ag:cssRule" : "activegrid.model.processmodel.CssRule",
|
||||
"ag:databaseService" : "activegrid.server.deployment.DatabaseService",
|
||||
"ag:datasource" : "activegrid.data.dataservice.DataSource",
|
||||
"ag:dataObjectList" : "activegrid.data.datalang.DataObjectList",
|
||||
"ag:debug" : "activegrid.model.processmodel.DebugOperation",
|
||||
"ag:deployment" : "activegrid.server.deployment.Deployment",
|
||||
"ag:formData" : "activegrid.model.processmodel.FormData",
|
||||
"ag:formVar" : "activegrid.model.processmodel.FormVar",
|
||||
"ag:generator" : "activegrid.server.layoutrenderer.SerializableGenerator",
|
||||
"ag:head" : "activegrid.server.layoutrenderer.Head",
|
||||
"ag:hr" : "activegrid.model.processmodel.HorizontalRow",
|
||||
"ag:identity" : "activegrid.model.identitymodel.Identity",
|
||||
"ag:identityref" : "activegrid.server.deployment.IdentityRef",
|
||||
"ag:image" : "activegrid.model.processmodel.Image",
|
||||
"ag:inputPart" : "activegrid.model.processmodel.InputPart",
|
||||
"ag:keystore" : "activegrid.model.identitymodel.KeyStore",
|
||||
"ag:label" : "activegrid.model.processmodel.Label",
|
||||
"ag:layout" : "activegrid.server.layoutrenderer.Layout",
|
||||
"ag:layouts" : "activegrid.server.layoutrenderer.Layouts",
|
||||
@@ -246,9 +227,11 @@ def getAgXsdToClassName():
|
||||
"ag:localService" : "activegrid.server.deployment.LocalService",
|
||||
"ag:parameter" : "activegrid.server.layoutrenderer.Parameter",
|
||||
"ag:parameters" : "activegrid.server.layoutrenderer.Parameters",
|
||||
"ag:postInitialize" : "activegrid.model.processmodel.PostInitialize",
|
||||
"ag:processref" : "activegrid.server.deployment.ProcessRef",
|
||||
"ag:query" : "activegrid.model.processmodel.Query",
|
||||
"ag:soapService" : "activegrid.server.deployment.SoapService",
|
||||
"ag:redirect" : "activegrid.server.layoutrenderer.Redirect",
|
||||
"ag:requiredFile" : "activegrid.server.layoutrenderer.RequiredFile",
|
||||
"ag:resource" : "activegrid.model.identitymodel.IDResource",
|
||||
"ag:restService" : "activegrid.server.deployment.RestService",
|
||||
@@ -355,27 +338,38 @@ def getAgXsdToClassName():
|
||||
"xforms:xforms" : "activegrid.model.processmodel.XFormsRoot",
|
||||
"xs:all" : "activegrid.model.schema.XsdSequence",
|
||||
"xs:any" : "activegrid.model.schema.XsdAny",
|
||||
"xs:anyAttribute" : "activegrid.model.schema.XsdAnyAttribute",
|
||||
"xs:attribute" : "activegrid.model.schema.XsdAttribute",
|
||||
"xs:choice" : "activegrid.model.schema.XsdChoice",
|
||||
"xs:complexContent" : "activegrid.model.schema.XsdComplexContent",
|
||||
"xs:complexType" : "activegrid.model.schema.XsdComplexType",
|
||||
"xs:documentation" : "activegrid.model.schema.XsdDocumentation",
|
||||
"xs:element" : "activegrid.model.schema.XsdElement",
|
||||
"xs:enumeration" : "activegrid.model.schema.XsdEnumeration",
|
||||
"xs:enumeration" : "activegrid.model.schema.XsdFacetEnumeration",
|
||||
"xs:extension" : "activegrid.model.schema.XsdExtension",
|
||||
"xs:fractionDigits" : "activegrid.model.schema.XsdFacetFractionDigits",
|
||||
"xs:field" : "activegrid.model.schema.XsdKeyField",
|
||||
"xs:import" : "activegrid.model.schema.XsdInclude",
|
||||
"xs:include" : "activegrid.model.schema.XsdInclude",
|
||||
"xs:key" : "activegrid.model.schema.XsdKey",
|
||||
"xs:keyref" : "activegrid.model.schema.XsdKeyRef",
|
||||
"xs:length" : "activegrid.model.schema.XsdLength",
|
||||
"xs:length" : "activegrid.model.schema.XsdFacetLength",
|
||||
"xs:list" : "activegrid.model.schema.XsdList",
|
||||
"xs:maxLength" : "activegrid.model.schema.XsdMaxLength",
|
||||
"xs:maxExclusive" : "activegrid.model.schema.XsdFacetMaxExclusive",
|
||||
"xs:maxInclusive" : "activegrid.model.schema.XsdFacetMaxInclusive",
|
||||
"xs:maxLength" : "activegrid.model.schema.XsdFacetMaxLength",
|
||||
"xs:minExclusive" : "activegrid.model.schema.XsdFacetMinExclusive",
|
||||
"xs:minInclusive" : "activegrid.model.schema.XsdFacetMinInclusive",
|
||||
"xs:minLength" : "activegrid.model.schema.XsdFacetMinLength",
|
||||
"xs:pattern" : "activegrid.model.schema.XsdFacetPattern",
|
||||
"xs:restriction" : "activegrid.model.schema.XsdRestriction",
|
||||
"xs:schema" : "activegrid.model.schema.Schema",
|
||||
"xs:selector" : "activegrid.model.schema.XsdKeySelector",
|
||||
"xs:sequence" : "activegrid.model.schema.XsdSequence",
|
||||
"xs:simpleContent" : "activegrid.model.schema.XsdSimpleContent",
|
||||
"xs:simpleType" : "activegrid.model.schema.XsdSimpleType",
|
||||
"xs:totalDigits" : "activegrid.model.schema.XsdTotalDigits",
|
||||
"xs:totalDigits" : "activegrid.model.schema.XsdFacetTotalDigits",
|
||||
"xs:whiteSpace" : "activegrid.model.schema.XsdFacetWhiteSpace",
|
||||
}
|
||||
return agXsdToClassName
|
||||
|
||||
|
||||
@@ -121,6 +121,7 @@ class FindService(wx.lib.pydocview.DocService):
|
||||
self._findDialog = None
|
||||
|
||||
self._replaceDialog = FindReplaceDialog(self.GetDocumentManager().FindSuitableParent(), -1, _("Replace"), size=(320,200), findString=findString)
|
||||
self._replaceDialog.CenterOnParent()
|
||||
self._replaceDialog.Show(True)
|
||||
else:
|
||||
if self._replaceDialog != None:
|
||||
@@ -129,6 +130,7 @@ class FindService(wx.lib.pydocview.DocService):
|
||||
self._replaceDialog = None
|
||||
|
||||
self._findDialog = FindDialog(self.GetDocumentManager().FindSuitableParent(), -1, _("Find"), size=(320,200), findString=findString)
|
||||
self._findDialog.CenterOnParent()
|
||||
self._findDialog.Show(True)
|
||||
|
||||
|
||||
@@ -152,6 +154,7 @@ class FindService(wx.lib.pydocview.DocService):
|
||||
""" Display Goto Line Number dialog box """
|
||||
line = -1
|
||||
dialog = wx.TextEntryDialog(parent, _("Enter line number to go to:"), _("Go to Line"))
|
||||
dialog.CenterOnParent()
|
||||
if dialog.ShowModal() == wx.ID_OK:
|
||||
try:
|
||||
line = int(dialog.GetValue())
|
||||
@@ -356,7 +359,10 @@ class FindDialog(wx.Dialog):
|
||||
wx.EVT_BUTTON(self, FindService.FINDONE_ID, self.OnActionEvent)
|
||||
cancelBtn = wx.Button(self, wx.ID_CANCEL)
|
||||
wx.EVT_BUTTON(self, wx.ID_CANCEL, self.OnClose)
|
||||
buttonSizer.Add(findBtn, 0, wx.BOTTOM, HALF_SPACE)
|
||||
BTM_SPACE = HALF_SPACE
|
||||
if wx.Platform == "__WXMAC__":
|
||||
BTM_SPACE = SPACE
|
||||
buttonSizer.Add(findBtn, 0, wx.BOTTOM, BTM_SPACE)
|
||||
buttonSizer.Add(cancelBtn, 0)
|
||||
gridSizer.Add(buttonSizer, pos=(0,2), span=(3,1))
|
||||
|
||||
@@ -455,9 +461,14 @@ class FindReplaceDialog(FindDialog):
|
||||
wx.EVT_BUTTON(self, FindService.REPLACEONE_ID, self.OnActionEvent)
|
||||
replaceAllBtn = wx.Button(self, FindService.REPLACEALL_ID, _("Replace All"))
|
||||
wx.EVT_BUTTON(self, FindService.REPLACEALL_ID, self.OnActionEvent)
|
||||
buttonSizer.Add(findBtn, 0, wx.BOTTOM, HALF_SPACE)
|
||||
buttonSizer.Add(replaceBtn, 0, wx.BOTTOM, HALF_SPACE)
|
||||
buttonSizer.Add(replaceAllBtn, 0, wx.BOTTOM, HALF_SPACE)
|
||||
|
||||
BTM_SPACE = HALF_SPACE
|
||||
if wx.Platform == "__WXMAC__":
|
||||
BTM_SPACE = SPACE
|
||||
|
||||
buttonSizer.Add(findBtn, 0, wx.BOTTOM, BTM_SPACE)
|
||||
buttonSizer.Add(replaceBtn, 0, wx.BOTTOM, BTM_SPACE)
|
||||
buttonSizer.Add(replaceAllBtn, 0, wx.BOTTOM, BTM_SPACE)
|
||||
buttonSizer.Add(cancelBtn, 0)
|
||||
gridSizer.Add(buttonSizer, pos=(0,2), span=(3,1))
|
||||
|
||||
@@ -495,12 +506,24 @@ def getFindData():
|
||||
return \
|
||||
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
|
||||
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
|
||||
\x00\x00\x81IDAT8\x8d\xa5S\xc1\x16\xc0\x10\x0ckk\xff\xff\xc7d\x87\xad^U\r\
|
||||
\x93S\xe5U$\n\xb3$:\xc1e\x17(\x19Z\xb3$\x9e\xf1DD\xe2\x15\x01x\xea\x93\xef\
|
||||
\x04\x989\xea\x1b\xf2U\xc0\xda\xb4\xeb\x11\x1f:\xd8\xb5\xff8\x93\xd4\xa9\xae\
|
||||
@/S\xaaUwJ3\x85\xc0\x81\xee\xeb.q\x17C\x81\xd5XU \x1a\x93\xc6\x18\x8d\x90\
|
||||
\xe8}\x89\x00\x9a&\x9b_k\x94\x0c\xdf\xd78\xf8\x0b\x99Y\xb4\x08c\x9e\xfe\xc6\
|
||||
\xe3\x087\xf9\xd0D\x180\xf1#\x8e\x00\x00\x00\x00IEND\xaeB`\x82'
|
||||
\x00\x01\xb1IDAT8\x8d\xa5\x93=o\xd3P\x14\x86\x1f\xa7\x11\x95<\xdc\xc6\xecN+5\
|
||||
[\x86B\x99\xacLQ2Zr[\x89\xa1\xfd\x0b%\x95\x90\x00\xf1\x03\x80\x01\x98\x80\
|
||||
\x19G\xac\x0cm\xff@Y\xd9:\xd9Ck\x94\xd6\xddb\x94\x9b\x98\xc8\xd2e1C\xe5\x8b\
|
||||
\xdd\x14\x96\xbe\xdb=\x1f\xefy\xef\xf90\x8c\xda\x12wA\xbd\xfc\x18\xfa\x9fs\
|
||||
\x80\xf9|\x0e\xc0\x93\xc1\x81\x01\xf0\xe6\xf5\xab\x1c`:\x9d\x02\xf0\xf6\xdd{\
|
||||
\xa3\xc8\xa9\xddd\xec\xf5z\xb4Z\xeb\x00\x1c\x1f\x1d\xe6\x85\xdd\xf3<\x06\x83\
|
||||
\xc1\x82\xbd\xa2 \x0cCL\xd3d<\x1e\x13\xc71\xb6m\x030\x1a\x8d\x08\x82\x00\x80\
|
||||
\xb3\xb3s:\x9d\x8e\xce\xa9(h6\x9b8\x8e\x83m\xdb4\x1a\r\x82 \xe0\xc5\xf3g\xb9\
|
||||
eY\xb4\xdbm\x1c\xc7Y\xe8\x81&\xf8\xf4\xf1C\xde\xedv+\xce\x97Owx\xfc\xe8k\xc5\
|
||||
\xb6\xb7\xb7\x8b\xef\x0foW \x84\xe0\xea\xea\x02\xa5\x94n\x18\x80\x94\x92\xd9\
|
||||
l\x02@\x96e\x95>\xd4nVO\xd3\xb9\x0e\xba\r\xa6i\xd2\xef\xf7\xf0\xfd!\xc7G\x87\
|
||||
y\xed:)\xd5\x01J\xfd\xd6c\xfc~\x9a\xfc\x93\xe8\xf2\xf2\x02(Ma6\x9b \x84@)\
|
||||
\xa5\t}\xff\x0b\xd0\'I~R\x14\xca\xb2L\xfb\x97\x97\xef-\xeeA!_J\x89\xeb\xba\
|
||||
\xb8\xae\xab\xbf\x06\x7f\x97\xacP[\x87\xeb9\x0b!H\x92\ta\x18"\xa5\xd4U\xbd\
|
||||
\xadm\xe3\xe1\x83\x8d<\x8a~\x90\xa6\xbf\x88\xe3\x18)\xa5&\xa9\x03X\x96E\xab\
|
||||
\xb5\x8em7\xf5\xc2\x94\xb1\xba\xba\xc6\xe6\xe6\x06++\xf7\x89\xa2\xa8\xe2\xd3\
|
||||
=89\xf9Va.\x14\x14\xd8\xdf?X VJa\x14\xd7X\xde\xef2\xbc\xadm\xe3\x7f~\xe3\xae\
|
||||
\xe7\xfc\x07\x84;\xc5\x82\xa1m&\x95\x00\x00\x00\x00IEND\xaeB`\x82'
|
||||
|
||||
|
||||
def getFindBitmap():
|
||||
|
||||
@@ -17,45 +17,45 @@ import FindService
|
||||
_ = wx.GetTranslation
|
||||
|
||||
class TextDocument(wx.lib.docview.Document):
|
||||
|
||||
def __init__(self):
|
||||
wx.lib.docview.Document .__init__(self)
|
||||
self._inModify = False
|
||||
|
||||
|
||||
def OnSaveDocument(self, filename):
|
||||
def SaveObject(self, fileObject):
|
||||
view = self.GetFirstView()
|
||||
if not view.GetTextCtrl().SaveFile(filename):
|
||||
return False
|
||||
self.Modify(False)
|
||||
self.SetDocumentSaved(True)
|
||||
#if wx.Platform == "__WXMAC__":
|
||||
# fn = wx.Filename(filename)
|
||||
# fn.MacSetDefaultTypeAndCreator()
|
||||
fileObject.write(view.GetTextCtrl().GetValue())
|
||||
return True
|
||||
|
||||
|
||||
def OnOpenDocument(self, filename):
|
||||
def LoadObject(self, fileObject):
|
||||
view = self.GetFirstView()
|
||||
if not view.GetTextCtrl().LoadFile(filename):
|
||||
return False
|
||||
self.SetFilename(filename, True)
|
||||
self.Modify(False)
|
||||
self.UpdateAllViews()
|
||||
self._savedYet = True
|
||||
data = fileObject.read()
|
||||
view.GetTextCtrl().SetValue(data)
|
||||
return True
|
||||
|
||||
|
||||
def IsModified(self):
|
||||
view = self.GetFirstView()
|
||||
if view and view.GetTextCtrl():
|
||||
return wx.lib.docview.Document.IsModified(self) or view.GetTextCtrl().IsModified()
|
||||
else:
|
||||
return wx.lib.docview.Document.IsModified(self)
|
||||
return view.GetTextCtrl().IsModified()
|
||||
return False
|
||||
|
||||
|
||||
def Modify(self, mod):
|
||||
def Modify(self, modify):
|
||||
if self._inModify:
|
||||
return
|
||||
self._inModify = True
|
||||
|
||||
view = self.GetFirstView()
|
||||
wx.lib.docview.Document.Modify(self, mod)
|
||||
if not mod and view and view.GetTextCtrl():
|
||||
if not modify and view and view.GetTextCtrl():
|
||||
view.GetTextCtrl().DiscardEdits()
|
||||
|
||||
wx.lib.docview.Document.Modify(self, modify) # this must called be after the DiscardEdits call above.
|
||||
|
||||
self._inModify = False
|
||||
|
||||
|
||||
class TextView(wx.lib.docview.View):
|
||||
|
||||
@@ -75,6 +75,7 @@ class TextView(wx.lib.docview.View):
|
||||
sizer = wx.BoxSizer()
|
||||
font, color = self._GetFontAndColorFromConfig()
|
||||
self._textCtrl = self._BuildTextCtrl(frame, font, color = color)
|
||||
self._textCtrl.Bind(wx.EVT_TEXT, self.OnModify)
|
||||
sizer.Add(self._textCtrl, 1, wx.EXPAND, 0)
|
||||
frame.SetSizer(sizer)
|
||||
frame.Layout()
|
||||
@@ -83,6 +84,10 @@ class TextView(wx.lib.docview.View):
|
||||
return True
|
||||
|
||||
|
||||
def OnModify(self, event):
|
||||
self.GetDocument().Modify(True)
|
||||
|
||||
|
||||
def _BuildTextCtrl(self, parent, font, color = wx.BLACK, value = "", selection = [0, 0]):
|
||||
if self._wordWrap:
|
||||
wordWrapStyle = wx.TE_WORDWRAP
|
||||
@@ -131,6 +136,9 @@ class TextView(wx.lib.docview.View):
|
||||
|
||||
|
||||
def OnUpdate(self, sender = None, hint = None):
|
||||
if wx.lib.docview.View.OnUpdate(self, sender, hint):
|
||||
return
|
||||
|
||||
if hint == "Word Wrap":
|
||||
self.SetWordWrap(wx.ConfigBase_Get().ReadInt("TextEditorWordWrap", True))
|
||||
elif hint == "Font":
|
||||
|
||||
+53
-20
@@ -6,7 +6,7 @@
|
||||
#
|
||||
# Created: 5/15/03
|
||||
# CVS-ID: $Id$
|
||||
# Copyright: (c) 2003-2005 ActiveGrid, Inc. (Port of wxWindows classes by Julian Smart et al)
|
||||
# Copyright: (c) 2003-2006 ActiveGrid, Inc. (Port of wxWindows classes by Julian Smart et al)
|
||||
# License: wxWindows license
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
@@ -214,8 +214,10 @@ class Document(wx.EvtHandler):
|
||||
false otherwise. You may need to override this if your document view
|
||||
maintains its own record of being modified (for example if using
|
||||
xTextWindow to view and edit the document).
|
||||
This method has been extended to notify its views that the dirty flag has changed.
|
||||
"""
|
||||
self._documentModified = modify
|
||||
self.UpdateAllViews(hint=("modify", self, self._documentModified))
|
||||
|
||||
|
||||
def SetDocumentModificationDate(self):
|
||||
@@ -236,6 +238,16 @@ class Document(wx.EvtHandler):
|
||||
return self._documentModificationDate
|
||||
|
||||
|
||||
def IsDocumentModificationDateCorrect(self):
|
||||
"""
|
||||
Returns False if the file has been modified outside of the application.
|
||||
This method has been added to wxPython and is not in wxWindows.
|
||||
"""
|
||||
if not os.path.exists(self.GetFilename()): # document must be in memory only and can't be out of date
|
||||
return True
|
||||
return self._documentModificationDate == os.path.getmtime(self.GetFilename())
|
||||
|
||||
|
||||
def GetViews(self):
|
||||
"""
|
||||
Returns the list whose elements are the views on the document.
|
||||
@@ -271,6 +283,7 @@ class Document(wx.EvtHandler):
|
||||
Destructor. Removes itself from the document manager.
|
||||
"""
|
||||
self.DeleteContents()
|
||||
self._documentModificationDate = None
|
||||
if self.GetDocumentManager():
|
||||
self.GetDocumentManager().RemoveDocument(self)
|
||||
wx.EvtHandler.Destroy(self)
|
||||
@@ -364,7 +377,7 @@ class Document(wx.EvtHandler):
|
||||
return True
|
||||
|
||||
""" check for file modification outside of application """
|
||||
if os.path.exists(self.GetFilename()) and os.path.getmtime(self.GetFilename()) != self.GetDocumentModificationDate():
|
||||
if not self.IsDocumentModificationDateCorrect():
|
||||
msgTitle = wx.GetApp().GetAppName()
|
||||
if not msgTitle:
|
||||
msgTitle = _("Application")
|
||||
@@ -485,9 +498,9 @@ class Document(wx.EvtHandler):
|
||||
self.GetDocumentWindow())
|
||||
return False
|
||||
|
||||
self.SetDocumentModificationDate()
|
||||
self.SetFilename(filename, True)
|
||||
self.Modify(False)
|
||||
self.SetDocumentModificationDate()
|
||||
self.SetDocumentSaved(True)
|
||||
#if wx.Platform == '__WXMAC__': # Not yet implemented in wxPython
|
||||
# wx.FileName(file).MacSetDefaultTypeAndCreator()
|
||||
@@ -529,9 +542,9 @@ class Document(wx.EvtHandler):
|
||||
self.GetDocumentWindow())
|
||||
return False
|
||||
|
||||
self.SetDocumentModificationDate()
|
||||
self.SetFilename(filename, True)
|
||||
self.Modify(False)
|
||||
self.SetDocumentModificationDate()
|
||||
self.SetDocumentSaved(True)
|
||||
self.UpdateAllViews()
|
||||
return True
|
||||
@@ -614,7 +627,7 @@ class Document(wx.EvtHandler):
|
||||
return True
|
||||
|
||||
""" check for file modification outside of application """
|
||||
if os.path.exists(self.GetFilename()) and os.path.getmtime(self.GetFilename()) != self.GetDocumentModificationDate():
|
||||
if not self.IsDocumentModificationDateCorrect():
|
||||
msgTitle = wx.GetApp().GetAppName()
|
||||
if not msgTitle:
|
||||
msgTitle = _("Warning")
|
||||
@@ -844,8 +857,14 @@ class View(wx.EvtHandler):
|
||||
unused but may in future contain application-specific information for
|
||||
making updating more efficient.
|
||||
"""
|
||||
pass
|
||||
|
||||
if hint:
|
||||
if hint[0] == "modify": # if dirty flag changed, update the view's displayed title
|
||||
frame = self.GetFrame()
|
||||
if frame and hasattr(frame, "OnTitleIsModified"):
|
||||
frame.OnTitleIsModified()
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def OnChangeFilename(self):
|
||||
"""
|
||||
@@ -916,11 +935,11 @@ class View(wx.EvtHandler):
|
||||
Call this from your view frame's OnActivate member to tell the
|
||||
framework which view is currently active. If your windowing system
|
||||
doesn't call OnActivate, you may need to call this function from
|
||||
any place where you know the view must be active, and
|
||||
OnMenuCommand or any place where you know the view must be active, and
|
||||
the framework will need to get the current view.
|
||||
|
||||
The prepackaged view frame wxDocChildFrame calls wxView.Activate from
|
||||
its OnActivate member.
|
||||
its OnActivate member and from its OnMenuCommand member.
|
||||
"""
|
||||
if self.GetDocument() and self.GetDocumentManager():
|
||||
self.OnActivateView(activate, self, self.GetDocumentManager().GetCurrentView())
|
||||
@@ -1865,7 +1884,7 @@ class DocManager(wx.EvtHandler):
|
||||
for document in self._docs:
|
||||
if document.GetFilename() and os.path.normcase(document.GetFilename()) == os.path.normcase(path):
|
||||
""" check for file modification outside of application """
|
||||
if os.path.exists(path) and os.path.getmtime(path) != document.GetDocumentModificationDate():
|
||||
if not document.IsDocumentModificationDateCorrect():
|
||||
msgTitle = wx.GetApp().GetAppName()
|
||||
if not msgTitle:
|
||||
msgTitle = _("Warning")
|
||||
@@ -2148,7 +2167,7 @@ class DocManager(wx.EvtHandler):
|
||||
if len(descr) > 0:
|
||||
descr = descr + _('|')
|
||||
descr = descr + temp.GetDescription() + _(" (") + temp.GetFileFilter() + _(") |") + temp.GetFileFilter() # spacing is important, make sure there is no space after the "|", it causes a bug on wx_gtk
|
||||
descr = _("All (*.*)|*.*|%s") % descr # spacing is important, make sure there is no space after the "|", it causes a bug on wx_gtk
|
||||
descr = _("All|*.*|%s") % descr # spacing is important, make sure there is no space after the "|", it causes a bug on wx_gtk
|
||||
else:
|
||||
descr = _("*.*")
|
||||
|
||||
@@ -2791,6 +2810,7 @@ class DocMDIChildFrame(wx.MDIChildFrame):
|
||||
self._childView.Activate(event.GetActive())
|
||||
self._activated = 0
|
||||
|
||||
|
||||
def OnCloseWindow(self, event):
|
||||
"""
|
||||
Closes and deletes the current view and document.
|
||||
@@ -2846,6 +2866,28 @@ class DocMDIChildFrame(wx.MDIChildFrame):
|
||||
self._childView = view
|
||||
|
||||
|
||||
def OnTitleIsModified(self):
|
||||
"""
|
||||
Add/remove to the frame's title an indication that the document is dirty.
|
||||
If the document is dirty, an '*' is appended to the title
|
||||
This method has been added to wxPython and is not in wxWindows.
|
||||
"""
|
||||
title = self.GetTitle()
|
||||
if title:
|
||||
if self.GetDocument().IsModified():
|
||||
if title.endswith("*"):
|
||||
return
|
||||
else:
|
||||
title = title + "*"
|
||||
self.SetTitle(title)
|
||||
else:
|
||||
if title.endswith("*"):
|
||||
title = title[:-1]
|
||||
self.SetTitle(title)
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
class DocPrintout(wx.Printout):
|
||||
"""
|
||||
DocPrintout is a default Printout that prints the first page of a document
|
||||
@@ -2892,15 +2934,6 @@ class DocPrintout(wx.Printout):
|
||||
return pageNum == 1
|
||||
|
||||
|
||||
def OnBeginDocument(self, startPage, endPage):
|
||||
"""
|
||||
Not quite sure why this was overridden, but it was in wxWindows! :)
|
||||
"""
|
||||
if not wx.Printout.OnBeginDocument(self, startPage, endPage):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def GetPageInfo(self):
|
||||
"""
|
||||
Indicates that the DocPrintout only has a single page.
|
||||
|
||||
+331
-177
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user