1
#-----------------------------------------------------------------------------
2
# Name: ZopeExplorer.py
5
# Author: Riaan Booysen & Robert Boulanger
8
# RCS-ID: $Id: ZopeExplorer.py,v 1.17 2007/07/02 15:01:17 riaan Exp $
9
# Copyright: (c) 2001 - 2007
11
#-----------------------------------------------------------------------------
12
print 'importing ZopeLib.ZopeExplorer'
14
import os, urllib, urlparse, time, socket
15
from thread import start_new_thread
19
from Explorers import ExplorerNodes
20
from Models import EditorHelper, Controllers
21
from ExternalLib import xmlrpclib, BasicAuthTransport
22
from Preferences import IS
23
import Utils, Preferences
24
import Views, Views.SourceViews, Views.PySourceView
27
import ZopeEditorModels, ZopeViews, Client, ExtMethDlg
28
from ZopeCompanions import ZopeConnection, ZopeCompanion, FolderZC
30
# XXX Add owner property
32
# XXX root attribute is no longer really necessary
33
# XXX Improve '/' management ;)
35
class ZopeEClip(ExplorerNodes.ExplorerClipboard):
36
def __init__(self, globClip, props):
37
ExplorerNodes.ExplorerClipboard.__init__(self, globClip)
41
self.zc = ZopeConnection()
42
self.zc.connect(props['host'], props['httpport'],
43
props['username'], props['passwd'])
44
def callAndSetRef(self, objpath, method, nodes):
45
names = [n.name for n in nodes]
46
mime, res = self.zc.call(objpath, method, ids = names)
47
self.clipRef = mime.get('Set-Cookie').split('"')[1]
48
def clipCut(self, node, nodes):
49
ExplorerNodes.ExplorerClipboard.clipCut(self, node, nodes)
50
self.callAndSetRef(node.resourcepath, 'manage_cutObjects', nodes)
51
def clipCopy(self, node, nodes):
52
ExplorerNodes.ExplorerClipboard.clipCopy(self, node, nodes)
53
self.callAndSetRef(node.resourcepath, 'manage_copyObjects', nodes)
54
# def clipPaste(self, node):
55
# ExplorerNodes.ExplorerClipboard.clipPaste(self, node)
57
def clipPaste_ZopeEClip(self, node, nodes, mode):
58
mime, res = self.zc.call(node.resourcepath,
59
'manage_pasteObjects', cb_copy_data = self.clipRef)
61
def clipPaste_FileSysExpClipboard(self, node, nodes, mode):
64
node.newFolder(file.name)
65
folderNode = node.createChildNode('Folder', file.name)
66
self.clipPaste_FileSysExpClipboard(folderNode,
67
file.openList(), mode)
69
node.uploadFromFS(file)
71
class ZopeCatNode(ExplorerNodes.CategoryNode):
72
protocol = 'config.zope'
76
defaultStruct = {'host': 'localhost',
84
def __init__(self, globClip, config, parent, bookmarks):
85
ExplorerNodes.CategoryNode.__init__(self, 'Zope', ('explorer', 'zope'),
87
self.globClip = globClip
88
self.bookmarks = bookmarks
90
def createChildNode(self, name, props):
91
# Zope clipboards should be global but unique on site / user
92
clipboard = ZopeEClip(self.globClip, props)
93
zin = ZopeItemNode('', props['path'], clipboard,
94
EditorHelper.imgZopeConnection, self, None, None, props, 'Folder')
97
zin.bookmarks = self.bookmarks
100
def createCatCompanion(self, catNode):
101
comp = ExplorerNodes.CategoryDictCompanion(catNode.treename, self)
104
class ZopeItemNode(ExplorerNodes.ExplorerNode):
106
Model = ZopeEditorModels.ZopeBlankEditorModel
108
additionalViews = (ZopeViews.ZopeSecurityView,
109
ZopeViews.ZopeUndoView)
112
def __init__(self, name, resourcepath, clipboard, imgIdx, parent, xmlrpcsvr,
113
root, properties, metatype):
114
ExplorerNodes.ExplorerNode.__init__(self, name, resourcepath, clipboard,
115
imgIdx, None, properties)
116
self.metatype = metatype
120
self.server = xmlrpcsvr
126
return '%s://%s/<%s>%s'%(self.protocol, self.category, self.metatype, self.getTitle())
129
path = urllib.quote(self.resourcepath)
137
return '%(host)s:%(httpport)d' % self.properties + path
144
def canAdd(self, paletteName):
145
return paletteName == 'Zope'
147
def createChildNode(self, metatype, id, respath=None):
149
respath = self.resourcepath
152
tmppath = respath + self.itemsSubPath + id
154
tmppath = respath + self.itemsSubPath + '/' + id
156
itm = self.checkentry(id, metatype, tmppath)
158
itm.imgIdx = ZopeEditorModels.ZOAIcons.get(metatype,
159
ZopeEditorModels.ZOAIcons['unknown'])
160
itm.category = self.category
161
itm.bookmarks = self.bookmarks
164
def checkentry(self, name, metatype, path):
165
ZopeNodeClass = zopeClassMap.get(metatype, ZopeItemNode)
166
return ZopeNodeClass(*(name, path, self.clipboard, -1, self,
167
self.server, self.root, self.properties, metatype))
169
def whole_name(self):
170
return self.resourcepath
172
def getResource(self, url=''):
174
url = self.buildUrl()
175
return getServer(url, self.properties['username'],
176
self.properties['passwd'])
178
def getParentResource(self):
179
path, name = os.path.split(self.name)
180
return self.getResource(os.path.dirname(self.buildUrl())), name
182
def openList(self, root = None):
183
url = self.buildUrl()+self.itemsSubPath
186
self.server = self.getResource(url)
188
self.entries, self.entryIds = self.server.zoa.items()
189
except xmlrpclib.Fault, error:
191
# see if zoa object is installed
193
Client.call('http://%s/zoa'%self.buildUrl(),
194
self.properties['username'], self.properties['passwd'],
196
except Client.NotFound:
198
'The zoa object not found in the root of your Zope tree.\n\n'
199
'Do you want to install it?', 'Install zoa',
200
wx.YES_NO | wx.ICON_QUESTION) == wx.YES:
203
conninfo = ('http://%s'%self.buildUrl(),
204
self.properties['username'], self.properties['passwd'])
205
ZoaClient.installFromFS(conninfo,
206
os.path.join(Preferences.pyPath, 'ZopeLib', 'zoa', ))
208
# try again, if this fails the real error should break thru
209
self.entries, self.entryIds = self.server.zoa.items()
212
err = error.faultString
213
raise zopeHtmlErr2Strs(err)
218
for i in range(len(self.entries)):
219
z = self.createChildNode(self.entries[i], self.entryIds[i] )
222
self.cache[self.entryIds[i]] = z
225
def isFolderish(self):
229
return self.resourcepath
231
def open(self, editor):
232
return editor.openOrGotoZopeDocument(self)
234
def deleteItems(self, names):
235
mime, res = self.clipboard.zc.call(self.resourcepath,
236
'manage_delObjects', ids = names)
238
def renameItem(self, name, newName):
239
mime, res = self.clipboard.zc.call(self.resourcepath,
240
'manage_renameObject', id = name, new_id = newName)
243
mime, res = self.clipboard.zc.call(os.path.dirname(self.resourcepath),
244
'manage_exportObject', download = 1, id = self.name)
247
def uploadObj(self, content):
248
mime, res = self.clipboard.zc.call(self.resourcepath,
249
'manage_upload', file = content)
252
def listImportFiles(self):
253
if self.properties.has_key('localpath') and self.properties['localpath']:
254
from Explorers import Explorer
255
return Explorer.listdirEx(self.properties['localpath']+'/import', '.zexp')
259
def importObj(self, name):
261
mime, res = self.clipboard.zc.call(self.resourcepath, 'manage_importObject', file = name)
262
except Exception, message:
263
wx.MessageBox(`message.args`, 'Error on import')
266
def newItem(self, name, Compn, getNewValidName = True):
267
props = self.properties
269
name = Utils.getValidName(self.cache.keys(), name)
270
cmp = Compn(name, self.resourcepath, props.get('localpath', ''))
271
cmp.connect(props['host'], props['httpport'],
272
props['username'], props['passwd'])
277
def getUndoableTransactions(self):
278
from ZopeLib.DateTime import DateTime
279
svr, name = self.getParentResource()
280
return eval(svr.zoa.undo(name), {})
282
def undoTransaction(self, transactionIds):
283
self.getResource().manage_undo_transactions(transactionIds)
285
def getPermissions(self):
286
return self.getResource().permission_settings()#ZOA('permissions')
289
return self.getResource().valid_roles()
291
def load(self, mode='rb'):
292
return ''#return self.getResource().document_src()
295
def save(self, filename, data, mode='wb'):
296
""" Saves contents of data to Zope """
297
pass#self.getResource().manage_upload(data)
299
def newFolder(self, name):
300
self.getResource().manage_addFolder(name)
302
def newBlankDocument(self, name=''):
304
self.getResource().manage_addDTMLDocument(name)
305
except xmlrpclib.ProtocolError, error:
306
if error.errcode != 302:
309
def uploadFromFS(self, filenode):
310
props = self.properties
311
from ExternalLib.WebDAV.client import Resource
312
r = Resource(('http://%(host)s:%(httpport)s/'+self.resourcepath+'/'+\
313
filenode.name) % props, props['username'], props['passwd'])
314
r.put(filenode.load())
316
def downloadToFS(self, filename):
317
open(filename, 'wb').write(self.getResource().manage_FTPget())
319
def getNodeFromPath(self, respath, metatype):
320
return self.createChildNode(metatype, os.path.basename(respath),
321
os.path.dirname(respath))
323
def findItems(self, obj_ids=(), obj_metatypes=None, obj_searchterm=None,
325
# silly xml-rpc restrictions
326
if obj_metatypes is None: obj_metatypes=0
327
if obj_searchterm is None: obj_searchterm=0
328
if not search_sub: search_sub=''
330
return self.getResource().zoa.find(obj_ids, obj_metatypes, obj_searchterm)
333
(wxID_ZOPEEXPORT, wxID_ZOPEIMPORT, wxID_ZOPEINSPECT, wxID_ZOPEOPENINEDITOR,
334
wxID_ZOPEUPLOAD, wxID_ZOPESECURITY, wxID_ZOPEUNDO, wxID_ZOPEVIEWBROWSER,
335
wxID_ZCCSTART, wxID_ZCCRESTART, wxID_ZCCSHUTDOWN, wxID_ZCCTEST, wxID_ZCCOPENLOG,
336
wxID_ZACONFZ2, wxID_ZOPEMANAGEBROWSER, wxID_ZOPEFIND,
337
wxID_ZCOPENZ2, wxID_ZCBREAKINTO,
338
) = Utils.wxNewIds(18)
340
class ZopeCatController(ExplorerNodes.CategoryController):
341
protocol = 'config.zope'
342
zopeStatupTimeout = 60 # default when not read from property
343
zopeRunning = 'The server is available'
344
err_zopeNotRunning = 'The server is not running'
345
err_localpathBlank = 'The "localpath" property must be defined'
346
def __init__(self, editor, list, inspector, controllers, menuDefs = []):
347
zccMenuDef = [ (-1, '-', None, '-'),
348
(wxID_ZCCSTART, 'Start', self.OnStart, '-'),
349
(wxID_ZCCRESTART, 'Restart', self.OnRestart, '-'),
350
(wxID_ZCCSHUTDOWN, 'Shutdown', self.OnShutdown, '-'),
351
(wxID_ZCCTEST, 'Test', self.OnTest, '-'),
352
(-1, '-', None, '-'),
353
(wxID_ZCCOPENLOG, 'Open Zope log', self.OnOpenZopeLog, '-'),
354
# (wxID_ZACONFZ2, 'Configure z2.py', self.OnConfigureZ2py, '-'),
355
(-1, '-', None, '-'),
356
(wxID_ZCOPENZ2, 'Open z2.py', self.OnOpenZ2, '-'),
357
(wxID_ZCBREAKINTO, 'Break into', self.OnBreakInto, '-'),
359
ExplorerNodes.CategoryController.__init__(self, editor, list, inspector,
360
controllers, menuDefs = menuDefs + zccMenuDef)
362
def checkAvailability(self, props, timeout=10, showDlg=True):
367
if showDlg and not dlg:
368
dlg = wx.ProgressDialog('Testing %s'% props['host'],
369
'Checking availability...', 100, self.editor,
370
wx.PD_CAN_ABORT | wx.PD_APP_MODAL | wx.PD_AUTO_HIDE)
374
while not timeout or time.time() < now + timeout:
375
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
377
s.connect( (props['host'], props['httpport']) )
378
except socket.error, err:
381
res = self.err_zopeNotRunning
382
if time.time() > now + timeout and \
383
wx.MessageBox('Keep checking for Zope to become available',
384
'Retry?', style=wx.YES_NO | wx.ICON_QUESTION) == wx.YES:
387
res = 'Socket error: '+err[1]
389
res = self.zopeRunning
399
def getControlPanel(self, props):
400
return getServer('%(host)s:%(httpport)d/Control_Panel' % props,
401
props['username'], props['passwd'])
403
def callControlPanelMethod(self, props, meth):
404
zc = ZopeConnection()
405
zc.connect(props['host'], props['httpport'],
406
props['username'], props['passwd'])
407
zc.call('/Control_Panel', meth)
409
def OnStart(self, event):
410
for node in self.getNodesForSelection(self.list.getMultiSelection()):
411
props = node.properties
412
try: zopeStatupTimeout = props['startuptimeout']
413
except KeyError: zopeStatupTimeout = self.zopeStatupTimeout
415
if props['servicename']:
416
os.system('net start "%s"'%props['servicename'])
417
self.checkAvailability(node.properties, zopeStatupTimeout)
418
elif props['localpath']:
419
if props['localpath'].find(' ') != -1:
420
wx.LogError('Localpath property may not contain spaces (use SHORT~1 version if necessary)')
422
os.system('start %s\\start.bat'%props['localpath'])
423
self.checkAvailability(node.properties, zopeStatupTimeout)
425
wx.LogError('Unable to start '+node.treename)
427
def OnRestart(self, event):
428
for node in self.getNodesForSelection(self.list.getMultiSelection()):
429
props = node.properties
430
try: zopeStatupTimeout = props['startuptimeout']
431
except KeyError: zopeStatupTimeout = self.zopeStatupTimeout
433
self.callControlPanelMethod(node.properties, 'manage_restart')
434
resp = self.checkAvailability(node.properties, zopeStatupTimeout)
435
if resp == 'The server is available':
436
self.editor.setStatus(resp)
438
self.editor.setStatus(resp, 'Warning')
439
except Exception, error:
440
wx.LogError('Restart not supported for '+node.treename+'\n'+str(error))
442
def OnShutdown(self, event):
443
for node in self.getNodesForSelection(self.list.getMultiSelection()):
444
self.callControlPanelMethod(node.properties, 'manage_shutdown')
446
def OnTest(self, event):
447
for node in self.getNodesForSelection(self.list.getMultiSelection()):
448
wx.LogMessage( '%s : %s' % (node.treename,
449
self.checkAvailability(node.properties, 0)))
451
def OnOpenZopeLog(self, event):
452
for node in self.getNodesForSelection(self.list.getMultiSelection()):
453
props = node.properties
454
if props['localpath']:
455
self.editor.openOrGotoModule(os.path.join(props['localpath'],
458
wx.LogError(self.err_localpathBlank)
460
def OnConfigureZ2py(self, event):
461
# XXX Disabled for now until only useful values are displayed
462
# XXX Or until someone complains :)
463
node = self.getNodesForSelection(self.list.getMultiSelection())
467
print 'Nothing selected'
469
props = node.properties
470
if props['localpath']:
471
cfgZ2SrcNode = ZopeZ2pySourceBasedPrefColNode('Z2.py',
472
('*',), props['localpath']+'/z2.py', -1, node)
473
cfgZ2SrcNode.open(self.editor)
475
wx.LogError(self.err_localpathBlank)
477
def OnOpenZ2(self, event):
478
for node in self.getNodesForSelection(self.list.getMultiSelection()):
479
localpath = node.properties['localpath']
481
self.editor.openOrGotoModule(localpath+'/z2.py')
483
wx.LogError(self.err_localpathBlank)
485
def breakpointInBackground(self, zc):
486
zc.call('zoa', 'breakpoint')
488
def OnBreakInto(self, event):
489
for node in self.getNodesForSelection(self.list.getMultiSelection()):
490
props = node.properties
491
zc = ZopeConnection()
492
zc.connect(props['host'], props['httpport'],
493
props['username'], props['passwd'])
494
start_new_thread(self.breakpointInBackground, (zc,))
497
# XXX Better field validation and hints as to when path props shound end in / or not !!
499
class ZopeController(ExplorerNodes.Controller, ExplorerNodes.ClipboardControllerMix):
500
inspectBmp = 'Images/Shared/Inspector.png'
501
importBmp = 'Images/Shared/ZopeImport.png'
502
exportBmp = 'Images/Shared/ZopeExport.png'
503
uploadBmp = 'Images/ZOA/upload_doc.png'
504
viewInBrowserBmp = 'Images/ZOA/ViewInBrowser.png'
505
findBmp = 'Images/Shared/Find.png'
506
def __init__(self, editor, list, inspector, controllers):
507
ExplorerNodes.ClipboardControllerMix.__init__(self)
508
ExplorerNodes.Controller.__init__(self, editor)
511
self.menu = wx.Menu()
512
self.inspector = inspector
515
(wxID_ZOPEINSPECT, 'Inspect', self.OnInspectItem, self.inspectBmp),
516
(-1, '-', None, '') ] +\
518
[ (-1, '-', None, ''),
519
(wxID_ZOPEFIND, 'Find', self.OnFindZopeItems, self.findBmp),
521
(wxID_ZOPEUPLOAD, 'Upload', self.OnUploadZopeItem, self.uploadBmp),
522
(wxID_ZOPEEXPORT, 'Export', self.OnExportZopeItem, self.exportBmp),
523
(wxID_ZOPEIMPORT, 'Import', self.OnImportZopeItem, self.importBmp),
524
(-1, '-', None, '-'),
525
(wxID_ZOPEOPENINEDITOR, 'Open in Editor', self.OnOpenInEditorZopeItem, '-'),
526
(wxID_ZOPESECURITY, 'Security', self.OnSecurityZopeItem, '-'),
527
(wxID_ZOPEUNDO, 'Undo', self.OnUndoZopeItem, '-'),
529
(wxID_ZOPEVIEWBROWSER,'View in browser', self.OnViewInBrowser, self.viewInBrowserBmp),
530
(wxID_ZOPEMANAGEBROWSER,'Manage in browser', self.OnManageInBrowser, '-'),
533
self.setupMenu(self.menu, self.list, self.zopeMenuDef)
534
self.toolbarMenus = [self.zopeMenuDef]
537
ExplorerNodes.ClipboardControllerMix.destroy(self)
538
self.zopeMenuDef = ()
539
self.toolbarMenus = ()
542
def OnExportZopeItem(self, event):
544
idxs = self.list.getMultiSelection()
547
item = self.list.items[idx]
549
zexp = item.exportObj()
551
from FileDlg import wxFileDialog
552
dlg = wxFileDialog(self.list, 'Save as...', currPath,
553
item.name+'.zexp', '', wx.SAVE | wx.OVERWRITE_PROMPT)
555
if dlg.ShowModal() == wx.ID_OK:
556
zexpFile = dlg.GetFilePath()
557
open(zexpFile, 'wb').write(zexp)
558
currPath = os.path.dirname(zexpFile)
562
def OnImportZopeItem(self, event):
563
fls = self.list.node.listImportFiles()
566
dlg = wx.SingleChoiceDialog(self.list, 'Choose the file to import', 'Import object', fls)
568
if dlg.ShowModal() == wx.ID_OK:
569
zexp = dlg.GetStringSelection()
575
dlg = wx.TextEntryDialog(self.list, 'Enter file to import', 'Import object', '.zexp')
577
if dlg.ShowModal() == wx.ID_OK:
578
zexp = dlg.GetValue()
584
self.list.node.importObj(zexp)
585
self.list.refreshCurrent()
587
def doInspectZopeItem(self, zopeItem):
588
props = zopeItem.properties
590
ZComp = PaletteStore.compInfo[zopeItem.metatype][1]
592
ZComp = ZopeCompanion
594
zc = ZComp(zopeItem.name, zopeItem.resourcepath)
595
zc.connect(props['host'], props['httpport'],
596
props['username'], props['passwd'])
599
self.inspector.selectObject(zc, False, focusPage=1)
601
def OnInspectItem(self, event):
603
# Create new companion for selection
604
zopeItem = self.list.getSelection()
605
if not zopeItem: zopeItem = self.list.node
606
self.doInspectZopeItem(zopeItem)
608
def OnUploadZopeItem(self, event):
610
idxs = self.list.getMultiSelection()
613
item = self.list.items[idx]
615
from FileDlg import wxFileDialog
616
dlg = wxFileDialog(self.list, 'Upload '+item.name, currPath,
617
item.name, '', wx.OPEN)
619
if dlg.ShowModal() == wx.ID_OK:
621
# XXX Update to handle all transports
622
item.uploadObj(open(dlg.GetFilePath(), 'rb'))#.read())
623
except Client.NotFound:
624
wx.MessageBox('Object does not support uploading', 'Error on upload')
625
currPath = dlg.GetDirectory()
629
def OnSecurityZopeItem(self, event):
631
zopeItem = self.list.getSelection()
633
model, cntrlr = self.editor.openOrGotoZopeDocument(zopeItem)
634
viewName = ZopeViews.ZopeSecurityView.viewName
635
if not model.views.has_key(viewName):
636
resultView = self.editor.addNewView(viewName,
637
ZopeViews.ZopeSecurityView)
639
resultView = model.views[viewName]
643
def OnUndoZopeItem(self, event):
645
zopeItem = self.list.getSelection()
646
if zopeItem and ZopeViews.ZopeUndoView in zopeItem.additionalViews:
647
model, cntrlr = self.editor.openOrGotoZopeDocument(zopeItem)
648
viewName = ZopeViews.ZopeUndoView.viewName
649
if not model.views.has_key(viewName):
650
resultView = self.editor.addNewView(viewName,
651
ZopeViews.ZopeUndoView)
653
resultView = model.views[viewName]
657
def openSelItemInBrowser(self, addToUrl='', zopeItem=None):
660
zopeItem = self.list.getSelection()
663
raise Exception, 'No item selected'
666
webbrowser.open('http://%s%s'%(zopeItem.buildUrl(), addToUrl))
668
raise Exception, 'Python 2.0 or higher required'
670
def OnViewInBrowser(self, event):
671
self.openSelItemInBrowser()
673
def OnManageInBrowser(self, event):
674
self.openSelItemInBrowser('/manage')
676
def OnOpenInEditorZopeItem(self, event):
678
zopeItem = self.list.getSelection()
680
model, cntrlr = self.editor.openOrGotoZopeDocument(zopeItem)
682
def OnFindZopeItems(self, event):
683
node = self.list.node
685
from ZopeFindDlg import ZopeFindDlg
686
dlg = ZopeFindDlg(self.editor)
688
if dlg.ShowModal() == wx.ID_OK:
689
res = dlg.objIds.GetValue().split(',') or ()
696
search_text = dlg.searchText.GetValue() or 0
697
search_sub = dlg.recurse.GetValue()
701
results = node.findItems(obj_ids, meta_type,
702
search_text, search_sub)
706
bookmarks, category = node.bookmarks, node.category
707
self.list.node = node = ZopeResultsFolderNode(
708
'Zope Find Results', node.resourcepath,
709
node.clipboard, -1, node, node.server, node.root,
710
node.properties, 'Zope Find Results')
711
node.bookmarks = bookmarks
712
node.category = category
714
node.results = results
715
#node.lastSearch = dlg.GetValue()
717
# Collapse possible current contents in tree
718
tree = self.editor.explorer.tree
719
item = tree.GetSelection()
720
tree.CollapseAndReset(item)
722
self.list.refreshCurrent()
728
def getServer(url, user, password):
729
return xmlrpclib.Server('http://' + url,
730
BasicAuthTransport.BasicAuthTransport(user, password) )
732
class ZopeNode(ZopeItemNode):
733
def load(self, mode='rb'):
734
return self.getResource().document_src()
736
def save(self, filename, data, mode='wb'):
737
""" Saves contents of data to Zope """
738
self.getResource().manage_upload(data)
740
def isFolderish(self):
743
class ZopeImageNode(ZopeNode):
746
class DirNode(ZopeItemNode): pass
748
class UserFolderNode(ZopeItemNode):
749
def deleteItems(self, names):
750
print 'User Folder delete: %s'%names
751
# mime, res = self.clipboard.zc.call(self.resourcepath,
752
# 'manage_delObjects', ids = names)
754
class ZopeUserNode(ZopeNode):
755
def isFolderish(self):
757
def open(self, editor):
758
print 'Should inspect'
759
#editor.openOrGotoZopeDocument(self)
761
class ControlNode(DirNode):
762
def checkentry(self, id, entry, path):
763
if entry == 'Product Management':
764
childnode = PMNode(id, path, self.clipboard, -1, self,
765
self.server, self.root, self.properties, entry)
767
childnode = DirNode.checkentry(self, id, entry, path)
770
class PMNode(ControlNode):
771
def checkentry(self,id,entry,path):
772
if entry == 'Product' :
773
childnode = ProductNode(id, path, self.clipboard, -1, self,
774
self.server, self.root, self.properties, entry)
776
childnode = ControlNode.checkentry(self, id, entry, path)
779
class ProductNode(DirNode):
780
def checkentry(self, id, entry, path):
781
if entry == 'Z Class' :
782
childnode = ZClassNode(id, path, self.clipboard, -1, self,
783
self.server, self.root, self.properties, entry)
785
childnode = DirNode.checkentry(self, id, entry, path)
788
class ZClassNode(DirNode):
789
itemsSubPath = '/propertysheets/methods'
790
## def __init__(self, name, resourcepath, clipboard, imgIdx, parent, xmlrpcsvr, root, properties, metatype):
791
## resourcepath = resourcepath + '/propertysheets/methods'
792
## DirNode.__init__(self, name, resourcepath, clipboard, imgIdx, parent,
793
## xmlrpcsvr, root, properties, metatype)
795
# Thanks to M. Adam Kendall (akendall) for fixing save
796
class ZSQLNode(ZopeNode):
797
Model = ZopeEditorModels.ZopeSQLMethodModel
798
defaultViews = (ZopeViews.ZopeHTMLSourceView,)
799
additionalViews = (ZopeViews.ZopeSecurityView, ZopeViews.ZopeUndoView)
800
def getParams(self, data):
801
return data.split('<params>')[1].split('</params>')[0]
802
def getBody(self, data):
803
return data.split('</params>')[1].lstrip()
804
def save(self, filename, data, mode='wb'):
805
""" Saves contents of data to Zope """
806
props = self.getResource().zoa.props.SQLMethod()
808
title = props['title']
809
connection_id = props['connection_id']
810
arguments = self.getParams(data)
811
template = self.getBody(data)
812
self.getResource().manage_edit(title, connection_id, arguments, template)
813
except xmlrpclib.ProtocolError, error:
814
# Getting a zero content warning is not an error
815
if error.errcode != 204:
816
raise ExplorerNodes.TransportSaveError(error, filename)
817
except Exception, error:
818
raise ExplorerNodes.TransportSaveError(error, filename)
820
class PythonNode(ZopeNode):
821
Model = ZopeEditorModels.ZopePythonScriptModel
822
defaultViews = (Views.PySourceView.PythonSourceView,)
823
additionalViews = (ZopeViews.ZopeSecurityView, Views.EditorViews.ToDoView,
824
ZopeViews.ZopeUndoView)
826
def getParams(self, data):
827
return data[data.find('(')+1 : data.find('):')]
829
def getBody(self, data):
830
tmp = data[data.find(':')+2:].split('\n')
833
# Handle comments which may be indented less
839
return '\n'.join(tmp2)
841
def save(self, filename, data, mode='wb'):
842
self.getResource().manage_edit(self.name, self.getParams(data),
845
class PythonScriptNode(PythonNode):
846
additionalViews = (ZopeViews.ZopeSecurityView,
847
ZopeViews.ZopeUndoView, Views.EditorViews.ToDoView)
849
def preparedata(self, data):
856
if l[:12] == '##parameters':
857
params = l[l.find('=')+1:]
859
pass # perhaps we need this anytime
862
return 'def %s(%s):\n%s' % (self.name, params, '\n'.join(tmp2))
864
def load(self, mode='rb'):
865
data = PythonNode.load(self, mode)
866
return self.preparedata(data)
868
def save(self, filename, data, mode='wb'):
869
self.getResource().ZPythonScriptHTML_editAction('fake',
870
self.name, self.getParams(data), self.getBody(data))
872
class ExtPythonNode(PythonNode):
873
Model = ZopeEditorModels.ZopeExternalMethodModel
874
defaultViews = (Views.PySourceView.PythonSourceView,
875
Views.EditorViews.ExploreView)
876
additionalViews = (Views.EditorViews.HierarchyView,
877
Views.EditorViews.ModuleDocView,
878
ZopeViews.ZopeSecurityView, Views.EditorViews.ToDoView,
879
ZopeViews.ZopeUndoView)
882
def openTransportFromProperties(self):
883
zopePath = self.properties['localpath']
885
svr, name = self.getParentResource()
886
res = svr.zoa.props.ExternalMethod(name)
888
module = res['module']
890
emf = ExtMethDlg.ExternalMethodFinder(zopePath)
891
extPath = emf.getExtPath(module)
893
from Explorers import Explorer
894
return Explorer.openEx(extPath)
896
def load(self, mode='rb'):
897
return self.openTransportFromProperties().load(mode=mode)
899
def save(self, filename, data, mode='wb'):
900
transp = self.openTransportFromProperties()
901
transp.save(transp.currentFilename(), data, mode)
903
class DTMLDocNode(ZopeNode):
904
Model = ZopeEditorModels.ZopeDTMLDocumentModel
905
defaultViews = (ZopeViews.ZopeHTMLSourceView,)
906
additionalViews = (ZopeViews.ZopeUndoView,
907
ZopeViews.ZopeSecurityView, ZopeViews.ZopeHTMLView,)
909
class DTMLMethodNode(ZopeNode):
910
Model = ZopeEditorModels.ZopeDTMLMethodModel
911
defaultViews = (ZopeViews.ZopeHTMLSourceView,)
912
additionalViews = (ZopeViews.ZopeUndoView,
913
ZopeViews.ZopeSecurityView, ZopeViews.ZopeHTMLView)
915
class SiteErrorLogNode(ZopeItemNode):
916
Model = ZopeEditorModels.ZopeSiteErrorLogModel
917
defaultViews = (ZopeViews.ZopeSiteErrorLogView,)
918
additionalViews = (ZopeViews.ZopeUndoView,
919
ZopeViews.ZopeSecurityView)
920
def isFolderish(self):
923
class HelpTopicNode(ZopeItemNode):
924
Model = ZopeEditorModels.ZopeHelpTopicModel
925
defaultViews = (ZopeViews.ZopeHTMLView,)
927
def isFolderish(self):
930
from Explorers.PrefsExplorer import SourceBasedPrefColNode
931
class ZopeZ2pySourceBasedPrefColNode(SourceBasedPrefColNode):
934
class ZopeResultsFolderNode(ZopeItemNode):
937
def createChildNode(self, metatype, id, respath, label):
938
item = ZopeItemNode.createChildNode(self, metatype, id, respath)
939
item.name = item.treename = label
943
self.parentOpensChildren = True
946
for zmeta, zid in self.results:
947
zpath = os.path.dirname(self.resourcepath+'/'+zid)
948
name = os.path.basename(zid)
949
node = self.createChildNode(zmeta, name, zpath, '%s (%s)'%(name, zpath))
950
if node:# and not node.isFolderish():
953
self.entries = entries
956
def openParent(self, editor):
957
editor.explorer.tree.SelectItem(editor.explorer.tree.GetSelection())
960
def open(self, node, editor):
961
# recreate with proper name
962
node = node.getNodeFromPath(node.resourcepath, node.metatype)
963
return node.open(editor)
966
return 'Zope Find Results'
968
def findBetween(strg, startMarker, endMarker):
971
idx = strL.find(startMarker)
974
idx2 = strL.find(endMarker, idx)
976
found = strg[idx + len(startMarker)+1: idx2]
977
return idx, idx2, found
979
class ZopeError(Exception):
980
def __init__(self, htmlFaultStr):
981
self.htmlFault = htmlFaultStr
983
# find possible traceback
984
idx, idx2, tracebk = findBetween(htmlFaultStr, '<pre>', '</pre>')
986
tracebk = 'Traceback:\n'+tracebk
987
self.traceback = tracebk
989
txt = Utils.html2txt(htmlFaultStr)
990
self.textFault = '%s\n%s\n' % (txt, tracebk)
992
idx, idx1, self.ErrorType = findBetween(txt, 'Error Type:', '\n')
993
idx, idx1, self.ErrorValue = findBetween(txt, 'Error Value:', '\n')
996
return self.ErrorType and ('%s:%s' % (self.ErrorType, self.ErrorValue)) or self.textFault
999
def zopeHtmlErr2Strs(faultStr):
1000
sFaultStr = str(faultStr)
1001
fs = sFaultStr.lower()
1002
idx = fs.find('<pre>')
1005
idx2 = fs.find('</pre>', idx)
1007
traceBk = '\nTraceback:\n'+sFaultStr[idx + 5: idx2]
1008
txt = Utils.html2txt(sFaultStr)
1011
def uriSplitZope(filename, filepath):
1012
# zope://[category]/<[meta type]>/[path] format
1013
segs = filepath.split('/')
1015
raise ExplorerNodes.TransportCategoryError(
1016
'Category not found', filepath)
1017
category = segs[0]+'|'+segs[1][1:-1]
1018
return 'zope', category, '/'.join(segs[2:]), filename
1020
def uriSplitZopeDebug(filename, filepath):
1021
# zopedebug://[host[:port]]/[path]/[meta type]
1022
# magically maps zopedebug urls to Boa zope uris
1023
segs = filepath.split('/')
1025
raise ExplorerNodes.TransportCategoryError(
1026
'Zope debug path invalid', filepath)
1027
host, filepaths, meta = segs[0], segs[1:-1], segs[-1]
1028
try: host, port = host.split(':')
1029
except ValueError: port = 80
1030
else: port = int(port)
1031
# try to find category that can open this url
1032
for cat in ExplorerNodes.all_transports.entries:
1033
if cat.itemProtocol == 'zope':
1034
itms = cat.openList()
1036
props = itm.properties
1038
if socket.gethostbyname(props['host']) == socket.gethostbyname(host) and \
1039
props['httpport'] == port:
1040
# @@@ original code follows:
1041
# if props['host'].lower() == host.lower() and \
1042
# props['httpport'] == port:
1043
path = '/'.join(filepaths)
1044
name = itm.name or itm.treename
1045
return 'zope', '%s|%s' %(name, meta), path, \
1046
'zope://%s/<%s>/%s'%(name, meta, path)
1048
raise ExplorerNodes.TransportCategoryError(\
1049
'Could not map Zope debug path to defined Zope Category item',
1052
def findZopeExplorerNode(catandmeta, respath, transports):
1053
category, metatype = catandmeta.split('|')
1054
for cat in transports.entries:
1055
if hasattr(cat, 'itemProtocol') and cat.itemProtocol == 'zope':
1056
itms = cat.openList()
1058
if itm.name == category or itm.treename == category:
1059
return itm.getNodeFromPath('/'+respath, metatype)
1060
raise ExplorerNodes.TransportError(
1061
'Zope transport could not be found: %s || %s'%(category, respath))
1063
#-------------------------------------------------------------------------------
1064
# maps meta types to ExplorerNodes
1065
zopeClassMap = { 'Folder': DirNode,
1066
'Product Help': DirNode,
1067
'Z Class': ZClassNode,
1068
'User Folder': UserFolderNode,
1069
'Control Panel': ControlNode,
1070
'Z SQL Method': ZSQLNode,
1071
'DTML Document': DTMLDocNode,
1072
'DTML Method': DTMLMethodNode,
1073
'Python Method': PythonNode,
1074
'External Method': ExtPythonNode,
1075
'Script (Python)': PythonScriptNode,
1076
'Image': ZopeImageNode,
1078
'User': ZopeUserNode,
1079
'Site Error Log': SiteErrorLogNode,
1080
'Help Topic': HelpTopicNode,
1083
ExplorerNodes.register(ZopeCatNode, controller=ZopeCatController)
1084
ExplorerNodes.register(ZopeItemNode, clipboard='global',
1085
confdef=('explorer', 'zope'), controller=ZopeController, category=ZopeCatNode)
1086
ExplorerNodes.uriSplitReg[('zope', 2)] = uriSplitZope
1087
ExplorerNodes.uriSplitReg[('zopedebug', 2)] = uriSplitZopeDebug
1088
ExplorerNodes.transportFindReg['zope'] = findZopeExplorerNode