2020-08-13 01:28:19 +02:00
#!/usr/bin/env python3
"""
Extension for InkScape 1.0
2020-08-23 14:08:11 +02:00
This extension parses the selection and will put all elements into one single group . If you have a cluster with lots of groups and elements you will clean up this way ( one top level group , all elements below it ) . If you select a single element or a set of elements you just wrap it like using CTRL + G ( like making a usual group ) . You can also use this extension to filter out unwanted SVG elements at all .
2020-08-13 01:28:19 +02:00
Author : Mario Voigt / FabLab Chemnitz
Mail : mario . voigt @stadtfabrikanten.org
Date : 13.08 .2020
2020-08-23 01:14:36 +02:00
Last Patch : 23.08 .2020
2020-08-13 01:28:19 +02:00
License : GNU GPL v3
"""
import inkex
2020-08-23 14:08:11 +02:00
from lxml import etree
2020-08-13 01:28:19 +02:00
class MigrateGroups ( inkex . Effect ) :
2020-08-23 14:08:11 +02:00
allElements = [ ]
2020-08-13 01:28:19 +02:00
allGroups = [ ]
2020-08-20 02:41:10 +02:00
allNonMigrates = [ ]
2020-08-13 01:28:19 +02:00
def __init__ ( self ) :
inkex . Effect . __init__ ( self )
2020-08-23 14:08:11 +02:00
self . arg_parser . add_argument ( " --allitems " , type = inkex . Boolean , default = True )
self . arg_parser . add_argument ( " --droponly " , type = inkex . Boolean , default = False )
self . arg_parser . add_argument ( " --showdroplist " , type = inkex . Boolean , default = False )
self . arg_parser . add_argument ( " --circle " , type = inkex . Boolean , default = True )
self . arg_parser . add_argument ( " --clipPath " , type = inkex . Boolean , default = True )
self . arg_parser . add_argument ( " --defs " , type = inkex . Boolean , default = True )
self . arg_parser . add_argument ( " --ellipse " , type = inkex . Boolean , default = True )
self . arg_parser . add_argument ( " --image " , type = inkex . Boolean , default = True )
self . arg_parser . add_argument ( " --line " , type = inkex . Boolean , default = True )
self . arg_parser . add_argument ( " --path " , type = inkex . Boolean , default = True )
self . arg_parser . add_argument ( " --polyline " , type = inkex . Boolean , default = True )
self . arg_parser . add_argument ( " --polygon " , type = inkex . Boolean , default = True )
self . arg_parser . add_argument ( " --rect " , type = inkex . Boolean , default = True )
#self.arg_parser.add_argument("--sodipodi", type=inkex.Boolean, default=True)
self . arg_parser . add_argument ( " --svg " , type = inkex . Boolean , default = True )
self . arg_parser . add_argument ( " --text " , type = inkex . Boolean , default = True )
self . arg_parser . add_argument ( " --tspan " , type = inkex . Boolean , default = True )
self . arg_parser . add_argument ( " --lineargradient " , type = inkex . Boolean , default = True )
self . arg_parser . add_argument ( " --radialgradient " , type = inkex . Boolean , default = True )
self . arg_parser . add_argument ( " --meshgradient " , type = inkex . Boolean , default = True )
self . arg_parser . add_argument ( " --meshrow " , type = inkex . Boolean , default = True )
self . arg_parser . add_argument ( " --meshpatch " , type = inkex . Boolean , default = True )
self . arg_parser . add_argument ( " --script " , type = inkex . Boolean , default = True )
self . arg_parser . add_argument ( " --stop " , type = inkex . Boolean , default = True )
self . arg_parser . add_argument ( " --use " , type = inkex . Boolean , default = True )
2020-08-13 01:28:19 +02:00
def effect ( self ) :
2020-08-20 02:41:10 +02:00
namespace = [ ]
2020-08-23 14:08:11 +02:00
namespace . append ( " { http://www.w3.org/2000/svg}circle " ) if self . options . circle else " "
namespace . append ( " { http://www.w3.org/2000/svg}clipPath " ) if self . options . clipPath else " "
namespace . append ( " { http://www.w3.org/2000/svg}defs " ) if self . options . defs else " "
namespace . append ( " { http://www.w3.org/2000/svg}ellipse " ) if self . options . ellipse else " "
namespace . append ( " { http://www.w3.org/2000/svg}image " ) if self . options . image else " "
namespace . append ( " { http://www.w3.org/2000/svg}line " ) if self . options . line else " "
namespace . append ( " { http://www.w3.org/2000/svg}polygon " ) if self . options . polygon else " "
namespace . append ( " { http://www.w3.org/2000/svg}path " ) if self . options . path else " "
namespace . append ( " { http://www.w3.org/2000/svg}polyline " ) if self . options . polyline else " "
namespace . append ( " { http://www.w3.org/2000/svg}rect " ) if self . options . rect else " "
#namespace.append("{http://www.w3.org/2000/svg}sodipodi") if self.options.sodipodi else "" #do not do this. it will crash InkScape
#namespace.append("{http://www.w3.org/2000/svg}svg") if self.options.svg else ""
namespace . append ( " { http://www.w3.org/2000/svg}text " ) if self . options . text else " "
namespace . append ( " { http://www.w3.org/2000/svg}tspan " ) if self . options . tspan else " "
namespace . append ( " { http://www.w3.org/2000/svg}lineargradient " ) if self . options . lineargradient else " "
namespace . append ( " { http://www.w3.org/2000/svg}radialgradient " ) if self . options . radialgradient else " "
namespace . append ( " { http://www.w3.org/2000/svg}meshgradient " ) if self . options . meshgradient else " "
namespace . append ( " { http://www.w3.org/2000/svg}meshrow " ) if self . options . meshrow else " "
namespace . append ( " { http://www.w3.org/2000/svg}meshpatch " ) if self . options . meshpatch else " "
namespace . append ( " { http://www.w3.org/2000/svg}script " ) if self . options . script else " "
namespace . append ( " { http://www.w3.org/2000/svg}stop " ) if self . options . stop else " "
namespace . append ( " { http://www.w3.org/2000/svg}use " ) if self . options . use else " "
#check if we have selected elements or if we should parse the whole document instead
selected = [ ] #list of elements to parse
if len ( self . svg . selected ) == 0 :
for element in self . document . getroot ( ) . iter ( tag = etree . Element ) :
if element != self . document . getroot ( ) :
selected . append ( element )
else :
selected = self . svg . selected
def parseNodes ( self , element ) :
if self . options . allitems :
if element not in self . allElements :
if element . tag != inkex . addNS ( ' g ' , ' svg ' ) and element . tag != inkex . addNS ( ' svg ' , ' svg ' ) and element . tag != inkex . addNS ( ' namedview ' , ' sodipodi ' ) :
self . allElements . append ( element )
else :
if element . tag in namespace :
if element not in self . allElements :
self . allElements . append ( element )
else :
if element . tag != inkex . addNS ( ' g ' , ' svg ' ) and element . tag != inkex . addNS ( ' svg ' , ' svg ' ) and element . tag != inkex . addNS ( ' namedview ' , ' sodipodi ' ) :
if element not in self . allNonMigrates :
self . allNonMigrates . append ( element )
if element . tag == inkex . addNS ( ' g ' , ' svg ' ) or element . tag == inkex . addNS ( ' svg ' , ' svg ' ) :
if element not in self . allGroups :
self . allGroups . append ( element )
groups = element . getchildren ( )
2020-08-13 01:28:19 +02:00
if groups is not None :
for group in groups :
parseNodes ( self , group )
if group not in self . allGroups :
self . allGroups . append ( group )
2020-08-23 14:08:11 +02:00
#get all elements from the selection. Remove all groups from the selection and form a new single group of it. We also handle svg:svg because it behaves like a group container too
for element in selected :
parseNodes ( self , element )
if len ( self . allElements ) > 0 :
#copy all element into the new group
for oldElement in self . allElements :
#oldElementId = oldElement.get('id')
if oldElement . getparent ( ) is not None :
oldElement . getparent ( ) . remove ( oldElement )
#newElement.set('id', oldElementId)
if self . options . droponly == False :
#make a new group at root level
newGroup = self . document . getroot ( ) . add ( inkex . Group ( ) )
newElement = oldElement . copy ( )
newGroup . add ( newElement )
2020-08-20 02:41:10 +02:00
2020-08-23 14:08:11 +02:00
if self . options . droponly == False :
#now remove all the obsolete groups
if len ( self . allGroups ) > 0 :
for group in self . allGroups :
if group . getparent ( ) is not None :
group . getparent ( ) . remove ( group )
#remove the selected, now empty group (if it's the case) - this applies not if there is no user selection at all so some dangling group(s) might be left over
if len ( self . svg . selected ) > 0 and len ( self . allElements ) > 0 :
if self . svg . selected [ 0 ] . tag == inkex . addNS ( ' g ' , ' svg ' ) or self . svg . selected [ 0 ] . tag == inkex . addNS ( ' svg ' , ' svg ' ) :
if self . svg . selected [ 0 ] . getparent ( ) is not None :
self . svg . selected [ 0 ] . getparent ( ) . remove ( self . svg . selected [ 0 ] )
if self . options . showdroplist and len ( self . allNonMigrates ) > 0 :
self . msg ( str ( len ( self . allNonMigrates ) ) + " elements were removed during nodes while migration: " )
2020-08-20 02:41:10 +02:00
for i in self . allNonMigrates :
2020-08-23 14:08:11 +02:00
self . msg ( i . tag . replace ( " { http://www.w3.org/2000/svg} " , " svg: " ) + " id: " + i . get ( ' id ' ) )
2020-08-20 02:41:10 +02:00
2020-08-13 01:28:19 +02:00
MigrateGroups ( ) . run ( )