% MetaUML, a MetaPost library for typesetting exquisite UML diagrams. % Copyright (C) 2005 Ovidiu Gheorghies % % This program 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. % % This program 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 this program; if not, write to the Free Software % Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. if known _metauml_class_mp: expandafter endinput fi; _metauml_class_mp:=1; input metauml_defaults; input util_log; input util_picture; input util_picture_stack; input util_shade; string accessPublic, accessProtected, accessPrivate; accessPublic:="+"; accessProtected:="#"; accessPrivate:="-"; vardef ClassInfo@#= attributes(@#); var(numeric) featureAccessSpacing, accessWidth, accessHeight; var(color) foreColor, borderColor; FontInfo.@#nameFont(metauml_defaultFont, defaultscale); FontInfo.@#attributeFont (metauml_defaultFont, defaultscale); FontInfo.@#methodFont (metauml_defaultFont, defaultscale); FontInfo.@#stereotypeFont(metauml_defaultFont, .7); ShadeInfo.@#iShade; @#featureAccessSpacing := 2; @#accessWidth := 7; @#accessHeight := 6.75; @#foreColor := .9white; @#borderColor := black; PictureInfo.@#iName (2, 2, 1, 3)(@#nameFont); PictureInfo.@#iStereotype(2, -5, 2, 2)(@#stereotypeFont); PictureInfo.@#iAttribute (2, 2, 1.25, 0)(@#attributeFont); PictureInfo.@#iMethod (2, 2, 1.25, 0)(@#methodFont); PictureStackInfo.@#iStereotypeStack(2, 2, 1, 1)(5.5)(@#iStereotype); PictureStackInfo.@#iAttributeStack (2, 2, 2.5, 2)(10.5)(@#iAttribute); % 8.5 PictureStackInfo.@#iMethodStack (2, 2, 2.5, 2)(10.5)(@#iMethod); @#iAttributeStack.iPict.bottom := 2; %@#iAttributeStack.iPict.boxed := 1; @#iMethodStack.iPict.bottom := 2; %@#iMethodStack.iPict.boxed := 1; LockInfo.@#iLock(@#accessWidth, @#accessHeight, .6, .15, .55, .4white, .6white, .7white, .3white); @#iName.ignoreNegativeBase := 1; @#iAttributeStack.iPict.ignoreNegativeBase := 1; @#iMethodStack.iPict.ignoreNegativeBase := 1; @#iStereotypeStack.iPict.ignoreNegativeBase := 1; enddef; vardef ClassInfoCopy@#(text src)= log "ClassInfoCopy: Copying class"; attributes(@#); var(numeric) featureAccessSpacing, accessWidth, accessHeight; var(color) foreColor, borderColor; FontInfoCopy.@#nameFont(src.nameFont); FontInfoCopy.@#attributeFont(src.attributeFont); FontInfoCopy.@#methodFont(src.methodFont); FontInfoCopy.@#stereotypeFont(src.stereotypeFont); ShadeInfoCopy.@#iShade(src.iShade); @#featureAccessSpacing := src.featureAccessSpacing; @#accessWidth := src.accessWidth; @#accessHeight := src.accessHeight; @#foreColor := src.foreColor; @#borderColor := src.borderColor; PictureInfoCopy.@#iName (src.iName); PictureInfoCopy.@#iStereotype(src.iStereotype); PictureInfoCopy.@#iAttribute (src.iAttribute); PictureInfoCopy.@#iMethod (src.iMethod); PictureStackInfoCopy.@#iStereotypeStack(src.iStereotypeStack); PictureStackInfoCopy.@#iAttributeStack (src.iAttributeStack); PictureStackInfoCopy.@#iMethodStack (src.iMethodStack); LockInfoCopy.@#iLock(src.iLock); enddef; ClassInfo.iClass; ClassInfoCopy.iInterface(iClass); iInterface.iName.iFont.name := metauml_defaultFontOblique; ClassInfoCopy.iAbstractClass(iInterface); % % CLASS % vardef defClass@#(expr pname) = ObjectEquations(@#); @#className := "Class"; string @#name; @#name = pname; numeric @#nStereotypes; string @#stereotypes[]; string @#attributes[]; string @#attributesAccess[]; string @#methods[]; string @#methodsAccess[]; numeric @#nAttrs; numeric @#nMethods; @#nStereotypes := 0; @#nAttrs := 0; @#nMethods := 0; enddef; vardef addAttribute@#(expr pcontent) = string access; access := substring(0,1) of pcontent; if (not (access = accessPublic)) and (not (access = accessPrivate)) and (not (access = accessProtected)): @#.attributes[@#.nAttrs] := pcontent; @#.attributesAccess[@#.nAttrs] := accessProtected; else: save from; from := 1; if (substring(1,2) of pcontent) = " ": from := 2; fi; @#.attributes[@#.nAttrs] := substring(from, infinity) of pcontent; @#.attributesAccess[@#.nAttrs] := access; fi; @#.nAttrs := @#.nAttrs + 1; enddef; vardef addMethod@#(expr pcontent) = string access; access := substring(0,1) of pcontent; if (not (access = accessPublic)) and (not (access = accessPrivate)) and (not (access = accessProtected)): @#.methods[@#.nMethods] := pcontent; @#.methodsAccess[@#.nMethods] := accessProtected; else: @#.methods[@#.nMethods] := substring(1, 999) of pcontent; @#.methodsAccess[@#.nMethods] := access; fi; @#.nMethods := @#.nMethods + 1; enddef; vardef classStereotype@#(expr pcontent) = @#stereotypes[@#nStereotypes] := pcontent; @#nStereotypes := @#nStereotypes + 1; enddef; vardef classStereotypes@#(text stereotypes)= for stereotype = stereotypes: classStereotype@#(stereotype); endfor; enddef; vardef EClass@#(text _info)(expr name)(text attributes)(text methods)= log "EClass begin: " & str @#; defClass@#(name); log "Copying class info"; ClassInfoCopy.@#info(_info); for a=attributes: log "Adding attribute ", a; addAttribute@#(a); endfor; for m=methods: log "Adding method ", m; addMethod@#(m); endfor; enddef; vardef Class@#(expr name)(text attributes)(text methods)= EClass@#(iClass)(name)(attributes)(methods); enddef; vardef Interface@#(expr name)(text methods)= EClass@#(iInterface)(name)()(methods); enddef; vardef EInterface@#(text _info)(expr name)(text methods)= EClass@#(_info)(name)()(methods); enddef; vardef AbstractClass@#(expr name)(text attributes)(text methods)= EClass@#(iAbstractClass)(name)(attributes)(methods); enddef; vardef EAbstractClass@#(text _info)(expr name)(text methods)= EClass@#(_info)(name)()(methods); enddef; vardef Class_border@#= objectBox(@#) enddef; vardef Class_layout@# = if @#layedout = 1: log "Class " & (str @#) & " has already been layed out"; else: @#layedout := 1; log "Class layout: " & (str @#); @#maxFeatureWidth := 0; EPictureStack.@#stereotypeStack(@#info.iStereotypeStack) (scantokens listArray(@#stereotypes)(@#nStereotypes))("vcenterbase"); EPicture.@#namePict(@#info.iName)(@#name); EPictureStack.@#attributeStack(@#info.iAttributeStack) (scantokens listArray(@#attributes)(@#nAttrs))("vleftbase"); EPictureStack.@#methodStack(@#info.iMethodStack) (scantokens listArray(@#methods)(@#nMethods))("vleftbase"); layoutObjects(@#stereotypeStack, @#namePict, @#attributeStack, @#methodStack); log "Computing maxFeatureWidth"; log @#stereotypeStack.width; log @#namePict.width; log @#attributeStack.width; log @#methodStack.width; log "..."; @#maxFeatureWidth := lmax(@#stereotypeStack.width, @#namePict.width, @#attributeStack.width, @#methodStack.width); log "Done computing maxFeatureWidth"; log "max feature width: " & decimal @#maxFeatureWidth; @#namePict.midx = @#midx; @#stereotypeStack.midx = @#namePict.midx; @#stereotypeStack.top = @#top; @#namePict.top = @#stereotypeStack.bottom; @#attributeStack.top = @#namePict.bottom; @#methodStack.top = @#attributeStack.bottom; @#attributeStack.left = @#methodStack.left = @#left + @#info.accessWidth + @#info.featureAccessSpacing; @#width = @#maxFeatureWidth + @#info.accessWidth + @#info.featureAccessSpacing; @#bottom = @#methodStack.bottom; log "Class layout done..."; fi; enddef; vardef Class_paintAccess@#(expr _access, _se) = save lock; ELock.lock(@#info.iLock)(_access); lock.se = _se; drawObject(lock); enddef; vardef Class_drawFeatures@#= log "Drawing stereotypes"; drawObject(@#stereotypeStack); log "Drawing name"; drawObject(@#namePict); log "Drawing attribute stack"; drawObject(@#attributeStack); log "Drawing method stack"; drawObject(@#methodStack); log "********************************** Drawing access locks"; for i = 0 upto @#nAttrs-1: log @#attributesAccess[i]; Class_paintAccess@#(@#attributesAccess[i], @#attributeStack.pict[i].sw + (-@#info.featureAccessSpacing, @#info.iAttributeStack.iPict.bottom)); endfor; for i = 0 upto @#nMethods-1: log @#methodsAccess[i]; Class_paintAccess@#(@#methodsAccess[i], @#methodStack.pict[i].sw + (-@#info.featureAccessSpacing, @#info.iMethodStack.iPict.bottom)); endfor; enddef; vardef Class_paintSkin@# = log "Painting class skin..."; nameAttributeY := @#attributeStack.top; attributeMethodY := @#methodStack.top; %fill Class_border.@# shifted (@#info.shade,-@#info.shade) % withcolor .7white withpen currentpen scaled 1; drawObjectShade(@#); fill Class_border.@# withcolor @#info.foreColor; draw Class_border.@# withcolor @#info.borderColor; draw (xpart @#nw, nameAttributeY)--(xpart @#se, nameAttributeY) withcolor @#info.borderColor; draw (xpart @#nw, attributeMethodY)--(xpart @#se, attributeMethodY) withcolor @#info.borderColor; enddef; vardef Class_draw@#= log "draw class begin..."; Class_layout.@#; objectEnsurePositioning.@#; Class_paintSkin.@#; Class_drawFeatures.@#; enddef; vardef Class_setDebugMode@#= @#.info.iName.boxed := 1; @#.info.iStereotypeStack.boxed := 1; @#.info.iStereotypeStack.iPict.boxed := 1; @#.info.iAttributeStack.boxed := 1; @#.info.iAttributeStack.iPict.boxed := 1; @#.info.iMethodStack.boxed := 1; @#.info.iMethodStack.iPict.boxed := 1; enddef;