• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

wxPythonで作った簡易XMLエディタ


Commit MetaInfo

Revisão154f0bd01547d6579da0bfcc6a7fd9cd100ab2fb (tree)
Hora2014-04-10 01:40:46
Autortamanegi <tamanegi@user...>
Commitertamanegi

Mensagem de Log

implement multiple cut copy paste

Mudança Sumário

Diff

--- a/README
+++ b/README
@@ -2,10 +2,12 @@ wmxmled.py: simple xml editor by wxPython
22
33 TODO
44 * test on other platforms (now tested only on Linux-GTK env.)
5-* add wm3D specific functions
6-* implement multiple delete, copy, cut
5+* add wm3d specific functions
6+* about information
7+* code refactoring
78
89 CHANGELOG
10+2014/04/09: implement and improve multiple copy, cut, delete functions
911 2014/04/07: fix and improve undo functions (paste, del, add)
1012 2014/03/14: read file from command line argument
1113 fix bug on removing attributes
--- a/wmutils.py
+++ b/wmutils.py
@@ -132,8 +132,7 @@ class WMXmlEditorParams:
132132 TC_showattr_value = False # active only when showattr_name is True
133133
134134 # undo/redo settings
135- UNDO_truncate_queue_wo_query = True
136- UNDO_queue_size = 5
135+ UNDO_queue_size = 15
137136
138137 # find settings
139138 FIND_clear_wo_query = True
@@ -314,6 +313,39 @@ class ActionAdd( Action ):
314313 def reverse( self ):
315314 return ActionDel( self.uniqids, self.pos, self.itemid, self.myxml )
316315
316+class ActionAdds( Action ):
317+ def __init__( self, uniqids = None, pos = None, itemids = None, myxmls = None ):
318+ Action.__init__( self )
319+ if len(myxmls) > 0:
320+ self.initialize( uniqids, pos, itemids, myxmls )
321+
322+ def initialize( self, uniqids, pos, itemids, myxmls ):
323+ mylen = len( uniqids )
324+ self.myadds = []
325+ # length shall be same
326+ #if len(pos) != mylen or len(itemids) != mylen or len(myxmls) != mylen:
327+ if len(itemids) != mylen or len(myxmls) != mylen:
328+ return
329+ for i in range( 0, mylen ):
330+ self.myadds.append( ActionAdd( uniqids[i], 0, itemids[i], myxmls[i] ) )
331+
332+ def undo( self, treectrl, wmxmled ):
333+ self.myadds.reverse()
334+ for myadd in self.myadds:
335+ myadd.undo( treectrl, wmxmled )
336+ return True
337+
338+ def reverse( self ):
339+ uniqids = []
340+ pos = []
341+ itemids = []
342+ myxmls = []
343+ for myadd in self.myadds:
344+ uniqids.append( myadd.uniqids )
345+ pos.append( myadd.pos )
346+ myxmls.append( myadd.myxml )
347+ return ActionDels( uniqids, pos, itemids, myxmls )
348+
317349 # delete action; reversed action is add
318350 class ActionDel( Action ):
319351 def __init__( self, uniqids = None, pos = None, itemid = None, myxml = None ):
@@ -357,3 +389,39 @@ class ActionDel( Action ):
357389
358390 def reverse( self ):
359391 return ActionAdd( self.uniqids, self.pos, self.itemid, self.myxml )
392+
393+# multiple deletes
394+# registered actions should not be nested
395+class ActionDels( Action ):
396+ def __init__( self, uniqids = None, pos = None, itemids = None, myxmls = None ):
397+ Action.__init__( self )
398+ if len(myxmls) > 0:
399+ self.initialize( uniqids, pos, itemids, myxmls )
400+
401+ def initialize( self, uniqids, pos, itemids, myxmls ):
402+ mylen = len( uniqids )
403+ self.mydels = []
404+ # lengths shall be same
405+ #if len(pos) != mylen or len(itemids) != mylen or len(myxmls) != mylen:
406+ if len(pos) != mylen or len(myxmls) != mylen:
407+ return
408+ for i in range( 0, mylen ):
409+ self.mydels.append( ActionDel( uniqids[i], pos[i], None, myxmls[i] ) )
410+
411+ def undo( self, treectrl, wmxmled ):
412+ self.mydels.reverse()
413+ for mydel in self.mydels:
414+ mydel.undo( treectrl, wmxmled )
415+ return True
416+
417+ def reverse( self ):
418+ uniqids = []
419+ pos = []
420+ itemids = []
421+ myxmls = []
422+ for mydel in self.mydels:
423+ uniqids.append( mydel.uniqids )
424+ pos.append( mydel.pos )
425+ itemids.append( mydel.itemid )
426+ myxmls.append( mydel.myxml )
427+ return ActionAdds( uniqids, pos, itemids, myxmls )
--- a/wmxmled.conf
+++ b/wmxmled.conf
@@ -1,7 +1,7 @@
11 <wmconf>
22 <!-- sample configuration file -->
33 <!-- the following values are equivalent to values in wmutils.py -->
4- <undo no_query_trunc="1" qsize="15" />
4+ <undo qsize="15" />
55 <find clear_wo_query="1" />
66 <tc showattr_name="1" showattr_value="1" />
77 <lc emphasis="blue" indent="2" />
--- a/wmxmled.fbp
+++ b/wmxmled.fbp
@@ -600,21 +600,6 @@
600600 <event name="OnMenuSelection"></event>
601601 <event name="OnUpdateUI"></event>
602602 </object>
603- <object class="wxMenuItem" expanded="1">
604- <property name="bitmap"></property>
605- <property name="checked">0</property>
606- <property name="enabled">1</property>
607- <property name="help"></property>
608- <property name="id">wxID_ANY</property>
609- <property name="kind">wxITEM_NORMAL</property>
610- <property name="label">Delete Selected</property>
611- <property name="name">rightClickMenuDeleteSelected</property>
612- <property name="permission">none</property>
613- <property name="shortcut"></property>
614- <property name="unchecked_bitmap"></property>
615- <event name="OnMenuSelection"></event>
616- <event name="OnUpdateUI"></event>
617- </object>
618603 <object class="separator" expanded="0">
619604 <property name="name">m_separator6</property>
620605 <property name="permission">none</property>
--- a/wmxmled.py
+++ b/wmxmled.py
@@ -108,7 +108,6 @@ class WMXmlEditor( wx.App ):
108108 self.Bind( wx.EVT_MENU, self.evPopupMenuPasteA, id=xrc.XRCID("rightClickMenuPasteAppend") )
109109 self.Bind( wx.EVT_MENU, self.evPopupMenuPasteAC, id=xrc.XRCID("rightClickMenuPasteAppendChild") )
110110 self.Bind( wx.EVT_MENU, self.evPopupMenuDelete, id=xrc.XRCID("rightClickMenuDelete") )
111- self.Bind( wx.EVT_MENU, self.evPopupMenuDeleteSelected, id=xrc.XRCID("rightClickMenuDeleteSelected") )
112111 self.Bind( wx.EVT_MENU, self.evPopupMenuInsert, id=xrc.XRCID("rightClickMenuInsert") )
113112 self.Bind( wx.EVT_MENU, self.evPopupMenuInsertChild, id=xrc.XRCID("rightClickMenuInsertChild") )
114113 self.Bind( wx.EVT_MENU, self.evPopupMenuAppend, id=xrc.XRCID("rightClickMenuAppend") )
@@ -608,6 +607,8 @@ class WMXmlEditor( wx.App ):
608607 if not self.lc.IsSelected( index ):
609608 return
610609 self.lc_editing_index = index
610+ self.lc_editing_indexes = self.listCtrlGetSelectedIndexes()
611+ numselected = len( self.lc_editing_indexes )
611612 ctrl = wx.GetKeyState( wx.WXK_CONTROL )
612613 if keycode == 3: # Ctrl-C; copy
613614 self.evPopupMenuCopy( None )
@@ -1067,7 +1068,6 @@ class WMXmlEditor( wx.App ):
10671068 if self.copybuffer is None:
10681069 self.rightClickMenu.FindItemById(xrc.XRCID("rightClickMenuPaste")).Enable( False )
10691070 self.rightClickMenu.FindItemById(xrc.XRCID("rightClickMenuDelete")).Enable( activate )
1070- self.rightClickMenu.FindItemById(xrc.XRCID("rightClickMenuDeleteSelected")).Enable( activate )
10711071 self.rightClickMenu.FindItemById(xrc.XRCID("rightClickMenuInsert")).Enable( True )
10721072 self.rightClickMenu.FindItemById(xrc.XRCID("rightClickMenuInsertChild")).Enable( True )
10731073 self.rightClickMenu.FindItemById(xrc.XRCID("rightClickMenuAppend")).Enable( True )
@@ -1087,11 +1087,21 @@ class WMXmlEditor( wx.App ):
10871087 def evPopupMenuCopy( self, event ):
10881088 if not self.popupIsItemAvailable( self.lc_editing_index ):
10891089 return
1090+ self.copybuffer = []
1091+ self.removeNestedIndexes()
1092+ if len( self.lc_editing_indexes ) > 1: # multiple
1093+ for myindex in self.lc_editing_indexes:
1094+ self.lc_editing_index = myindex
1095+ self.copybuffer.append( self.workerCopy() )
1096+ else: # single copy
1097+ self.copybuffer = [ self.workerCopy() ]
1098+
1099+ def workerCopy( self ):
10901100 myindex = min( self.lc_editing_index, self.l2l_correspondence[self.lc_editing_index] )
1091- treeitemid = self.l2t_correspondence[myindex]
1101+ itemid = self.l2t_correspondence[myindex]
10921102 # uniqids will be discarded
1093- self.copybuffer, uniqids = self.createElementTreeFromTreeCtrl( treeitemid )
1094- self.copybuffer = self.copybuffer.getroot()
1103+ buf, uniqids = self.createElementTreeFromTreeCtrl( itemid )
1104+ return buf.getroot()
10951105
10961106 def evPopupMenuCut( self, event ):
10971107 if not self.popupIsItemAvailable( self.lc_editing_index ):
@@ -1113,69 +1123,131 @@ class WMXmlEditor( wx.App ):
11131123 self.evPopupMenuPaste( event, False, True )
11141124
11151125 def evPopupMenuPaste( self, event, insert = True, child = True ):
1126+ # brief check
11161127 if self.copybuffer is None:
11171128 self.miscShowMessageBox( "no data in buffer" )
11181129 return
1119- newxml = copy.deepcopy( self.copybuffer )
1120- showname = self.createTreeCtrlLabel( newxml )
1130+ if len( self.copybuffer ) == 0:
1131+ self.miscShowMessageBox( "no data in buffer" )
1132+ return
1133+ # prepare TreeCtrl labels
1134+ newxmls = copy.deepcopy( self.copybuffer )
1135+ names = []
1136+ for newxml in newxmls:
1137+ names.append( self.createTreeCtrlLabel( newxml ) )
1138+ numadd = len( names )
1139+ # get ListCtrl index
11211140 if len( self.l2l_correspondence ) > 0:
11221141 index = min( self.lc_editing_index, self.l2l_correspondence[self.lc_editing_index] )
11231142 else:
11241143 index = -1
1144+
1145+ if insert:
1146+ names.reverse()
1147+ newxmls.reverse()
1148+
1149+ # add xml in copybuffer
1150+ my_itemids = []
11251151 if index >= 0:
1126- treeitemid = self.l2t_correspondence[index]
1152+ itemid = self.l2t_correspondence[index]
11271153 if index < 0 and child: # i do not know what to do
11281154 self.miscShowMessageBox( "cannot create child element." )
11291155 return
11301156 elif index < 0 and self.tc.IsEmpty(): # add root element
1131- my_itemid = self.tc.AddRoot( showname, self.imageFolder, self.imageFolderOpen )
1157+ if numadd > 1:
1158+ self.miscShowMessageBox( "cannot add multiple root element." )
1159+ return
1160+ my_itemids.append( self.tc.AddRoot( names[0], self.imageFolder, self.imageFolderOpen ) )
11321161 else:
11331162 if insert and child: # insert child
1134- my_itemid = self.insertChildElement( showname, treeitemid )
1163+ for name in names:
1164+ my_itemids.append( self.insertChildElement( name, itemid ) )
11351165 elif insert and not child: # insert
11361166 if index == 0:
11371167 self.miscShowMessageBox("Cannot insert another root element.")
11381168 return
11391169 else:
1140- my_itemid = self.insertElement( showname, treeitemid )
1170+ my_itemids.append( self.insertElement( names[0], itemid ) )
1171+ for i in range( 1, numadd ):
1172+ my_itemids.append( self.insertElement( names[i], my_itemids[-1] ) )
11411173 elif not insert and child: # append child
1142- my_itemid = self.appendChildElement( showname, treeitemid )
1174+ for name in names:
1175+ my_itemids.append( self.appendChildElement( names[i], itemid ) )
11431176 elif not insert and not child: # append
11441177 if index == 0:
11451178 self.miscShowMessageBox("Cannot insert another root element.")
11461179 return
11471180 else:
1148- my_itemid = self.appendElement( showname, treeitemid )
1149- newxml = WMXmlElement( self.copybuffer )
1150- # use new uniq id
1151- self.tc.SetItemPyData( my_itemid, [ self.tc.GetCount() - 1, newxml, self.uniqid ] )
1152- self.uniqid += 1
1153- self.createXmlTreeRecursive( self.copybuffer, my_itemid )
1181+ my_itemids.append( self.appendElement( names[0], itemid ) )
1182+ for i in range( 1, numadd ):
1183+ my_itemids.append( self.appendElement( names[i], my_itemids[-1] ) )
1184+ # convert
1185+ myxmls = []
1186+ for i in range( 0, numadd ):
1187+ myxmls.append( WMXmlElement( newxmls[i] ) )
1188+ # use new uniq id
1189+ self.tc.SetItemPyData( my_itemids[i], [ self.tc.GetCount() - 1, myxmls[-1], self.uniqid ] )
1190+ self.uniqid += 1
1191+ self.createXmlTreeRecursive( self.copybuffer[i], my_itemids[i] )
11541192 self.createListCtrlFromTreeData()
1155- # add to the undo queue
1156- self.addActionToUndoQueue( ActionAdd( self.gatherUniqIds( my_itemid ), 0, my_itemid, newxml ) )
1193+
1194+ if numadd == 1:
1195+ # add to the undo queue
1196+ self.addActionToUndoQueue( ActionAdd( self.gatherUniqIds( my_itemids[0] ), 0, my_itemids[0], myxmls[0] ) )
1197+ else:
1198+ uniqids = []
1199+ for i in range( 0, numadd ):
1200+ uniqids.append( self.gatherUniqIds( my_itemids[i] ) )
1201+ self.addActionToUndoQueue( ActionAdds( uniqids, 0, my_itemids, myxmls ) )
11571202 self.IsSaved = False
1203+ # focus on newly created item
1204+ self.focusTreeCtrlItem( my_itemids[-1] )
11581205
1159- def evPopupMenuDelete( self, event ):
1206+ def focusTreeCtrlItem( self, itemid ):
1207+ # TreeCtrl
1208+ self.tc.UnselectAll()
1209+ self.tc.SelectItem( itemid )
1210+ # ListCtrl
1211+ index = self.tc.GetItemPyData( itemid )[0]
1212+ self.deselectAllItemsListCtrl()
1213+ self.selectListCtrlItems( index )
1214+ self.lc.Focus( index )
1215+
1216+ # preprocess for deleting item
1217+ def preRemove( self ):
11601218 if not self.popupIsItemAvailable( self.lc_editing_index ):
11611219 return
11621220 myindex = self.lc_editing_index
1163- treeitemid = self.l2t_correspondence[myindex]
1164- # save action
1165- pos = self.calculateItemPosition( treeitemid )
1166- if not self.tc.GetNextSibling( treeitemid ):
1221+ itemid = self.l2t_correspondence[myindex]
1222+ # remember item position for undoing
1223+ pos = self.calculateItemPosition( itemid )
1224+ if not self.tc.GetNextSibling( itemid ):
11671225 pos = -1
11681226 ## we need Element, not WMXmlElement
1169- myxml, uniqids = self.createElementTreeFromTreeCtrl( treeitemid )
1227+ myxml, uniqids = self.createElementTreeFromTreeCtrl( itemid )
11701228 myxml = myxml.getroot()
1171- parent = self.tc.GetItemParent(treeitemid)
1229+ parent = self.tc.GetItemParent( itemid )
11721230 if parent.IsOk():
11731231 uniqids.insert( 0, self.tc.GetItemPyData(parent)[2] )
11741232 else:
11751233 uniqids.insert( 0, None )
1176- #myxml = self.tc.GetItemPyData( treeitemid )[1]
1234+ return uniqids, pos, itemid, myxml
1235+
1236+ def evPopupMenuDelete( self, event ):
1237+ if not self.popupIsItemAvailable( self.lc_editing_index ):
1238+ return
1239+ if len( self.lc_editing_indexes ) > 1:
1240+ self.deleteItemMultiple()
1241+ else:
1242+ self.deleteItem()
1243+
1244+ def deleteItem( self ):
1245+ uniqids, pos, itemid, myxml = self.preRemove()
1246+ # find next item
1247+ nextitem = self.tc.GetNextSibling(itemid)
1248+ parent = self.tc.GetItemParent(itemid)
11771249 # remove item
1178- if self.deleteTreeCtrlItem( treeitemid ):
1250+ if self.deleteTreeCtrlItem( itemid ):
11791251 # add to undo queue
11801252 self.addActionToUndoQueue( ActionDel( uniqids, pos, None, myxml ) )
11811253 # store removed data for undo
@@ -1183,17 +1255,59 @@ class WMXmlEditor( wx.App ):
11831255 self.IsSaved = False
11841256 # force update data
11851257 self.createListCtrlFromTreeData()
1186-
1187- def evPopupMenuDeleteSelected( self, event ):
1188- if not self.popupIsItemAvailable( self.lc_editing_index ):
1189- return
1258+ if nextitem.IsOk():
1259+ self.focusTreeCtrlItem( nextitem )
1260+ elif parent.IsOk():
1261+ self.focusTreeCtrlItem( parent )
1262+
1263+ def deleteItemMultiple( self ):
1264+ # remove nested indexes
1265+ self.removeNestedIndexes()
11901266 # sort indexes
11911267 self.lc_editing_indexes.sort()
11921268 self.lc_editing_indexes.reverse()
11931269 # use self.lc_editing_indexes to delete selected items
1270+ uniqidss = []
1271+ poss = []
1272+ myxmls = []
11941273 for index in self.lc_editing_indexes:
11951274 self.lc_editing_index = index
1196- self.evPopupMenuDelete( event )
1275+ uniqids, pos, itemid, myxml = self.preRemove()
1276+ if self.deleteTreeCtrlItem( itemid ):
1277+ uniqidss.append( uniqids )
1278+ poss.append( pos )
1279+ myxmls.append( myxml )
1280+ self.addActionToUndoQueue( ActionDels( uniqidss, poss, None, myxmls ) )
1281+ self.IsSaved = False
1282+ self.createListCtrlFromTreeData()
1283+ # do not focus next item here
1284+
1285+ # remove nested elements from lc_editing_indexes
1286+ def removeNestedIndexes( self ):
1287+ num = len(self.lc_editing_indexes)
1288+ itemids = []
1289+ for i in range( 0, num ):
1290+ ind = self.lc_editing_indexes[i]
1291+ ind = min( ind, self.l2l_correspondence[ind] )
1292+ itemids.append( self.l2t_correspondence[ind] )
1293+ self.lc_editing_indexes[i] = ind
1294+
1295+ newone = []
1296+ for i in range( 0, num ):
1297+ if not self.isNestedItem( itemids[i] ):
1298+ newone.append( self.lc_editing_indexes[i] )
1299+
1300+ # replace to new data
1301+ self.lc_editing_indexes = list(set(newone))
1302+
1303+ def isNestedItem( self, itemid ):
1304+ parent = self.tc.GetItemParent( itemid )
1305+ while parent.IsOk():
1306+ ind = self.tc.GetItemPyData( parent )[0]
1307+ if ind in self.lc_editing_indexes:
1308+ return True
1309+ parent = self.tc.GetItemParent( parent )
1310+ return False
11971311
11981312 def evPopupMenuInsert( self, event ):
11991313 if self.lc_editing_index == 0:
--- a/wmxmled.xrc
+++ b/wmxmled.xrc
@@ -678,10 +678,6 @@
678678 <label>Delete</label>
679679 <help></help>
680680 </object>
681- <object class="wxMenuItem" name="rightClickMenuDeleteSelected">
682- <label>Delete Selected</label>
683- <help></help>
684- </object>
685681 <object class="separator" />
686682 <object class="wxMenuItem" name="rightClickMenuInsert">
687683 <label>Insert</label>