# $Id: WordMap.py,v 1.6 2003/08/18 07:44:24 berlingo Exp $ # # Copyright 2001, 2002 by IVA Team and contributors # # This file is part of IVA. # # IVA is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # IVA is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with IVA; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """Contains class WordMap, which represents one working Concept map""" import AccessControl import OFS, Globals from OFS import SimpleItem import types import time import math from TraversableWrapper import Traversable from Globals import Persistent from AccessControl import ClassSecurityInfo from Cruft import Cruft from common import add_dtml, translate, perm_edit, perm_view, get_roles try: from PIL import Image, ImageDraw except: pass class WordMap( OFS.Folder.Folder, Persistent, AccessControl.Role.RoleManager, Traversable, Cruft ): "Words in picture" security = AccessControl.ClassSecurityInfo() security.declareObjectPublic() def __init__(self): "Constructor" self.meta_type="WordMap" self.initializeVariables() def initializeVariables(self): "Initialize variables at startup and on cleaning" self.picturesize=[500, 600] #picture size in pixels self.planpicturesize=[200, 200] #whole map without zooming #viewing area in logical units self.viewingbounds=[0, 0, self.picturesize[0], self.picturesize[1]] self.viewingcentre=[ (self.viewingbounds[0]+self.viewingbounds[2])/2.0, (self.viewingbounds[1]+self.viewingbounds[3])/2.0, ] self.viewcoef=1 #monitor points/logical points self.zoomcoef=0.5 self.wordcolor=(0, 200, 0) self.linecolor=(0, 0, 200) self.selectedlinecolor=(200, 0, 0) self.backgroundcolor=(255, 255, 255) self.viewingboundslinecolor=(200, 200, 200) self.selectedarealinecolor=(255, 100, 100) self.leftdistance=10 #free space from picture side in pixels self.rightdistance=10 self.topdistance=10 self.bottomdistance=10 self.movingdistanceinscreen=25 self.words=[] #words in graph. At exaple ["Tallinn", "Tartu", "Valga"] #word placing in picture. Each word have x and y coordinate #at example [[10, 10], [10, 20], [10, 30]] self.wordplaces=[] #in self.relationnumbers each element is a array, where index means starting vertex and #value point to end vertex. At example [[1], [0, 2], [1]] self.relationnumbers=[] self.startingvertex=None #Central vertex index in graph at example 2 #self.parentarray displays way to starting vertex #at example [1, 2, -1] means, that way from vertex 0 to #startingvertex (here 2) goes (0, 1) and (1, 2). In place 2 #are value -1, because we allready are in vertex 2 self.parentarray=[] #Parent vertex in trees self.distancegrouparray=None #Each element presents list of #vertexes in same distance from start vertex #active action number #0 - horizontal tree; 1-move self.activeaction=0 self.selectedmovevertex=None #vertex selected to move self.selectedwords=[] #word indexes self.selectededge=None self.selectingdistance=3 #distance in points selecting with mouse self.selectedarea=None #[x, y, w, h] if present self.selectedareafirstclick=None #[x, y] if present self.menustates={'edit':0, 'select':0, 'zoom':0} self.picturefilenames=["wm_kursor", "wm_margistus", "wm_luuppluss", #0, 1, 2 "wm_luupmiinus", "wm_lisaseos", "wm_kustutus", #3, 4, 5 "wm_horpuu", "wm_kiirpuu", "wm_noolv", #6, 7, 8 "wm_noolp", "wm_nooly", "wm_noola", #9, 10, 11 "wm_margistusnool", "wm_margistus", "wm_margistusmaha", "wm_margistusloika", "wm_margistuskopeeri", "wm_margistuskleebi", "wm_margistusv", "wm_margistusp", "wm_margistusy", "wm_margistusa", "wm_lisaseos", "wm_margistus", "wm_luuppluss", #22 "wm_luuptyhi", "wm_piltsuuremaks", "wm_piltvaiksemaks" ] #which picture is with border self.pictureselections=[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, #0-11 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, #12-20 ] self.menuicons=(22, 23, 24) self.additionalpictures=[] self.selectpictures=[12, 13, 14, 15, 16, 17, 18, 19, 20, 21] self.picturehints=[ "Click with mouse", "Select area", "Zoom bigger", "Zoom Smaller", "Add edge", "Delete", "Horizontal tree", "Circle tree", "View left", "Viev right", "View up", "View down", "Select words", "Select area words", "Unselect all", "Cut", "Copy", "Paste", "Move left", "Move right", "Move up", "Move down", "Edit menu", "Select menu", "Zoom menu", "Zoom to bounds", "Increase picture", "Decrease picture" ] return "ok" security.declareProtected(perm_view, 'getAdditionalPictures') def getMenuState(self, type): "Is menu open" return self.menustates[type] def changeMenuState(self, type): "on/off" if self.menustates[type]: self.menustates[type]=0 else: self.menustates[type]=1 security.declareProtected(perm_view, 'getAdditionalPictures') def getAdditionalPictures(self): "Additional menu" return self.additionalpictures security.declareProtected(perm_view, 'getIconByNr') def getIconByNr(self, pnr): "Returns the file name" return self.picturefilenames[int(pnr)] security.declareProtected(perm_view, 'isIconSelected') def isIconSelected(self, pnr): "yes/no" return self.pictureselections[int(pnr)] security.declareProtected(perm_view, 'getIconHint') def getIconHint(self, pnr): "Hint to picture" return self.picturehints[int(pnr)] security.declareProtected(perm_view, 'makeCopy') def makeCopy(self): "Copy of self with same main data" import copy newmap=WordMap() newmap.words=copy.copy(self.words) newmap.wordplaces=[] for p in self.wordplaces: newmap.wordplaces.append(copy.copy(p)) newmap.relationnumbers=[] for n in self.relationnumbers: newmap.relationnumbers.append(copy.copy(n)) newmap.parentarray=copy.copy(self.parentarray) return newmap security.declareProtected(perm_view, 'addChildMap') def addChildMap(self, copying): "Adds child map to current map" nr=self.getNewWordMapNr() if copying: m=self.makeCopy() else: m=WordMap() m.id='map'+str(nr) self._setObject(m.id, m) return str(nr) def addChildMap_handler(self, REQUEST): "Adds child map and redirects to index" self.addChildMap(copying=1) REQUEST.RESPONSE.redirect(self.absolute_url()) security.declareProtected(perm_view, 'getChildMaps') def getChildMaps(self): "Child maps of current map" return self.objectValues('WordMap') security.declareProtected(perm_view, 'readData') def readData(self, kogum): """Parameetrina saadavas assotsiatiivmassiivis on votmeteks solmede ID-d iga elemendi kyljes olevas assotsiatiivmassiivis on votmeteks solmede ID-d kuhu vastavalt kohalt viidatakse ning vaartusteks seose tyybid. Salvestatase arvuline massiiv, kus iga elemendi kohal olevas massiivis on kirjas arvud, millega vastaval solmel seos""" tulemus=[] votmed=kogum.keys() votmed.sort() for i in range(len(votmed)): abi=[] element=votmed[i] for x in kogum[element].keys(): abi.append(votmed.index(x)) for arv in range(len(votmed)): for x in kogum[votmed[arv]].keys(): if x==votmed[i] and arv not in abi: abi.append(arv) tulemus.append(abi) self.wordplaces=[] #sonade paiknemine graafis for i in range(len(votmed)): self.wordplaces.append([0, i*10]) #algul yksteise alla self.relationnumbers=tulemus #elementide vahelised seosed #self.sonagr=kogum #koik andmed self.words=votmed #graafis olevad sonad security.declareProtected(perm_view, 'calculateDistances') def calculateDistances(self, nr): "Luuakse massiiv kaugused naitamaks, mitme serva kaugusel on iga tipp tipust nr" abi=[] vanem=[] for i in range(len(self.relationnumbers)): abi.append(-1) vanem.append(-1) abi[nr]=0 jarjekord=[] jarjekord.append(nr) self.distancegrouparray=[] while len(jarjekord)>0: uuritav=jarjekord.pop(0) if len(self.distancegrouparray)<=abi[uuritav]: self.distancegrouparray.append([]) self.distancegrouparray[abi[uuritav]].append(uuritav) for x in self.relationnumbers[uuritav]: if abi[x]==-1: abi[x]=abi[uuritav]+1 vanem[x]=uuritav jarjekord.append(x) self.kaugused=abi self.suurimkaugus=0 for k in self.kaugused: if k>self.suurimkaugus: self.suurimkaugus=k self.startingvertex=nr self.parentarray=vanem security.declareProtected(perm_view, 'calculateHorizontalTree') def calculateHorizontalTree(self): "Luuakse pilt, kus peaelement hakkab vasakult keskelt, alamelemendid hargnevad" tulpadearv=len(self.distancegrouparray) tulbalaius=(self.viewingbounds[2]-self.leftdistance*1.0/self.viewcoef-self.rightdistance*1.0/self.viewcoef)/tulpadearv sonax=self.viewingbounds[0]+self.leftdistance/self.viewcoef for distance in range(len(self.distancegrouparray)): sonutulbas=len(self.distancegrouparray[distance]) reavahe=(self.viewingbounds[3]-self.topdistance*1.0/self.viewcoef-self.bottomdistance*1.0/self.viewcoef)/sonutulbas sonay=self.viewingbounds[1]+self.topdistance*1.0/self.viewcoef+reavahe*1.0/2 for sonanr in range(sonutulbas): self.wordplaces[self.distancegrouparray[distance][sonanr]]=[sonax, sonay] sonay+=reavahe sonax+=tulbalaius security.declareProtected(perm_view, 'calculateCircleTree') def calculateCircleTree(self): "Tree, where are central word and others around him in circles" centerx=self.viewingcentre[0] centery=self.viewingcentre[1] maxr=min(self.viewingbounds[2]-self.leftdistance*1.0/self.viewcoef-self.rightdistance*1.0/self.viewcoef, self.viewingbounds[3]-self.topdistance*1.0/self.viewcoef-self.bottomdistance*1.0/self.viewcoef)/2 r=0 dr=maxr/(len(self.distancegrouparray)-1) for distance in range(len(self.distancegrouparray)): import random startangle=random.random()*6.28 angle=startangle deltaangle=6.28/len(self.distancegrouparray[distance]) for nr in self.distancegrouparray[distance]: self.wordplaces[nr]=[centerx+r*math.cos(angle), centery+r*math.sin(angle)] angle+=deltaangle r+=dr security.declareProtected(perm_view, 'calculateCircleTree') def calculateRayCircleTree(self): "Each new word will be centre of new circle" centerx=self.viewingcentre[0] centery=self.viewingcentre[1] maxr=min(self.viewingbounds[2]-self.leftdistance*1.0/self.viewcoef-self.rightdistance*1.0/self.viewcoef, self.viewingbounds[3]-self.topdistance*1.0/self.viewcoef-self.bottomdistance*1.0/self.viewcoef)/2.0 r=0 dr=maxr/(len(self.distancegrouparray)-1) if not self.distancegrouparray: return self.wordplaces[self.distancegrouparray[0][0]]=[centerx, centery] if len(self.distancegrouparray)==1: return startangle=3.14/4 angle=startangle deltaangle=6.28/len(self.distancegrouparray[1]) angles=[0]*len(self.wordplaces) r+=dr for nr in self.distancegrouparray[1]: self.wordplaces[nr]=[centerx+r*math.cos(angle), centery+r*math.sin(angle)] angles[nr]=angle angle+=deltaangle distance=2 while distance0: deltaangle=3.14/len(v) angle=deltaangle/2-3.14/2+angles[parent] for nr in v: self.wordplaces[nr]= \ [ self.wordplaces[parent][0]+dr*math.cos(angle), self.wordplaces[parent][1]+dr*math.sin(angle) ] angles[nr]=(angles[parent]+angle)/2.0 angle+=deltaangle distance+=1 security.declareProtected(perm_view, 'clearPicture') def clearPicture(self, g, psize=None): "Pildile joonistatakse taustavarviga ristkylik" if psize is None: psize=self.picturesize g.setink(self.backgroundcolor) g.setfill(1) g.rectangle((0, 0, psize[0], psize[1])) g.setfill(0) g.setink(self.wordcolor) security.declareProtected(perm_view, 'pictureX') def pictureX(self, worldx, vcentre=None, vcoef=None, psize=None): "From world coordinates to picture coordinates" if vcentre is None: vcentre=self.viewingcentre if vcoef is None: vcoef=self.viewcoef if psize is None: psize=self.picturesize return (worldx-vcentre[0])*vcoef+psize[0]/2.0 security.declareProtected(perm_view, 'pictureY') def pictureY(self, worldy, vcentre=None, vcoef=None, psize=None): "From world coordinates to picture coordinates" if vcentre is None: vcentre=self.viewingcentre if vcoef is None: vcoef=self.viewcoef if psize is None: psize=self.picturesize return (worldy-vcentre[1])*vcoef+psize[1]/2.0 security.declareProtected(perm_view, 'worldX') def worldX(self, picturex, vcentre=None, vcoef=None, psize=None): "From picture coordinates to world coordinates" if vcentre is None: vcentre=self.viewingcentre if vcoef is None: vcoef=self.viewcoef if psize is None: psize=self.picturesize return (picturex-psize[0]/2.0)/vcoef+vcentre[0] security.declareProtected(perm_view, 'worldY') def worldY(self, picturey, vcentre=None, vcoef=None, psize=None): "From picture coordinates to world coordinates" if vcentre is None: vcentre=self.viewingcentre if vcoef is None: vcoef=self.viewcoef if psize is None: psize=self.picturesize return (picturey-psize[1]/2.0)/vcoef+vcentre[1] security.declareProtected('View', 'drawWords') def drawWords(self, g, vcentre=None, vcoef=None, psize=None): "Koostatakse sonadest pilt" g.setink(self.wordcolor) for i in range(len(self.words)): g.text( ( self.pictureX(self.wordplaces[i][0], vcentre, vcoef, psize), self.pictureY(self.wordplaces[i][1], vcentre, vcoef, psize) ), self.words[i] ) for wi in self.selectedwords: g.rectangle(( self.pictureX(self.wordplaces[wi][0], vcentre, vcoef, psize), self.pictureY(self.wordplaces[wi][1], vcentre, vcoef, psize), self.pictureX(self.wordplaces[wi][0], vcentre, vcoef, psize)+g.textsize(self.words[wi])[0], self.pictureY(self.wordplaces[wi][1], vcentre, vcoef, psize)+g.textsize(self.words[wi])[1] )) security.declareProtected(perm_view, 'drawEdges') def drawEdges(self, g, vcentre=None, vcoef=None, psize=None): "Sonade vahele tommatakse jooned" g.setink(self.linecolor) for nr in range(len(self.words)): for sihtnr in self.relationnumbers[nr]: g.line(( self.pictureX(self.wordplaces[nr][0], vcentre, vcoef, psize), self.pictureY(self.wordplaces[nr][1], vcentre, vcoef, psize), self.pictureX(self.wordplaces[sihtnr][0], vcentre, vcoef, psize), self.pictureY(self.wordplaces[sihtnr][1], vcentre, vcoef, psize) )) if self.selectededge is not None: g.setink(self.selectedlinecolor) g.line(( self.pictureX(self.wordplaces[self.selectededge[0]][0], vcentre, vcoef, psize), self.pictureY(self.wordplaces[self.selectededge[0]][1], vcentre, vcoef, psize), self.pictureX(self.wordplaces[self.selectededge[1]][0], vcentre, vcoef, psize), self.pictureY(self.wordplaces[self.selectededge[1]][1], vcentre, vcoef, psize) )) security.declareProtected(perm_view, 'makePicture') def makePicture(self, type="normal"): "Joonistuskasud sobivas jarjekorras" from PIL import Image, ImageDraw if type=="normal": psize=self.picturesize vcoef=self.viewcoef vcentre=self.viewingcentre if type=="plan": psize=self.planpicturesize b=self.getBounds() #??? if self.viewingbounds[0]+self.viewingbounds[2]>b[0]+b[2]: b[2]=self.viewingbounds[0]+self.viewingbounds[2]-b[0] if self.viewingbounds[1]+self.viewingbounds[3]>b[1]+b[3]: b[3]=self.viewingbounds[1]+self.viewingbounds[3]-b[1] if self.viewingbounds[0]=self.wordplaces[nr][0] and x<=self.wordplaces[nr][0]+g.textsize(self.words[nr])[0]/self.viewcoef and \ y>=self.wordplaces[nr][1] and y<=self.wordplaces[nr][1]+g.textsize(self.words[nr])[1]/self.viewcoef: leitud=nr return leitud def findEdgeInPicture(self, x, y): "Returns edge in place or None" x=float(x) y=float(y) for p1 in range(len(self.words)): for p2 in range(len(self.words)): if p2 in self.relationnumbers[p1] or p1 in self.relationnumbers[p2]: x1=self.wordplaces[p1][0] y1=self.wordplaces[p1][1] x2=self.wordplaces[p2][0] y2=self.wordplaces[p2][1] a=y2-y1 b=x1-x2 c=y1*(x2-x1)-x1*(y2-y1) import math d=abs(a*x+b*y+c)/math.sqrt(a*a+b*b) if d=min(x1, x2)-self.selectingdistance and x<=max(x1, x2)+self.selectingdistance and \ y>=min(y1, y2)-self.selectingdistance and y<=max(y1, y2)+self.selectingdistance: return [p1, p2] return None security.declareProtected(perm_view, 'getPicture') def getPicture(self, REQUEST): "Pilt ekraanile" import cStringIO puhver=cStringIO.StringIO() self.makePicture().save(puhver, 'gif') REQUEST.RESPONSE.setHeader("Content-type", "image/gif") return puhver.getvalue() security.declareProtected(perm_view, 'getPlanPicture') def getPlanPicture(self, REQUEST): "Small picture where visible viewing area location in map" import cStringIO puhver=cStringIO.StringIO() self.makePicture("plan").save(puhver, 'gif') REQUEST.RESPONSE.setHeader("Content-type", "image/gif") return puhver.getvalue() def savePicture(self, failinimi='pilt.gif'): "Pildi salvestus faili" self.makePicture().save(failinimi, 'gif') security.declareProtected(perm_view, 'zoomToBounds') def zoomToBounds(self): "Set all words visible" self.viewingbounds=self.getBounds() self.viewingcentre[0]=self.viewingbounds[0]+self.viewingbounds[2]/2.0 self.viewingcentre[1]=self.viewingbounds[1]+self.viewingbounds[3]/2.0 self.viewcoef=min(self.picturesize[0]*1.0/self.viewingbounds[2], self.picturesize[1]*1.0/self.viewingbounds[3]) security.declareProtected(perm_view, 'recalculateViewingBounds') def recalculateViewingBounds(self): "Recalculates viewing bounds using viewingcentre, picture size and viewcoef" self.viewingbounds=[ self.viewingcentre[0]-self.picturesize[0]/2.0/self.viewcoef, self.viewingcentre[1]-self.picturesize[1]/2.0/self.viewcoef, self.picturesize[0]*1.0/self.viewcoef, self.picturesize[1]*1.0/self.viewcoef ] security.declareProtected(perm_view, 'calculateZoomWithPoint') def calculateZoomWithPoint(self, x, y, direction='bigger'): "Calculates new displaying properties using user click data" self.viewingcentre=[x, y] if direction=="bigger": self.viewcoef*=(1+self.zoomcoef) if direction=="smaller": self.viewcoef/=(1.0+self.zoomcoef) self.recalculateViewingBounds() security.declareProtected(perm_view, 'checkPlanPlacing') def checkPlanPlacing(self, REQUEST): "If user changes location clicking to plan" if hasattr(REQUEST, 'plan1.x') and hasattr(REQUEST, 'plan1.y'): psize=self.planpicturesize b=self.getBounds() vcentre=[b[0]+b[2]/2.0, b[1]+b[3]/2] vcoef=min(psize[0]*1.0/b[2], psize[1]*1.0/b[3]) self.viewingcentre[0]=self.worldX(int(getattr(REQUEST, 'plan1.x')), vcentre, vcoef, psize) self.viewingcentre[1]=self.worldY(int(getattr(REQUEST, 'plan1.y')), vcentre, vcoef, psize) self.recalculateViewingBounds() security.declareProtected(perm_edit, 'checkNewWords') def checkNewWords(self, REQUEST): "Add new words to picture, if they exists" if hasattr(REQUEST, 'addnewword'): if len(REQUEST.newwords)>0: wds=REQUEST.newwords.split("\n") for wd in wds: if len(wd)>0: self.addWord(wd) self.selectSoloIcon(0) security.declareProtected(perm_view, 'checkSampleData') def checkSampleData(self, REQUEST): "If sample data button is pressed" if hasattr(REQUEST, 'sampledata'): self.setSampleData() security.declareProtected(perm_view, 'checkClearAll') def checkClearAll(self, REQUEST): "If sample data button is pressed" if hasattr(REQUEST, 'clearall'): self.initializeVariables() security.declareProtected(perm_view, 'checkCommands') def checkCommands(self, REQUEST): "Check commands from Web page" if hasattr(REQUEST, 'actionnr'): self.setActiveAction(REQUEST.actionnr) # self.checkViewpointMoving(REQUEST) self.checkPlanPlacing(REQUEST) self.checkNewWords(REQUEST) self.checkSampleData(REQUEST) self.checkClearAll(REQUEST) self.selectedarea=None def wmap_pichandler(self, REQUEST, pnr): "Icon click handler" pnr=int(pnr) self.additionalpictures=[] if pnr>=8 and pnr<=11: #arrows if pnr==8: self.viewingcentre[0]-=self.viewingbounds[2]/2.0 if pnr==9: self.viewingcentre[0]+=self.viewingbounds[2]/2.0 if pnr==10: self.viewingcentre[1]-=self.viewingbounds[3]/2.0 if pnr==11: self.viewingcentre[1]+=self.viewingbounds[3]/2.0 self.recalculateViewingBounds() if pnr==6: self.selectSoloIcon(6) self.activeaction=0 #Horizontal tree if pnr==7: self.selectSoloIcon(7) self.activeaction=6 #RayCircleTree if pnr==2: self.selectSoloIcon(2) # self.activeaction=7 #Zoom Bigger if pnr==3: self.selectSoloIcon(3) # self.activeaction=8 #Zoom smaller if pnr==4: self.selectSoloIcon(4) self.activeaction=2 #Add edge if pnr==5: #removebuttonclick self.hideSelectedWords() if self.selectededge: self.removeEdge(self.selectededge[0], self.selectededge[1]) self.selectededge=None if pnr==1: self.selectSoloIcon(1) self.activeaction=9 #Select area self.pictureselections[12]=1 if pnr==0: self.selectSoloIcon(0) self.activeaction=11 #Selecting arrow if pnr==12: self.selectSoloIcon(12) if pnr==13: #Selection area submenu self.selectSoloIcon(13) self.selectedarea=None self.selectedareafirstclick=None if pnr==14: #unselect all self.selectedwords=[] if pnr==18: #Selection move left self.moveSelection(-1, 0) if pnr==19: #Selection move right self.moveSelection( 1, 0) if pnr==20: #Selection move up self.moveSelection( 0, -1) if pnr==21: #Selection move down self.moveSelection( 0, 1) if pnr==22: #Edit menu self.pictureselections[22]=1-self.pictureselections[22] if self.pictureselections[22]: self.selectSoloIcon(4) else: if self.pictureselections[4] or \ self.pictureselections[6] or \ self.pictureselections[7]: self.selectSoloIcon(0) if pnr==23: #Select menu self.pictureselections[23]=1-self.pictureselections[23] if self.pictureselections[23]: self.selectSoloIcon(12) else: if self.pictureselections[12] or \ self.pictureselections[13]: self.selectSoloIcon(0) if pnr==24: #Zoom menu self.pictureselections[24]=1-self.pictureselections[24] if self.pictureselections[24]: self.selectSoloIcon(2) else: if self.pictureselections[2] or \ self.pictureselections[3]: self.selectSoloIcon(0) if pnr==25: #zoom to bounds self.zoomToBounds() # if self.activeaction==9: # self.additionalpictures=self.selectpictures REQUEST.RESPONSE.redirect(self.absolute_url()+'/wmapindex') def selectSoloIcon(self, pnr): "Only this icon will be selected" for i in range(len(self.pictureselections)): if i not in self.menuicons: self.pictureselections[i]=0 self.pictureselections[pnr]=1 self.selectededge=None security.declareProtected(perm_view, 'wmapindex_handler') def wmapindex_handler(self, REQUEST): "ZPT form handler" self.checkCommands(REQUEST) if hasattr(REQUEST, 'map1.x') and hasattr(REQUEST, 'map1.y'): x=self.worldX(int(getattr(REQUEST, 'map1.x'))) y=self.worldY(int(getattr(REQUEST, 'map1.y'))) if self.pictureselections[6]: self.startHorizontalTreeCalculation(x, y) # if self.activeaction==1: # self.startMoving(x, y) if self.pictureselections[4]: self.addEdgeInPicture(x, y) # if self.activeaction==3: # self.removeEdgeFromPicture(x, y) # if self.activeaction==4: # self.hideVertex(x, y) # if self.activeaction==5: # self.startCircleTreeCalculation(x, y) if self.pictureselections[7]: self.startRayCircleTreeCalculation(x, y) if self.pictureselections[2]: self.calculateZoomWithPoint(x, y, "bigger") if self.pictureselections[3]: self.calculateZoomWithPoint(x, y, "smaller") if self.pictureselections[12] or self.pictureselections[0]: self.selectingPointerClick(x, y) if self.pictureselections[13]: self.selectedAreaClick(x, y) # if self.activeaction==10: # self.moveSelectedArea(x, y) # if self.pictureselections[0]: # self.selectArrow(x, y) REQUEST.RESPONSE.redirect('wmapindex') def moveSelection(self, dx, dy): "Move selected words" dx*=self.movingdistanceinscreen/self.viewcoef dy*=self.movingdistanceinscreen/self.viewcoef for wi in self.selectedwords: self.wordplaces[wi][0]+=dx self.wordplaces[wi][1]+=dy security.declareProtected(perm_view, 'selectArrow') def selectArrow(self, x, y): "Selecting with arrow" self.selectedwords=[] self.selectededge=None wi=self.findWordInPicture(x, y) if wi!=-1: self.selectedwords.append(wi) return self.selectededge=self.findEdgeInPicture(x, y) security.declareProtected(perm_view, 'addEdgeInPicture') def addEdgeInPicture(self, x, y): "Adding edge" sona=self.findWordInPicture(x, y) if sona==-1: self.selectedwords=[] return if not self.selectedwords: self.selectedwords.append(sona) return self.addEdge(self.selectedwords[0], sona) self.selectedwords=[] security.declareProtected(perm_view, 'addEdge') def addEdge(self, word1, word2): "Adding edge data" wordmin=word1 wordmax=word2 if word1>word2: wordmin=word2 wordmax=word1 if wordmax not in self.relationnumbers[wordmin]: self.relationnumbers[wordmin].append(wordmax) if wordmin not in self.relationnumbers[wordmax]: self.relationnumbers[wordmax].append(wordmin) security.declareProtected(perm_view, 'removeEdgeFromPicture') def removeEdgeFromPicture(self, x, y): "Removing edge in coordinaates" e=self.findEdgeInPicture(x, y) if e is None: self.selectededge=None return if e==self.selectededge: self.removeEdge(e[0], e[1]) self.selectededge=None return self.selectededge=e security.declareProtected(perm_view, 'removeEdge') def removeEdge(self, word1, word2): if word1 in self.relationnumbers[word2]: self.relationnumbers[word2].remove(word1) if word2 in self.relationnumbers[word1]: self.relationnumbers[word1].remove(word2) security.declareProtected(perm_view, 'hideSelectedWords') def hideSelectedWords(self): "Removing word edges and set word content empty" hidded=[] for sona in self.selectedwords: for v in range(len(self.relationnumbers)): if sona in self.relationnumbers[v]: self.removeEdge(v, sona) for nr in self.relationnumbers[sona]: self.removeEdge(sona, nr) self.words[sona]="" hidded.append(sona) self.selectedwords=[] security.declareProtected(perm_view, 'addWord') def addWord(self, word): "Add word to graph and picture" self.words.append(word) self.relationnumbers.append([]) x=self.viewingbounds[0]+self.leftdistance*1.0/self.viewcoef y=self.viewingbounds[1]+self.topdistance*1.0/self.viewcoef while self.findWordInPicture(x, y)>=0: y+=1.0/self.viewcoef self.wordplaces.append([x, y]) security.declareProtected(perm_view, 'startHorizontalTreeCalculation') def startHorizontalTreeCalculation(self, x, y): "Hiirevajutusest saadud andmed" sona=self.findWordInPicture(x, y) if sona!=-1: self.calculateDistances(sona) self.calculateHorizontalTree() security.declareProtected(perm_view, 'startCircleTreeCalculation') def startCircleTreeCalculation(self, x, y): "Hiirevajutusest saadud andmed" sona=self.findWordInPicture(x, y) if sona!=-1: self.calculateDistances(sona) self.calculateCircleTree() security.declareProtected(perm_view, 'startRayCircleTreeCalculation') def startRayCircleTreeCalculation(self, x, y): "Hiirevajutusest saadud andmed" sona=self.findWordInPicture(x, y) if sona!=-1: self.calculateDistances(sona) self.calculateRayCircleTree() # security.declareProtected(perm_view, 'startMoving') # def startMoving(self, x, y): # selectword=self.findWordInPicture(x, y) # if self.selectedmovevertex is not None: # if selectword==-1: #if in previous time was word selected and now # #pointed to free place # self.wordplaces[self.selectedmovevertex]=[float(x), float(y)] # self.selectedmovevertex=None # if selectword!=-1: # self.selectedmovevertex=selectword security.declareProtected(perm_view, 'selectingPointerClick') def selectingPointerClick(self, x, y): "Mouse click, when selecting function is active" wi=self.findWordInPicture(x, y) if wi!=-1: if wi in self.selectedwords: self.selectedwords.remove(wi) else: if self.pictureselections[12]: #if select arrow in selection submenu self.selectedwords.append(wi) if self.pictureselections[0]: self.selectedwords=[wi] else: self.selectededge=self.findEdgeInPicture(x, y) if len(self.selectedwords)==1: self.wordplaces[self.selectedwords[0]][0]=x self.wordplaces[self.selectedwords[0]][1]=y self.selectedwords=[] security.declareProtected(perm_view, 'selectedAreaClick') def selectedAreaClick(self, x, y): "Mouse click, when selecting function is active" if self.selectedareafirstclick is None and self.selectedarea is None: self.selectedareafirstclick=[x, y] return if self.selectedareafirstclick is not None and \ self.selectedarea is None: minx=min(self.selectedareafirstclick[0], x) maxx=max(self.selectedareafirstclick[0], x) miny=min(self.selectedareafirstclick[1], y) maxy=max(self.selectedareafirstclick[1], y) #self.selectedarea=[ # minx, miny, maxx-minx, maxy-miny #] self.selectedareafirstclick=None for wi in range(len(self.wordplaces)): if ( self.wordplaces[wi][0]>=minx and self.wordplaces[wi][0]<=maxx and self.wordplaces[wi][1]>=miny and self.wordplaces[wi][1]<=maxy ): if wi not in self.selectedwords: self.selectedwords.append(wi) return if self.selectedarea: if not self.isInSelectedArea(x, y): self.selectedareafirstclick=[x, y] self.selectedarea=None security.declareProtected(perm_view, 'isInSelectedArea') def isInSelectedArea(self, x, y): "test, is point in selected area" if not self.selectedarea: return 0 if x>=self.selectedarea[0] and x<=self.selectedarea[0]+self.selectedarea[2] and \ y>=self.selectedarea[1] and y<=self.selectedarea[1]+self.selectedarea[3]: return 1 return 0 security.declareProtected(perm_view, 'moveSelectedArea') def moveSelectedArea(self, x, y): "Left upper point of area to specified value. Moving all words in area" words=self.findWordsInSelectedArea() if words: dx=x-self.selectedarea[0] dy=y-self.selectedarea[1] for nr in words: self.wordplaces[nr][0]+=dx self.wordplaces[nr][1]+=dy self.selectedarea=None security.declareProtected(perm_view, 'findWordsInSelectedArea') def findWordsInSelectedArea(self): "List of word indexes" result=[] for nr in range(len(self.wordplaces)): if self.isInSelectedArea(self.wordplaces[nr][0], self.wordplaces[nr][1]): result.append(nr) return result security.declareProtected(perm_view, 'toString') def toString(self): "Vahetulemused statistika tarbeks" t=str(self.words)+" ja\n"+ \ " relationnumbers:" +str(self.relationnumbers) +\ " bounds:"+str(self.getBounds())+\ " viewingbounds:"+str(self.viewingbounds) return t def getBounds(self): "Minimal rectangle to place words. x, y, width, height" if len(self.wordplaces)==0: return [0, 0, self.picturesize[0], self.picturesize[1]] minx=maxx=self.wordplaces[0][0] miny=maxy=self.wordplaces[0][1] pilt=Image.new('RGB', [5, 5]) g=ImageDraw.ImageDraw(pilt) for nr in range(len(self.wordplaces)): place=self.wordplaces[nr] if place[0]maxx: maxx=place[0]+g.textsize(self.words[nr])[0] if place[1]maxy: maxy=place[1]+g.textsize(self.words[nr])[1] # if self.viewingbounds[0]maxx: # maxx=self.viewingbounds[0]+self.viewingbounds[2] # if self.viewingbounds[1]+self.viewingbounds[3]>maxy: # maxy=self.viewingbounds[1]+self.viewingbounds[3] return [minx, miny, maxx-minx, maxy-miny] security.declareProtected(perm_view, 'isAllWordsVisible') def areAllWordsVisible(self): "True if nothing is invisible in big picture" visible=1 b=self.getBounds() vb=self.viewingbounds if b[0]vb[0]+vb[2]: visible=0 if b[1]+b[3]>vb[1]+vb[3]: visible=0 return visible security.declareProtected(perm_view, 'getActions') def getActions(self): "Return available actions list" a=[ "Horizontal tree", "Move word", "Add edge", "Remove edge", "Remove word", "Circle tree", "Ray Circle tree", "Zoom bigger", "Zoom smaller", "Select area", "Move area" ] return a security.declareProtected(perm_view, 'getActiveAction') def getActiveAction(self): "Current action" return "ac: "+str(self.activeaction) security.declareProtected(perm_view, 'setActiveAction') def setActiveAction(self, action): "setting property" self.activeaction=int(action) return self.activeaction def list_parents_to_top(): "For breadgrumbs" return [] security.declareProtected(perm_view, 'setSampleData') def setSampleData(self): "algandmed" gr={ "Tallinn": { "Aegviidu": "", "Valkla": "", "Maardu": "", "Rakvere": "", "Kuressaare": "", }, "Aegviidu": {}, "Valkla": {}, "Maardu":{}, "Rakvere": {"Roela": ""}, "Roela": {}, "Kuressaare":{"Kihelkonna": "", "Mustjala": ""}, "Kihelkonna": {}, "Mustjala": {"Tagala":""}, "Tagala": {}, } self.initializeVariables() self.readData(gr) self.calculateDistances(3) self.calculateHorizontalTree() self.selectedwords=[] return gr def getWordmapTree(self): "Wordmaps to root" result=[] map=self while map.meta_type=='WordMap': result.append(map) map=map.aq_parent result.reverse() return result def get_name(self): "name to breadgrumbs" return "" security.declareProtected(perm_view, 'index_html') def index_html(self, REQUEST): "Index file" return self.wmapindex(self, REQUEST) if __name__=="__main__": ""