Compare commits

...

No commits in common. "master" and "experimental" have entirely different histories.

90 changed files with 56787 additions and 170 deletions

94
.gitignore vendored
View File

@ -1,94 +0,0 @@
# ---> CVS
/CVS/*
**/CVS/*
.cvsignore
*/.cvsignore
# ---> Java
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
# ---> Eclipse
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# CDT- autotools
.autotools
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
# Annotation Processing
.apt_generated/
.apt_generated_test/
# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.worksheet
# Uncomment this line if you wish to ignore the project description file.
# Typically, this file would be tracked if it contains build/dependency configurations:
#.project

73
LICENSE
View File

@ -1,73 +0,0 @@
Eclipse Public License - v 1.0
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
1. DEFINITIONS
"Contribution" means:
a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and
b) in the case of each subsequent Contributor:
i) changes to the Program, and
ii) additions to the Program;
where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.
"Contributor" means any person or entity that distributes the Program.
"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.
"Program" means the Contributions distributed in accordance with this Agreement.
"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.
2. GRANT OF RIGHTS
a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.
b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
3. REQUIREMENTS
A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:
a) it complies with the terms and conditions of this Agreement; and
b) its license agreement:
i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and
iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.
When the Program is made available in source code form:
a) it must be made available under this Agreement; and
b) a copy of this Agreement must be included with each copy of the Program.
Contributors may not remove or alter any copyright notices contained within the Program.
Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.
4. COMMERCIAL DISTRIBUTION
Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.
For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.
5. NO WARRANTY
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.
6. DISCLAIMER OF LIABILITY
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
7. GENERAL
If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.
All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.
Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved.
This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation.

View File

@ -1,3 +0,0 @@
# Eclipse-PyUML
Fork of https://sourceforge.net/projects/eclipse-pyuml/ to make it compliant with last Eclipse version. The official project seems to be abandoned as the code has not been migrated outside CVS repository. The transfer to git has been done by cvs2git .

17
pyUML_feature/.project Executable file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>pyUML_feature</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.pde.FeatureBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.FeatureNature</nature>
</natures>
</projectDescription>

1
pyUML_feature/build.properties Executable file
View File

@ -0,0 +1 @@
bin.includes = feature.xml

134
pyUML_feature/feature.xml Executable file
View File

@ -0,0 +1,134 @@
<?xml version="1.0" encoding="UTF-8"?>
<feature
id="pyUML-experimental"
label="PyUML Feature (Experimental)"
version="1.2.2"
provider-name="Freie University Berlin, Germany, Martin Dittmar">
<description url="http://www.example.com/description">
[Enter Feature Description here.]
</description>
<copyright>
Freie Universität Berlin / Martin Dittmar
</copyright>
<license url="http://www.eclipse.org/legal/epl-v10.html">
Eclipse Public License - v 1.0
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (&quot;AGREEMENT&quot;). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT&apos;S ACCEPTANCE OF THIS AGREEMENT.
1. DEFINITIONS
&quot;Contribution&quot; means:
a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and
b) in the case of each subsequent Contributor:
i) changes to the Program, and
ii) additions to the Program;
where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution &apos;originates&apos; from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor&apos;s behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.
&quot;Contributor&quot; means any person or entity that distributes the Program.
&quot;Licensed Patents&quot; mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.
&quot;Program&quot; means the Contributions distributed in accordance with this Agreement.
&quot;Recipient&quot; means anyone who receives the Program under this Agreement, including all Contributors.
2. GRANT OF RIGHTS
a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.
b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient&apos;s responsibility to acquire that license before distributing the Program.
d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
3. REQUIREMENTS
A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:
a) it complies with the terms and conditions of this Agreement; and
b) its license agreement:
i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and
iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.
When the Program is made available in source code form:
a) it must be made available under this Agreement; and
b) a copy of this Agreement must be included with each copy of the Program.
Contributors may not remove or alter any copyright notices contained within the Program.
Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.
4. COMMERCIAL DISTRIBUTION
Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (&quot;Commercial Contributor&quot;) hereby agrees to defend and indemnify every other Contributor (&quot;Indemnified Contributor&quot;) against any losses, damages and costs (collectively &quot;Losses&quot;) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.
For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor&apos;s responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.
5. NO WARRANTY
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.
6. DISCLAIMER OF LIABILITY
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
7. GENERAL
If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient&apos;s patent(s), then such Recipient&apos;s rights granted under Section 2(b) shall terminate as of the date such litigation is filed.
All Recipient&apos;s rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient&apos;s rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient&apos;s obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.
Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved.
This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation.
</license>
<requires>
<import plugin="org.eclipse.core.resources"/>
<import plugin="org.eclipse.core.runtime"/>
<import plugin="org.eclipse.jface"/>
<import plugin="org.eclipse.ui"/>
<import plugin="org.eclipse.ui.ide"/>
<import plugin="org.eclipse.emf.common"/>
<import plugin="org.eclipse.emf.ecore"/>
<import plugin="org.eclipse.uml2.uml"/>
<import plugin="org.eclipse.gmf.runtime.common.core"/>
<import plugin="org.eclipse.gmf.runtime.diagram.core"/>
<import plugin="org.eclipse.gmf.runtime.common.ui"/>
<import plugin="org.eclipse.gmf.runtime.diagram.ui"/>
<import plugin="org.eclipse.gmf.runtime.diagram.ui.resources.editor"/>
<import plugin="org.python.pydev" version="1.4.6" match="greaterOrEqual"/>
<import plugin="org.python.pydev.core"/>
<import plugin="org.python.pydev.parser"/>
<import plugin="org.eclipse.uml2.diagram.clazz"/>
<import feature="org.python.pydev.feature"/>
</requires>
<plugin
id="pyUml-experimental"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
</feature>

10
pyUml/.classpath Executable file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry exported="true" kind="lib" path="bin/"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="lib" path="lib/refactoring.jar"/>
<classpathentry kind="lib" path="/pydev"/>
<classpathentry kind="output" path="bin"/>
</classpath>

28
pyUml/.project Executable file
View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>pyUml</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

4
pyUml/.pydevproject Executable file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?eclipse-pydev version="1.0"?>
<pydev_project/>

View File

@ -0,0 +1,5 @@
#Tue Jan 08 23:39:24 CET 2008
eclipse.preferences.version=1
encoding//custom-src/pyUMLProfile.umlprofile_diagram=UTF-8
encoding//documents/pythonTree.uml=UTF-8
encoding//documents/pythonTree.umlclass_diagram=UTF-8

View File

@ -0,0 +1,3 @@
#Tue Nov 13 00:31:02 CET 2007
eclipse.preferences.version=1
org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false

View File

@ -0,0 +1,3 @@
#Tue May 12 13:34:43 CEST 2009
eclipse.preferences.version=1
resolve.requirebundle=false

37
pyUml/META-INF/MANIFEST.MF Executable file
View File

@ -0,0 +1,37 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: PyUML (Experimental)
Bundle-SymbolicName: pyUml-experimental;singleton:=true
Bundle-Version: 1.2.2
Bundle-Activator: pyUML.plugin.Activator
Eclipse-LazyStart: true
Bundle-ClassPath: lib/refactoring.jar,
.,
src/,
bin/
Bundle-Vendor: Freie University Berlin, Germany, Martin Dittmar
Export-Package: pyUML.actions,
pyUML.backend,
pyUML.exceptions,
pyUML.listeners,
pyUML.plugin,
pyUML.pythonTree,
pyUML.refactoring,
pyUML.views
Require-Bundle: org.eclipse.core.resources,
org.eclipse.core.runtime,
org.eclipse.jface,
org.eclipse.ui,
org.eclipse.ui.ide,
org.eclipse.emf.common,
org.eclipse.emf.ecore,
org.eclipse.uml2.uml,
org.eclipse.gmf.runtime.common.core,
org.eclipse.gmf.runtime.diagram.core,
org.eclipse.gmf.runtime.common.ui,
org.eclipse.gmf.runtime.diagram.ui,
org.eclipse.gmf.runtime.diagram.ui.resources.editor,
org.python.pydev,
org.python.pydev.core,
org.python.pydev.parser,
org.eclipse.uml2.diagram.clazz

12
pyUml/build.properties Executable file
View File

@ -0,0 +1,12 @@
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.,\
plugin.xml,\
lib/refactoring.jar,\
images/,\
src/,\
bin/
additional.bundles = org.eclipse.ui.ide
src.includes = src/,\
.usedDocuments/

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<uml:Profile xmi:version="2.1" xmlns:xmi="http://schema.omg.org/spec/XMI/2.1" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:uml="http://www.eclipse.org/uml2/2.1.0/UML" xmi:id="_7Y-UAKi8Edyr_pXRyLU3wA" name="PyUMLProfile " metaclassReference="_ZtOxIKjHEdym48zZ96s2nA" metamodelReference="_bkzWwKjHEdym48zZ96s2nA">
<eAnnotations xmi:id="_oyijYKjHEdym48zZ96s2nA" source="http://www.eclipse.org/uml2/2.0.0/UML">
<contents xmi:type="ecore:EPackage" xmi:id="_bm4k8KjIEdym48zZ96s2nA" name="PyUMLProfile" nsURI="http:///schemas/PyUMLProfile/_bm06kKjIEdym48zZ96s2nA/1" nsPrefix="PyUMLProfile">
<eClassifiers xmi:type="ecore:EClass" xmi:id="_bm4k8ajIEdym48zZ96s2nA" name="BeanClass">
<eAnnotations xmi:id="_bm4k8qjIEdym48zZ96s2nA" source="http://www.eclipse.org/uml2/2.0.0/UML" references="_e8aLwKjHEdym48zZ96s2nA"/>
<eAnnotations xmi:id="_bm4k86jIEdym48zZ96s2nA" source="duplicates">
<contents xmi:type="ecore:EReference" xmi:id="_bm4k9KjIEdym48zZ96s2nA" name="base_Class" ordered="false" lowerBound="1">
<eAnnotations xmi:id="_bm4k9ajIEdym48zZ96s2nA" source="redefines" references="_bm4k-ajIEdym48zZ96s2nA"/>
<eType xmi:type="ecore:EClass" href="http://www.eclipse.org/uml2/2.1.0/UML#//Class"/>
</contents>
</eAnnotations>
<eStructuralFeatures xmi:type="ecore:EAttribute" xmi:id="_bm4k96jIEdym48zZ96s2nA" name="TestProperty" ordered="false" lowerBound="1">
<eType xmi:type="ecore:EDataType" href="http://www.eclipse.org/emf/2002/Ecore#//EString"/>
</eStructuralFeatures>
<eStructuralFeatures xmi:type="ecore:EReference" xmi:id="_bm4k-ajIEdym48zZ96s2nA" name="base_Class" ordered="false" lowerBound="1">
<eType xmi:type="ecore:EClass" href="http://www.eclipse.org/uml2/2.1.0/UML#//Class"/>
</eStructuralFeatures>
</eClassifiers>
</contents>
</eAnnotations>
<elementImport xmi:id="_ZtOxIKjHEdym48zZ96s2nA">
<importedElement xmi:type="uml:Class" href="pathmap://UML_METAMODELS/UML.metamodel.uml#Class"/>
</elementImport>
<packageImport xmi:id="_bkzWwKjHEdym48zZ96s2nA">
<importedPackage xmi:type="uml:Model" href="pathmap://UML_METAMODELS/UML.metamodel.uml#_0"/>
</packageImport>
<packagedElement xmi:type="uml:Stereotype" xmi:id="_e8aLwKjHEdym48zZ96s2nA" name="BeanClass">
<ownedAttribute xmi:id="_OAXE4KjIEdym48zZ96s2nA" name="base_Class">
<type xmi:type="uml:Class" href="pathmap://UML_METAMODELS/UML.metamodel.uml#Class"/>
</ownedAttribute>
<ownedAttribute xmi:id="_S_NkgKjIEdym48zZ96s2nA" name="base_Class" association="_S_MWYKjIEdym48zZ96s2nA">
<type xmi:type="uml:Class" href="pathmap://UML_METAMODELS/UML.metamodel.uml#Class"/>
</ownedAttribute>
</packagedElement>
<packagedElement xmi:type="uml:Extension" xmi:id="_S_MWYKjIEdym48zZ96s2nA" name="Class_BeanClass" memberEnd="_S_M9cKjIEdym48zZ96s2nA _S_NkgKjIEdym48zZ96s2nA">
<ownedEnd xmi:type="uml:ExtensionEnd" xmi:id="_S_M9cKjIEdym48zZ96s2nA" name="extension_BeanClass" type="_e8aLwKjHEdym48zZ96s2nA" aggregation="composite" association="_S_MWYKjIEdym48zZ96s2nA"/>
</packagedElement>
</uml:Profile>

View File

@ -0,0 +1,96 @@
package org.eclipse.uml2.diagram.clazz.providers;
import java.util.Arrays;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.EditPart;
import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor;
import org.eclipse.gmf.runtime.emf.ui.providers.marker.AbstractModelMarkerNavigationProvider;
import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditorPlugin;
import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditorUtil;
/**
* @generated
*/
public class UMLMarkerNavigationProvider extends
AbstractModelMarkerNavigationProvider {
/**
* @generated
*/
public static final String MARKER_TYPE = UMLDiagramEditorPlugin.ID
+ ".diagnostic"; //$NON-NLS-1$
/**
* @generated
*/
protected void doGotoMarker(IMarker marker) {
String elementId = marker
.getAttribute(
org.eclipse.gmf.runtime.common.core.resources.IMarker.ELEMENT_ID,
null);
if (elementId == null || !(getEditor() instanceof DiagramEditor)) {
return;
}
DiagramEditor editor = (DiagramEditor) getEditor();
Map editPartRegistry = editor.getDiagramGraphicalViewer()
.getEditPartRegistry();
EObject targetView = editor.getDiagram().eResource().getEObject(
elementId);
if (targetView == null) {
return;
}
EditPart targetEditPart = (EditPart) editPartRegistry.get(targetView);
if (targetEditPart != null) {
UMLDiagramEditorUtil.selectElementsInDiagram(editor, Arrays
.asList(new EditPart[] { targetEditPart }));
}
}
/**
* @generated
*/
public static void deleteMarkers(IResource resource) {
try {
resource.deleteMarkers(MARKER_TYPE, true, IResource.DEPTH_ZERO);
} catch (CoreException e) {
UMLDiagramEditorPlugin.getInstance().logError(
"Failed to delete validation markers", e); //$NON-NLS-1$
}
}
/**
* @generated
*/
public static IMarker addMarker(IFile file, String elementId,
String location, String message, int statusSeverity) {
IMarker marker = null;
try {
marker = file.createMarker(MARKER_TYPE);
marker.setAttribute(IMarker.MESSAGE, message);
marker.setAttribute(IMarker.LOCATION, location);
marker
.setAttribute(
org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID,
elementId);
int markerSeverity = IMarker.SEVERITY_INFO;
if (statusSeverity == IStatus.WARNING) {
markerSeverity = IMarker.SEVERITY_WARNING;
} else if (statusSeverity == IStatus.ERROR
|| statusSeverity == IStatus.CANCEL) {
markerSeverity = IMarker.SEVERITY_ERROR;
}
marker.setAttribute(IMarker.SEVERITY, markerSeverity);
} catch (CoreException e) {
UMLDiagramEditorPlugin.getInstance().logError(
"Failed to create validation marker", e); //$NON-NLS-1$
}
return marker;
}
}

View File

@ -0,0 +1,463 @@
package org.eclipse.uml2.diagram.clazz.providers;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.draw2d.FlowLayout;
import org.eclipse.draw2d.Label;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
import org.eclipse.gef.EditDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.editparts.AbstractConnectionEditPart;
import org.eclipse.gmf.runtime.common.core.service.AbstractProvider;
import org.eclipse.gmf.runtime.common.core.service.IOperation;
import org.eclipse.gmf.runtime.common.ui.resources.FileChangeManager;
import org.eclipse.gmf.runtime.common.ui.resources.IFileObserver;
import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil;
import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditDomain;
import org.eclipse.gmf.runtime.diagram.ui.services.decorator.AbstractDecorator;
import org.eclipse.gmf.runtime.diagram.ui.services.decorator.CreateDecoratorsOperation;
import org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecorator;
import org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorProvider;
import org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorTarget;
import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.gmf.runtime.notation.Edge;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.uml2.diagram.clazz.edit.parts.PackageEditPart;
import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditor;
import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditorPlugin;
import org.eclipse.uml2.diagram.clazz.part.UMLVisualIDRegistry;
/**
* @generated
*/
public class UMLValidationDecoratorProvider extends AbstractProvider implements
IDecoratorProvider {
public static Resource usedResource = null;
/**
* @generated
*/
private static final String KEY = "validationStatus"; //$NON-NLS-1$
/**
* @generated
*/
private static final String MARKER_TYPE = UMLDiagramEditorPlugin.ID
+ ".diagnostic"; //$NON-NLS-1$
/**
* @generated
*/
private static MarkerObserver fileObserver;
/**
* @generated
*/
private static Map/*<String, List<IDecorator>>*/allDecorators = new HashMap();
/**
* @generated
*/
public void createDecorators(IDecoratorTarget decoratorTarget) {
EditPart editPart = (EditPart) decoratorTarget
.getAdapter(EditPart.class);
if (editPart instanceof GraphicalEditPart
|| editPart instanceof AbstractConnectionEditPart) {
Object model = editPart.getModel();
if ((model instanceof View)) {
View view = (View) model;
if (!(view instanceof Edge) && !view.isSetElement()) {
return;
}
}
EditDomain ed = editPart.getViewer().getEditDomain();
if (!(ed instanceof DiagramEditDomain)) {
return;
}
if (((DiagramEditDomain) ed).getEditorPart() instanceof UMLDiagramEditor) {
decoratorTarget.installDecorator(KEY, new StatusDecorator(
decoratorTarget));
}
}
}
/**
* @generated
*/
public boolean provides(IOperation operation) {
if (!(operation instanceof CreateDecoratorsOperation)) {
return false;
}
IDecoratorTarget decoratorTarget = ((CreateDecoratorsOperation) operation)
.getDecoratorTarget();
View view = (View) decoratorTarget.getAdapter(View.class);
return view != null
&& PackageEditPart.MODEL_ID.equals(UMLVisualIDRegistry
.getModelID(view));
}
/**
* @generated
*/
public static void refreshDecorators(View view) {
refreshDecorators(ViewUtil.getIdStr(view), view.getDiagram());
}
/**
* @generated
*/
private static void refreshDecorators(String viewId, Diagram diagram) {
final List decorators = viewId != null ? (List) allDecorators
.get(viewId) : null;
if (decorators == null || decorators.isEmpty() || diagram == null) {
return;
}
final Diagram fdiagram = diagram;
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
public void run() {
try {
if (UMLValidationDecoratorProvider.usedResource == null)
UMLValidationDecoratorProvider.usedResource = fdiagram.eResource();
if (UMLValidationDecoratorProvider.usedResource == null)
return;
TransactionalEditingDomain domain =
TransactionalEditingDomain.Factory.INSTANCE.getEditingDomain(
UMLValidationDecoratorProvider.usedResource.getResourceSet());
domain.runExclusive(
new Runnable() {
public void run() {
for (Iterator it = decorators.iterator(); it
.hasNext();) {
IDecorator decorator = (IDecorator) it
.next();
decorator.refresh();
}
}
});
} catch (Exception e) {
UMLDiagramEditorPlugin.getInstance().logError(
"Decorator refresh failure", e); //$NON-NLS-1$
}
}
});
}
/**
* @generated
*/
public static class StatusDecorator extends AbstractDecorator {
/**
* @generated
*/
private String viewId;
/**
* @generated
*/
public StatusDecorator(IDecoratorTarget decoratorTarget) {
super(decoratorTarget);
try {
final View view = (View) getDecoratorTarget().getAdapter(
View.class);
TransactionUtil.getEditingDomain(view).runExclusive(
new Runnable() {
public void run() {
StatusDecorator.this.viewId = view != null ? ViewUtil
.getIdStr(view)
: null;
}
});
} catch (Exception e) {
UMLDiagramEditorPlugin.getInstance().logError(
"ViewID access failure", e); //$NON-NLS-1$
}
}
/**
* @generated
*/
public void refresh() {
removeDecoration();
View view = (View) getDecoratorTarget().getAdapter(View.class);
if (view == null || view.eResource() == null) {
return;
}
EditPart editPart = (EditPart) getDecoratorTarget().getAdapter(
EditPart.class);
if (editPart == null || editPart.getViewer() == null) {
return;
}
// query for all the validation markers of the current resource
String elementId = ViewUtil.getIdStr(view);
if (elementId == null) {
return;
}
int severity = IMarker.SEVERITY_INFO;
IMarker foundMarker = null;
IResource resource = WorkspaceSynchronizer
.getFile(view.eResource());
if (resource == null || !resource.exists()) {
return;
}
IMarker[] markers = null;
try {
markers = resource.findMarkers(MARKER_TYPE, true,
IResource.DEPTH_INFINITE);
} catch (CoreException e) {
UMLDiagramEditorPlugin.getInstance().logError(
"Validation markers refresh failure", e); //$NON-NLS-1$
}
if (markers == null || markers.length == 0) {
return;
}
Label toolTip = null;
for (int i = 0; i < markers.length; i++) {
IMarker marker = markers[i];
String attribute = marker
.getAttribute(
org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID,
""); //$NON-NLS-1$
if (attribute.equals(elementId)) {
int nextSeverity = marker.getAttribute(IMarker.SEVERITY,
IMarker.SEVERITY_INFO);
Image nextImage = getImage(nextSeverity);
if (foundMarker == null) {
foundMarker = marker;
toolTip = new Label(marker.getAttribute(
IMarker.MESSAGE, ""), //$NON-NLS-1$
nextImage);
} else {
if (toolTip.getChildren().isEmpty()) {
Label comositeLabel = new Label();
FlowLayout fl = new FlowLayout(false);
fl.setMinorSpacing(0);
comositeLabel.setLayoutManager(fl);
comositeLabel.add(toolTip);
toolTip = comositeLabel;
}
toolTip.add(new Label(marker.getAttribute(
IMarker.MESSAGE, ""), //$NON-NLS-1$
nextImage));
}
severity = (nextSeverity > severity) ? nextSeverity
: severity;
}
}
if (foundMarker == null) {
return;
}
// add decoration
if (editPart instanceof org.eclipse.gef.GraphicalEditPart) {
if (view instanceof Edge) {
setDecoration(getDecoratorTarget().addConnectionDecoration(
getImage(severity), 50, true));
} else {
int margin = -1;
if (editPart instanceof org.eclipse.gef.GraphicalEditPart) {
margin = MapModeUtil.getMapMode(
((org.eclipse.gef.GraphicalEditPart) editPart)
.getFigure()).DPtoLP(margin);
}
setDecoration(getDecoratorTarget()
.addShapeDecoration(getImage(severity),
IDecoratorTarget.Direction.NORTH_EAST,
margin, true));
}
getDecoration().setToolTip(toolTip);
}
}
/**
* @generated
*/
private Image getImage(int severity) {
String imageName = ISharedImages.IMG_OBJS_ERROR_TSK;
switch (severity) {
case IMarker.SEVERITY_ERROR:
imageName = ISharedImages.IMG_OBJS_ERROR_TSK;
break;
case IMarker.SEVERITY_WARNING:
imageName = ISharedImages.IMG_OBJS_WARN_TSK;
break;
default:
imageName = ISharedImages.IMG_OBJS_INFO_TSK;
}
return PlatformUI.getWorkbench().getSharedImages().getImage(
imageName);
}
/**
* @generated
*/
public void activate() {
if (viewId == null) {
return;
}
// add self to global decorators registry
List list = (List) allDecorators.get(viewId);
if (list == null) {
list = new ArrayList(2);
list.add(this);
allDecorators.put(viewId, list);
} else if (!list.contains(this)) {
list.add(this);
}
// start listening to changes in resources
View view = (View) getDecoratorTarget().getAdapter(View.class);
if (view == null) {
return;
}
Diagram diagramView = view.getDiagram();
if (diagramView == null) {
return;
}
if (fileObserver == null) {
FileChangeManager.getInstance().addFileObserver(
fileObserver = new MarkerObserver(diagramView));
}
}
/**
* @generated
*/
public void deactivate() {
if (viewId == null) {
return;
}
// remove self from global decorators registry
List list = (List) allDecorators.get(viewId);
if (list != null) {
list.remove(this);
if (list.isEmpty()) {
allDecorators.remove(viewId);
}
}
// stop listening to changes in resources if there are no more decorators
if (fileObserver != null && allDecorators.isEmpty()) {
FileChangeManager.getInstance()
.removeFileObserver(fileObserver);
fileObserver = null;
}
super.deactivate();
}
}
/**
* @generated
*/
static class MarkerObserver implements IFileObserver {
/**
* @generated
*/
private Diagram diagram;
/**
* @generated
*/
private MarkerObserver(Diagram diagram) {
this.diagram = diagram;
}
/**
* @generated
*/
public void handleFileRenamed(IFile oldFile, IFile file) {
}
/**
* @generated
*/
public void handleFileMoved(IFile oldFile, IFile file) {
}
/**
* @generated
*/
public void handleFileDeleted(IFile file) {
}
/**
* @generated
*/
public void handleFileChanged(IFile file) {
}
/**
* @generated
*/
public void handleMarkerAdded(IMarker marker) {
if (marker
.getAttribute(
org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID,
null) != null) {
handleMarkerChanged(marker);
}
}
/**
* @generated
*/
public void handleMarkerDeleted(IMarker marker, Map attributes) {
String viewId = (String) attributes
.get(org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID);
refreshDecorators(viewId, diagram);
}
/**
* @generated
*/
public void handleMarkerChanged(IMarker marker) {
if (!MARKER_TYPE.equals(getType(marker))) {
return;
}
String viewId = marker
.getAttribute(
org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID,
""); //$NON-NLS-1$
refreshDecorators(viewId, diagram);
}
/**
* @generated
*/
private String getType(IMarker marker) {
try {
return marker.getType();
} catch (CoreException e) {
UMLDiagramEditorPlugin.getInstance().logError(
"Validation marker refresh failure", e); //$NON-NLS-1$
return ""; //$NON-NLS-1$
}
}
}
}

View File

@ -0,0 +1,406 @@
package org.eclipse.uml2.diagram.clazz.providers;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.emf.validation.model.IClientSelector;
import org.eclipse.emf.validation.service.IBatchValidator;
import org.eclipse.emf.validation.service.ITraversalStrategy;
import org.eclipse.gmf.runtime.common.ui.services.action.contributionitem.AbstractContributionItemProvider;
import org.eclipse.gmf.runtime.common.ui.util.IWorkbenchPartDescriptor;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.jface.action.IAction;
import org.eclipse.uml2.diagram.clazz.edit.parts.PackageEditPart;
import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditorPlugin;
import org.eclipse.uml2.diagram.clazz.part.UMLVisualIDRegistry;
import org.eclipse.uml2.diagram.clazz.part.ValidateAction;
/**
* @generated
*/
public class UMLValidationProvider extends AbstractContributionItemProvider {
/**
* @generated
*/
private static boolean constraintsActive = false;
/**
* @generated
*/
public static boolean shouldConstraintsBePrivate() {
return false;
}
/**
* @generated
*/
protected IAction createAction(String actionId,
IWorkbenchPartDescriptor partDescriptor) {
if (ValidateAction.VALIDATE_ACTION_KEY.equals(actionId)) {
return new ValidateAction(partDescriptor);
}
return super.createAction(actionId, partDescriptor);
}
/**
* @generated
*/
public static void runWithConstraints(View view, Runnable op) {
final Runnable fop = op;
Runnable task = new Runnable() {
public void run() {
try {
constraintsActive = true;
fop.run();
} finally {
constraintsActive = false;
}
}
};
TransactionalEditingDomain txDomain = TransactionUtil
.getEditingDomain(view);
if (txDomain != null) {
try {
txDomain.runExclusive(task);
} catch (Exception e) {
UMLDiagramEditorPlugin.getInstance().logError(
"Validation action failed", e); //$NON-NLS-1$
}
} else {
task.run();
}
}
/**
* @generated
*/
static boolean isInDefaultEditorContext(Object object) {
if (shouldConstraintsBePrivate() && !constraintsActive) {
return false;
}
if (object instanceof View) {
return constraintsActive
&& PackageEditPart.MODEL_ID.equals(UMLVisualIDRegistry
.getModelID((View) object));
}
return true;
}
/**
* @generated
*/
static final Map semanticCtxIdMap = new HashMap();
/**
* @generated
*/
public static class DefaultCtx1 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static class DefaultCtx2 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static class DefaultCtx3 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static class DefaultCtx4 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static class DefaultCtx5 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static class DefaultCtx6 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static class DefaultCtx7 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static class DefaultCtx8 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static class DefaultCtx9 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static class DefaultCtx10 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static class DefaultCtx11 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static class DefaultCtx12 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static class DefaultCtx13 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static class DefaultCtx14 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static ITraversalStrategy getNotationTraversalStrategy(
IBatchValidator validator) {
return new CtxSwitchStrategy(validator);
}
/**
* @generated
*/
private static class CtxSwitchStrategy implements ITraversalStrategy {
/**
* @generated
*/
private ITraversalStrategy defaultStrategy;
/**
* @generated
*/
private String currentSemanticCtxId;
/**
* @generated
*/
private boolean ctxChanged = true;
/**
* @generated
*/
private EObject currentTarget;
/**
* @generated
*/
private EObject preFetchedNextTarget;
/**
* @generated
*/
CtxSwitchStrategy(IBatchValidator validator) {
this.defaultStrategy = validator.getDefaultTraversalStrategy();
}
/**
* @generated
*/
public void elementValidated(EObject element, IStatus status) {
defaultStrategy.elementValidated(element, status);
}
/**
* @generated
*/
public boolean hasNext() {
return defaultStrategy.hasNext();
}
/**
* @generated
*/
public boolean isClientContextChanged() {
if (preFetchedNextTarget == null) {
preFetchedNextTarget = next();
prepareNextClientContext(preFetchedNextTarget);
}
return ctxChanged;
}
/**
* @generated
*/
public EObject next() {
EObject nextTarget = preFetchedNextTarget;
if (nextTarget == null) {
nextTarget = defaultStrategy.next();
}
this.preFetchedNextTarget = null;
return this.currentTarget = nextTarget;
}
/**
* @generated
*/
public void startTraversal(Collection traversalRoots,
IProgressMonitor monitor) {
defaultStrategy.startTraversal(traversalRoots, monitor);
}
/**
* @generated
*/
private void prepareNextClientContext(EObject nextTarget) {
if (nextTarget != null && currentTarget != null) {
if (nextTarget instanceof View) {
String id = ((View) nextTarget).getType();
String nextSemanticId = id != null
&& semanticCtxIdMap.containsKey(id) ? id : null;
if ((currentSemanticCtxId != null && !currentSemanticCtxId
.equals(nextSemanticId))
|| (nextSemanticId != null && !nextSemanticId
.equals(currentSemanticCtxId))) {
this.ctxChanged = true;
}
currentSemanticCtxId = nextSemanticId;
} else {
// context of domain model
this.ctxChanged = currentSemanticCtxId != null;
currentSemanticCtxId = null;
}
} else {
this.ctxChanged = false;
}
}
}
/**
* @generated
*/
static class JavaAudits {
}
}

View File

@ -0,0 +1,297 @@
package org.eclipse.uml2.diagram.clazz.part;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.emf.validation.model.EvaluationMode;
import org.eclipse.emf.validation.model.IConstraintStatus;
import org.eclipse.emf.validation.service.IBatchValidator;
import org.eclipse.emf.validation.service.ModelValidationService;
import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gmf.runtime.common.ui.util.IWorkbenchPartDescriptor;
import org.eclipse.gmf.runtime.diagram.ui.OffscreenEditPartFactory;
import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart;
import org.eclipse.gmf.runtime.emf.core.util.EMFCoreUtil;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.WorkspaceModifyDelegatingOperation;
import org.eclipse.uml2.diagram.clazz.providers.UMLMarkerNavigationProvider;
import org.eclipse.uml2.diagram.clazz.providers.UMLValidationProvider;
/**
* @generated
*/
public class ValidateAction extends Action {
/**
* @generated
*/
public static final String VALIDATE_ACTION_KEY = "validateAction"; //$NON-NLS-1$
/**
* @generated
*/
private IWorkbenchPartDescriptor workbenchPartDescriptor;
/**
* @generated
*/
public ValidateAction(IWorkbenchPartDescriptor workbenchPartDescriptor) {
setId(VALIDATE_ACTION_KEY);
setText(Messages.ValidateActionMessage);
this.workbenchPartDescriptor = workbenchPartDescriptor;
}
/**
* @generated
*/
public void run() {
IWorkbenchPart workbenchPart = workbenchPartDescriptor.getPartPage()
.getActivePart();
if (workbenchPart instanceof IDiagramWorkbenchPart) {
final IDiagramWorkbenchPart part = (IDiagramWorkbenchPart) workbenchPart;
try {
new WorkspaceModifyDelegatingOperation(
new IRunnableWithProgress() {
public void run(IProgressMonitor monitor)
throws InterruptedException,
InvocationTargetException {
runValidation(part.getDiagramEditPart(), part
.getDiagram());
}
}).run(new NullProgressMonitor());
} catch (Exception e) {
UMLDiagramEditorPlugin.getInstance().logError(
"Validation action failed", e); //$NON-NLS-1$
}
}
}
/**
* @generated
*/
public static void runValidation(View view) {
try {
if (UMLDiagramEditorUtil.openDiagram(view.eResource())) {
IEditorPart editorPart = PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getActivePage()
.getActiveEditor();
if (editorPart instanceof IDiagramWorkbenchPart) {
runValidation(((IDiagramWorkbenchPart) editorPart)
.getDiagramEditPart(), view);
} else {
runNonUIValidation(view);
}
}
} catch (Exception e) {
UMLDiagramEditorPlugin.getInstance().logError(
"Validation action failed", e); //$NON-NLS-1$
}
}
/**
* @generated
*/
public static void runNonUIValidation(View view) {
DiagramEditPart diagramEditPart = OffscreenEditPartFactory
.getInstance().createDiagramEditPart(view.getDiagram());
runValidation(diagramEditPart, view);
}
/**
* @generated
*/
public static void runValidation(DiagramEditPart diagramEditPart, View view) {
final DiagramEditPart fpart = diagramEditPart;
final View fview = view;
UMLValidationProvider.runWithConstraints(view, new Runnable() {
public void run() {
validate(fpart, fview);
}
});
}
/**
* @generated
*/
private static Diagnostic runEMFValidator(View target) {
if (target.isSetElement() && target.getElement() != null) {
return new Diagnostician() {
public String getObjectLabel(EObject eObject) {
return EMFCoreUtil.getQualifiedName(eObject, true);
}
}.validate(target.getElement());
}
return Diagnostic.OK_INSTANCE;
}
/**
* @generated
*/
private static void validate(DiagramEditPart diagramEditPart, View view) {
IFile target = view.eResource() != null ? WorkspaceSynchronizer
.getFile(view.eResource()) : null;
if (target != null) {
UMLMarkerNavigationProvider.deleteMarkers(target);
}
Diagnostic diagnostic = runEMFValidator(view);
createMarkers(target, diagnostic, diagramEditPart);
IBatchValidator validator = (IBatchValidator) ModelValidationService
.getInstance().newValidator(EvaluationMode.BATCH);
validator.setIncludeLiveConstraints(true);
if (view.isSetElement() && view.getElement() != null) {
IStatus status = validator.validate(view.getElement());
createMarkers(target, status, diagramEditPart);
}
}
/**
* @generated
*/
private static void createMarkers(IFile target, IStatus validationStatus,
DiagramEditPart diagramEditPart) {
if (validationStatus.isOK()) {
return;
}
final IStatus rootStatus = validationStatus;
List allStatuses = new ArrayList();
UMLDiagramEditorUtil.LazyElement2ViewMap element2ViewMap = new UMLDiagramEditorUtil.LazyElement2ViewMap(
diagramEditPart.getDiagramView(), collectTargetElements(
rootStatus, new HashSet(), allStatuses));
for (Iterator it = allStatuses.iterator(); it.hasNext();) {
IConstraintStatus nextStatus = (IConstraintStatus) it.next();
View view = UMLDiagramEditorUtil.findView(diagramEditPart,
nextStatus.getTarget(), element2ViewMap);
addMarker(diagramEditPart.getViewer(), target, view.eResource()
.getURIFragment(view), EMFCoreUtil.getQualifiedName(
nextStatus.getTarget(), true), nextStatus.getMessage(),
nextStatus.getSeverity());
}
}
/**
* @generated
*/
private static void createMarkers(IFile target,
Diagnostic emfValidationStatus, DiagramEditPart diagramEditPart) {
if (emfValidationStatus.getSeverity() == Diagnostic.OK) {
return;
}
final Diagnostic rootStatus = emfValidationStatus;
List allDiagnostics = new ArrayList();
UMLDiagramEditorUtil.LazyElement2ViewMap element2ViewMap = new UMLDiagramEditorUtil.LazyElement2ViewMap(
diagramEditPart.getDiagramView(), collectTargetElements(
rootStatus, new HashSet(), allDiagnostics));
for (Iterator it = emfValidationStatus.getChildren().iterator(); it
.hasNext();) {
Diagnostic nextDiagnostic = (Diagnostic) it.next();
List data = nextDiagnostic.getData();
if (data != null && !data.isEmpty()
&& data.get(0) instanceof EObject) {
EObject element = (EObject) data.get(0);
View view = UMLDiagramEditorUtil.findView(diagramEditPart,
element, element2ViewMap);
addMarker(
diagramEditPart.getViewer(),
target,
view.eResource().getURIFragment(view),
EMFCoreUtil.getQualifiedName(element, true),
nextDiagnostic.getMessage(),
diagnosticToStatusSeverity(nextDiagnostic.getSeverity()));
}
}
}
/**
* @generated
*/
private static void addMarker(EditPartViewer viewer, IFile target,
String elementId, String location, String message,
int statusSeverity) {
if (target == null) {
return;
}
UMLMarkerNavigationProvider.addMarker(target, elementId, location,
message, statusSeverity);
}
/**
* @generated
*/
private static int diagnosticToStatusSeverity(int diagnosticSeverity) {
if (diagnosticSeverity == Diagnostic.OK) {
return IStatus.OK;
} else if (diagnosticSeverity == Diagnostic.INFO) {
return IStatus.INFO;
} else if (diagnosticSeverity == Diagnostic.WARNING) {
return IStatus.WARNING;
} else if (diagnosticSeverity == Diagnostic.ERROR
|| diagnosticSeverity == Diagnostic.CANCEL) {
return IStatus.ERROR;
}
return IStatus.INFO;
}
/**
* @generated
*/
private static Set collectTargetElements(IStatus status,
Set targetElementCollector, List allConstraintStatuses) {
if (status instanceof IConstraintStatus) {
targetElementCollector
.add(((IConstraintStatus) status).getTarget());
allConstraintStatuses.add(status);
}
if (status.isMultiStatus()) {
IStatus[] children = status.getChildren();
for (int i = 0; i < children.length; i++) {
collectTargetElements(children[i], targetElementCollector,
allConstraintStatuses);
}
}
return targetElementCollector;
}
/**
* @generated
*/
private static Set collectTargetElements(Diagnostic diagnostic,
Set targetElementCollector, List allDiagnostics) {
List data = diagnostic.getData();
EObject target = null;
if (data != null && !data.isEmpty() && data.get(0) instanceof EObject) {
target = (EObject) data.get(0);
targetElementCollector.add(target);
allDiagnostics.add(diagnostic);
}
if (diagnostic.getChildren() != null
&& !diagnostic.getChildren().isEmpty()) {
for (Iterator it = diagnostic.getChildren().iterator(); it
.hasNext();) {
collectTargetElements((Diagnostic) it.next(),
targetElementCollector, allDiagnostics);
}
}
return targetElementCollector;
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<notation:Diagram xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:notation="http://www.eclipse.org/gmf/runtime/1.0.1/notation" xmlns:uml="http://www.eclipse.org/uml2/2.1.0/UML" xmi:id="_dobnwK1vEdyCurEqUBGZMw" type="UMLProfile" name="pyUMLProfile.umlprofile_diagram" measurementUnit="Pixel">
<children xmi:type="notation:Node" xmi:id="_rcHaEK1vEdyCurEqUBGZMw" type="2007">
<children xmi:type="notation:Node" xmi:id="_rcHaE61vEdyCurEqUBGZMw" type="5009"/>
<children xmi:type="notation:Node" xmi:id="_rcHaFK1vEdyCurEqUBGZMw" type="7005">
<styles xmi:type="notation:DrawerStyle" xmi:id="_rcHaFa1vEdyCurEqUBGZMw"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_rcHaFq1vEdyCurEqUBGZMw"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_rcHaF61vEdyCurEqUBGZMw"/>
</children>
<styles xmi:type="notation:ShapeStyle" xmi:id="_rcHaEa1vEdyCurEqUBGZMw" fontName="Sans Serif"/>
<element xmi:type="uml:Profile" href="PyUMLProfile.uml#_7Y-UAKi8Edyr_pXRyLU3wA"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_rcHaEq1vEdyCurEqUBGZMw"/>
</children>
<children xmi:type="notation:Node" xmi:id="_rcIoMK1vEdyCurEqUBGZMw" type="2001">
<children xmi:type="notation:Node" xmi:id="_rcJPQK1vEdyCurEqUBGZMw" type="5001"/>
<children xmi:type="notation:Node" xmi:id="_rcJ2UK1vEdyCurEqUBGZMw" type="7001">
<styles xmi:type="notation:DrawerStyle" xmi:id="_rcJ2Ua1vEdyCurEqUBGZMw"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_rcJ2Uq1vEdyCurEqUBGZMw"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_rcJ2U61vEdyCurEqUBGZMw"/>
</children>
<children xmi:type="notation:Node" xmi:id="_rcKdYK1vEdyCurEqUBGZMw" type="7002">
<styles xmi:type="notation:DrawerStyle" xmi:id="_rcKdYa1vEdyCurEqUBGZMw"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_rcKdYq1vEdyCurEqUBGZMw"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_rcKdY61vEdyCurEqUBGZMw"/>
</children>
<styles xmi:type="notation:ShapeStyle" xmi:id="_rcIoMa1vEdyCurEqUBGZMw" fontName="Sans Serif"/>
<element xmi:type="uml:Stereotype" href="PyUMLProfile.uml#_e8aLwKjHEdym48zZ96s2nA"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_rcIoMq1vEdyCurEqUBGZMw" x="167"/>
</children>
<children xmi:type="notation:Node" xmi:id="_rcM5oK1vEdyCurEqUBGZMw" type="2006">
<children xmi:type="notation:Node" xmi:id="_rcNgsK1vEdyCurEqUBGZMw" type="5008"/>
<styles xmi:type="notation:ShapeStyle" xmi:id="_rcM5oa1vEdyCurEqUBGZMw" fontName="Sans Serif"/>
<element xmi:type="uml:ElementImport" href="PyUMLProfile.uml#_ZtOxIKjHEdym48zZ96s2nA"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_rcM5oq1vEdyCurEqUBGZMw" x="189" y="117" width="78"/>
</children>
<styles xmi:type="notation:DiagramStyle" xmi:id="_dobnwa1vEdyCurEqUBGZMw"/>
<element xmi:type="uml:Profile" href="PyUMLProfile.uml#_7Y-UAKi8Edyr_pXRyLU3wA"/>
</notation:Diagram>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,49 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.uml2.diagram.clazz; singleton:=true
Bundle-Version: 0.7.1.qualifier
Bundle-ClassPath: .
Bundle-Activator: org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditorPlugin
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Export-Package: org.eclipse.uml2.diagram.clazz.edit.parts,
org.eclipse.uml2.diagram.clazz.part,
org.eclipse.uml2.diagram.clazz.providers,
org.eclipse.uml2.diagram.clazz.navigator
Require-Bundle: org.eclipse.core.runtime,
org.eclipse.core.resources,
org.eclipse.core.expressions,
org.eclipse.jface,
org.eclipse.ui.ide,
org.eclipse.ui.views,
org.eclipse.ui.navigator,
org.eclipse.emf.ecore,
org.eclipse.emf.ecore.xmi,
org.eclipse.emf.edit.ui,
org.eclipse.gef;visibility:=reexport,
org.eclipse.gmf.runtime.emf.core,
org.eclipse.gmf.runtime.emf.commands.core,
org.eclipse.gmf.runtime.emf.ui.properties,
org.eclipse.gmf.runtime.diagram.ui,
org.eclipse.gmf.runtime.diagram.ui.properties,
org.eclipse.gmf.runtime.diagram.ui.providers,
org.eclipse.gmf.runtime.diagram.ui.providers.ide,
org.eclipse.gmf.runtime.diagram.ui.resources.editor,
org.eclipse.gmf.runtime.diagram.ui.resources.editor.ide,
org.eclipse.gmf.runtime.notation.providers,
org.eclipse.uml2.uml;visibility:=reexport,
org.eclipse.uml2.uml.edit;visibility:=reexport,
org.eclipse.emf.ecore;visibility:=reexport,
org.eclipse.emf.ecore.edit;visibility:=reexport,
org.eclipse.emf.ocl;visibility:=reexport,
org.eclipse.emf.query.ocl;visibility:=reexport,
org.eclipse.gmf.runtime.draw2d.ui;visibility:=reexport,
org.eclipse.uml2.diagram.common;visibility:=reexport,
org.eclipse.draw2d;visibility:=reexport,
org.eclipse.ocl.ecore;visibility:=reexport,
org.eclipse.gmf.runtime.diagram.ui.render,
org.eclipse.ui.navigator.resources,
org.eclipse.emf.validation;visibility:=reexport
Eclipse-LazyStart: true
Bundle-RequiredExecutionEnvironment: J2SE-1.5

107
pyUml/documents/pythonTree.uml Executable file
View File

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?>
<uml:Package xmi:version="2.1" xmlns:xmi="http://schema.omg.org/spec/XMI/2.1" xmlns:uml="http://www.eclipse.org/uml2/2.1.0/UML" xmi:id="_Mve2kaGbEdy6I6R2I8Pp5Q" name="PythonTree">
<packagedElement xmi:type="uml:Class" xmi:id="_RzMBAKGbEdy6I6R2I8Pp5Q" name="PythonTreePackage">
<generalization xmi:id="_YFqPMKGcEdyiqaZxdx2orw" general="_V11hoKGcEdyiqaZxdx2orw"/>
<ownedAttribute xmi:id="_oCNygKGcEdyiqaZxdx2orw" name="packagedFile" type="_Zg8hcKGcEdyiqaZxdx2orw" association="_oCL9UKGcEdyiqaZxdx2orw">
<upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_pjpTkKGdEdyiqaZxdx2orw" value="*"/>
<lowerValue xmi:type="uml:LiteralInteger" xmi:id="_pjp6oKGdEdyiqaZxdx2orw" value="1"/>
</ownedAttribute>
<ownedAttribute xmi:id="_qqgDYqGcEdyiqaZxdx2orw" name="childClass" type="_ar4qkKGcEdyiqaZxdx2orw" association="_qqfcUKGcEdyiqaZxdx2orw">
<upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_v6Qs0KGcEdyiqaZxdx2orw" value="*"/>
<lowerValue xmi:type="uml:LiteralInteger" xmi:id="_v6RT4KGcEdyiqaZxdx2orw" value="1"/>
</ownedAttribute>
<ownedAttribute xmi:id="_7HezMKGcEdyiqaZxdx2orw" name="childPackage" type="_RzMBAKGbEdy6I6R2I8Pp5Q" association="_7Hc-AKGcEdyiqaZxdx2orw">
<upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_TcvG0KGdEdyiqaZxdx2orw" value="*"/>
<lowerValue xmi:type="uml:LiteralInteger" xmi:id="_Tcvt4KGdEdyiqaZxdx2orw" value="1"/>
</ownedAttribute>
</packagedElement>
<packagedElement xmi:type="uml:Class" xmi:id="_ST-Z4KGbEdy6I6R2I8Pp5Q" name="PythonTreeRoot">
<generalization xmi:id="_VD-m4KGcEdyiqaZxdx2orw" general="_RzMBAKGbEdy6I6R2I8Pp5Q"/>
<ownedAttribute xmi:id="_7xOJMKGbEdyiqaZxdx2orw" name="childPackage" type="_RzMBAKGbEdy6I6R2I8Pp5Q" association="_7w9DcKGbEdyiqaZxdx2orw">
<upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_Nq5ggKGcEdyiqaZxdx2orw" value="*"/>
<lowerValue xmi:type="uml:LiteralInteger" xmi:id="_Nq6HkKGcEdyiqaZxdx2orw" value="1"/>
</ownedAttribute>
</packagedElement>
<packagedElement xmi:type="uml:Association" xmi:id="_7w9DcKGbEdyiqaZxdx2orw" name="contains ->" memberEnd="_7xE_QKGbEdyiqaZxdx2orw _7xOJMKGbEdyiqaZxdx2orw">
<ownedEnd xmi:id="_7xE_QKGbEdyiqaZxdx2orw" name="src" type="_ST-Z4KGbEdy6I6R2I8Pp5Q" association="_7w9DcKGbEdyiqaZxdx2orw">
<upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_7xNiIKGbEdyiqaZxdx2orw" value="1"/>
<lowerValue xmi:type="uml:LiteralInteger" xmi:id="_7xLs8KGbEdyiqaZxdx2orw" value="1"/>
</ownedEnd>
</packagedElement>
<packagedElement xmi:type="uml:Class" xmi:id="_V11hoKGcEdyiqaZxdx2orw" name="PythonTreeNode">
<ownedAttribute xmi:id="_1h4nMKGdEdyiqaZxdx2orw" name="parent" type="_V11hoKGcEdyiqaZxdx2orw" aggregation="composite"/>
<ownedAttribute xmi:id="_85RrgKGdEdyiqaZxdx2orw" name="associatedModelElement" aggregation="composite"/>
<ownedAttribute xmi:id="_sINsoKGeEdyiqaZxdx2orw" name="xmiID" aggregation="composite"/>
<ownedAttribute xmi:id="_zgt5UKGgEdyiqaZxdx2orw" name="name" aggregation="composite"/>
<ownedOperation xmi:id="_5aDyoKGdEdyiqaZxdx2orw" name="synchonizeCode">
<ownedParameter xmi:id="_6QYWoKGdEdyiqaZxdx2orw" direction="return"/>
</ownedOperation>
<ownedOperation xmi:id="_6rj2wKGdEdyiqaZxdx2orw" name="synchronizeModel">
<ownedParameter xmi:id="_7OuOMKGdEdyiqaZxdx2orw" direction="return"/>
</ownedOperation>
</packagedElement>
<packagedElement xmi:type="uml:Class" xmi:id="_Zg8hcKGcEdyiqaZxdx2orw" name="PythonTreeFile">
<generalization xmi:id="_gz_RQKGcEdyiqaZxdx2orw" general="_V11hoKGcEdyiqaZxdx2orw"/>
<ownedAttribute xmi:id="_tGRFwqGdEdyiqaZxdx2orw" name="containedClass" type="_ar4qkKGcEdyiqaZxdx2orw" association="_tGP3oKGdEdyiqaZxdx2orw">
<upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_v1pdIKGdEdyiqaZxdx2orw" value="*"/>
<lowerValue xmi:type="uml:LiteralInteger" xmi:id="_v1pdIaGdEdyiqaZxdx2orw" value="1"/>
</ownedAttribute>
<ownedAttribute xmi:id="_cG6zQKGeEdyiqaZxdx2orw" name="fileAST" aggregation="composite"/>
</packagedElement>
<packagedElement xmi:type="uml:Class" xmi:id="_ar4qkKGcEdyiqaZxdx2orw" name="PythonTreeClass">
<generalization xmi:id="_hmyAIKGcEdyiqaZxdx2orw" general="_V11hoKGcEdyiqaZxdx2orw"/>
<ownedAttribute xmi:id="_tazn0KGcEdyiqaZxdx2orw" name="childMethod" type="_bvh44KGcEdyiqaZxdx2orw" association="_taxyoKGcEdyiqaZxdx2orw">
<upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_u2imAKGcEdyiqaZxdx2orw" value="*"/>
<lowerValue xmi:type="uml:LiteralInteger" xmi:id="_u2jNEKGcEdyiqaZxdx2orw" value="1"/>
</ownedAttribute>
<ownedOperation xmi:id="_Iva9oKGfEdyiqaZxdx2orw" name="createNewClass">
<ownedParameter xmi:id="_JWMCsKGfEdyiqaZxdx2orw" direction="return"/>
</ownedOperation>
</packagedElement>
<packagedElement xmi:type="uml:Class" xmi:id="_bvh44KGcEdyiqaZxdx2orw" name="PythonTreeMethod">
<generalization xmi:id="_iB514KGcEdyiqaZxdx2orw" general="_V11hoKGcEdyiqaZxdx2orw"/>
<ownedAttribute xmi:id="_wxIqcaGcEdyiqaZxdx2orw" name="childAttribute" type="_dULigKGcEdyiqaZxdx2orw" association="_wxHcUKGcEdyiqaZxdx2orw">
<upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_yniycKGcEdyiqaZxdx2orw" value="*"/>
<lowerValue xmi:type="uml:LiteralInteger" xmi:id="_ynjZgKGcEdyiqaZxdx2orw" value="1"/>
</ownedAttribute>
</packagedElement>
<packagedElement xmi:type="uml:Class" xmi:id="_dULigKGcEdyiqaZxdx2orw" name="PythonTreeAttribute">
<generalization xmi:id="_iXnnMKGcEdyiqaZxdx2orw" general="_V11hoKGcEdyiqaZxdx2orw"/>
</packagedElement>
<packagedElement xmi:type="uml:Association" xmi:id="_oCL9UKGcEdyiqaZxdx2orw" name="contains ->" memberEnd="_oCMkYKGcEdyiqaZxdx2orw _oCNygKGcEdyiqaZxdx2orw">
<ownedEnd xmi:id="_oCMkYKGcEdyiqaZxdx2orw" name="src" type="_RzMBAKGbEdy6I6R2I8Pp5Q" association="_oCL9UKGcEdyiqaZxdx2orw">
<upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_oCNLcaGcEdyiqaZxdx2orw" value="1"/>
<lowerValue xmi:type="uml:LiteralInteger" xmi:id="_oCNLcKGcEdyiqaZxdx2orw" value="1"/>
</ownedEnd>
</packagedElement>
<packagedElement xmi:type="uml:Association" xmi:id="_qqfcUKGcEdyiqaZxdx2orw" name="contains ->" memberEnd="_qqfcUaGcEdyiqaZxdx2orw _qqgDYqGcEdyiqaZxdx2orw">
<ownedEnd xmi:id="_qqfcUaGcEdyiqaZxdx2orw" name="src" type="_RzMBAKGbEdy6I6R2I8Pp5Q" association="_qqfcUKGcEdyiqaZxdx2orw">
<upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_qqgDYaGcEdyiqaZxdx2orw" value="1"/>
<lowerValue xmi:type="uml:LiteralInteger" xmi:id="_qqgDYKGcEdyiqaZxdx2orw" value="1"/>
</ownedEnd>
</packagedElement>
<packagedElement xmi:type="uml:Association" xmi:id="_taxyoKGcEdyiqaZxdx2orw" name="contains ->" memberEnd="_tayZsKGcEdyiqaZxdx2orw _tazn0KGcEdyiqaZxdx2orw">
<ownedEnd xmi:id="_tayZsKGcEdyiqaZxdx2orw" name="src" type="_ar4qkKGcEdyiqaZxdx2orw" association="_taxyoKGcEdyiqaZxdx2orw">
<upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_tazAwaGcEdyiqaZxdx2orw" value="1"/>
<lowerValue xmi:type="uml:LiteralInteger" xmi:id="_tazAwKGcEdyiqaZxdx2orw" value="1"/>
</ownedEnd>
</packagedElement>
<packagedElement xmi:type="uml:Association" xmi:id="_wxHcUKGcEdyiqaZxdx2orw" name=" contains ^" memberEnd="_wxIDYKGcEdyiqaZxdx2orw _wxIqcaGcEdyiqaZxdx2orw">
<ownedEnd xmi:id="_wxIDYKGcEdyiqaZxdx2orw" name="src" type="_bvh44KGcEdyiqaZxdx2orw" association="_wxHcUKGcEdyiqaZxdx2orw">
<upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_wxIqcKGcEdyiqaZxdx2orw" value="1"/>
<lowerValue xmi:type="uml:LiteralInteger" xmi:id="_wxIDYaGcEdyiqaZxdx2orw" value="1"/>
</ownedEnd>
</packagedElement>
<packagedElement xmi:type="uml:Association" xmi:id="_7Hc-AKGcEdyiqaZxdx2orw" name="contains ->" memberEnd="_7HdlEKGcEdyiqaZxdx2orw _7HezMKGcEdyiqaZxdx2orw">
<ownedEnd xmi:id="_7HdlEKGcEdyiqaZxdx2orw" name="src" type="_RzMBAKGbEdy6I6R2I8Pp5Q" association="_7Hc-AKGcEdyiqaZxdx2orw">
<upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_7HeMIaGcEdyiqaZxdx2orw" value="1"/>
<lowerValue xmi:type="uml:LiteralInteger" xmi:id="_7HeMIKGcEdyiqaZxdx2orw" value="1"/>
</ownedEnd>
</packagedElement>
<packagedElement xmi:type="uml:Association" xmi:id="_tGP3oKGdEdyiqaZxdx2orw" name="conatins ->" memberEnd="_tGQesKGdEdyiqaZxdx2orw _tGRFwqGdEdyiqaZxdx2orw">
<ownedEnd xmi:id="_tGQesKGdEdyiqaZxdx2orw" name="src" type="_Zg8hcKGcEdyiqaZxdx2orw" association="_tGP3oKGdEdyiqaZxdx2orw">
<upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_tGRFwaGdEdyiqaZxdx2orw" value="1"/>
<lowerValue xmi:type="uml:LiteralInteger" xmi:id="_tGRFwKGdEdyiqaZxdx2orw" value="1"/>
</ownedEnd>
</packagedElement>
</uml:Package>

View File

@ -0,0 +1,492 @@
<?xml version="1.0" encoding="UTF-8"?>
<notation:Diagram xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:notation="http://www.eclipse.org/gmf/runtime/1.0.1/notation" xmlns:uml="http://www.eclipse.org/uml2/2.1.0/UML" xmi:id="_M8LOwKGbEdy6I6R2I8Pp5Q" type="UMLClass" name="pythonTree.umlclass_diagram" measurementUnit="Pixel">
<children xmi:type="notation:Node" xmi:id="_N0TJkKGbEdy6I6R2I8Pp5Q" type="2014">
<children xmi:type="notation:Node" xmi:id="_N0UXsKGbEdy6I6R2I8Pp5Q" type="5020"/>
<children xmi:type="notation:Node" xmi:id="_N0bFYKGbEdy6I6R2I8Pp5Q" type="7032">
<styles xmi:type="notation:DrawerStyle" xmi:id="_N0bFYaGbEdy6I6R2I8Pp5Q"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_N0bFYqGbEdy6I6R2I8Pp5Q"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_N0bFY6GbEdy6I6R2I8Pp5Q"/>
</children>
<styles xmi:type="notation:ShapeStyle" xmi:id="_N0TJkaGbEdy6I6R2I8Pp5Q" fontName="Sans Serif"/>
<element xmi:type="uml:Package" href="pythonTree.uml#_Mve2kaGbEdy6I6R2I8Pp5Q"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_N0TJkqGbEdy6I6R2I8Pp5Q"/>
</children>
<children xmi:type="notation:Node" xmi:id="_SBmQcKGbEdy6I6R2I8Pp5Q" type="2001">
<children xmi:type="notation:Node" xmi:id="_SBoFoKGbEdy6I6R2I8Pp5Q" type="5003">
<styles xmi:type="notation:FontStyle" xmi:id="_SDBz0KGbEdy6I6R2I8Pp5Q"/>
</children>
<children xmi:type="notation:Node" xmi:id="_SBossKGbEdy6I6R2I8Pp5Q" type="5019"/>
<children xmi:type="notation:Node" xmi:id="_SBzEwKGbEdy6I6R2I8Pp5Q" type="7001">
<styles xmi:type="notation:DrawerStyle" xmi:id="_SBzEwaGbEdy6I6R2I8Pp5Q"/>
<styles xmi:type="notation:TitleStyle" xmi:id="_SBzEwqGbEdy6I6R2I8Pp5Q" showTitle="true"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_SBzEw6GbEdy6I6R2I8Pp5Q"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_SBzExKGbEdy6I6R2I8Pp5Q"/>
</children>
<children xmi:type="notation:Node" xmi:id="_SB39QKGbEdy6I6R2I8Pp5Q" type="7002">
<styles xmi:type="notation:DrawerStyle" xmi:id="_SB39QaGbEdy6I6R2I8Pp5Q"/>
<styles xmi:type="notation:TitleStyle" xmi:id="_SB39QqGbEdy6I6R2I8Pp5Q" showTitle="true"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_SB39Q6GbEdy6I6R2I8Pp5Q"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_SB39RKGbEdy6I6R2I8Pp5Q"/>
</children>
<children xmi:type="notation:Node" xmi:id="_SB5ycKGbEdy6I6R2I8Pp5Q" type="7003">
<styles xmi:type="notation:DrawerStyle" xmi:id="_SB5ycaGbEdy6I6R2I8Pp5Q"/>
<styles xmi:type="notation:TitleStyle" xmi:id="_SB5ycqGbEdy6I6R2I8Pp5Q" showTitle="true"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_SB5yc6GbEdy6I6R2I8Pp5Q"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_SB5ydKGbEdy6I6R2I8Pp5Q"/>
</children>
<styles xmi:type="notation:ShapeStyle" xmi:id="_SBmQcaGbEdy6I6R2I8Pp5Q" fontName="Sans Serif"/>
<element xmi:type="uml:Class" href="pythonTree.uml#_RzMBAKGbEdy6I6R2I8Pp5Q"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_SBmQcqGbEdy6I6R2I8Pp5Q" x="104" y="195"/>
</children>
<children xmi:type="notation:Node" xmi:id="_SUL1QKGbEdy6I6R2I8Pp5Q" type="2001">
<children xmi:type="notation:Node" xmi:id="_SUL1Q6GbEdy6I6R2I8Pp5Q" type="5003">
<styles xmi:type="notation:FontStyle" xmi:id="_SUPfoKGbEdy6I6R2I8Pp5Q"/>
</children>
<children xmi:type="notation:Node" xmi:id="_SUMcUKGbEdy6I6R2I8Pp5Q" type="5019"/>
<children xmi:type="notation:Node" xmi:id="_SUNDYKGbEdy6I6R2I8Pp5Q" type="7001">
<styles xmi:type="notation:DrawerStyle" xmi:id="_SUNDYaGbEdy6I6R2I8Pp5Q"/>
<styles xmi:type="notation:TitleStyle" xmi:id="_SUNDYqGbEdy6I6R2I8Pp5Q" showTitle="true"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_SUNDY6GbEdy6I6R2I8Pp5Q"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_SUNDZKGbEdy6I6R2I8Pp5Q"/>
</children>
<children xmi:type="notation:Node" xmi:id="_SUNDZaGbEdy6I6R2I8Pp5Q" type="7002">
<styles xmi:type="notation:DrawerStyle" xmi:id="_SUNDZqGbEdy6I6R2I8Pp5Q"/>
<styles xmi:type="notation:TitleStyle" xmi:id="_SUNDZ6GbEdy6I6R2I8Pp5Q" showTitle="true"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_SUNDaKGbEdy6I6R2I8Pp5Q"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_SUNDaaGbEdy6I6R2I8Pp5Q"/>
</children>
<children xmi:type="notation:Node" xmi:id="_SUNqcKGbEdy6I6R2I8Pp5Q" type="7003">
<styles xmi:type="notation:DrawerStyle" xmi:id="_SUNqcaGbEdy6I6R2I8Pp5Q"/>
<styles xmi:type="notation:TitleStyle" xmi:id="_SUNqcqGbEdy6I6R2I8Pp5Q" showTitle="true"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_SUNqc6GbEdy6I6R2I8Pp5Q"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_SUNqdKGbEdy6I6R2I8Pp5Q"/>
</children>
<styles xmi:type="notation:ShapeStyle" xmi:id="_SUL1QaGbEdy6I6R2I8Pp5Q" fontName="Sans Serif"/>
<element xmi:type="uml:Class" href="pythonTree.uml#_ST-Z4KGbEdy6I6R2I8Pp5Q"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_SUL1QqGbEdy6I6R2I8Pp5Q" x="26" y="416"/>
</children>
<children xmi:type="notation:Node" xmi:id="_V4DIIKGcEdyiqaZxdx2orw" type="2001">
<children xmi:type="notation:Node" xmi:id="_V4FkYKGcEdyiqaZxdx2orw" type="5003">
<styles xmi:type="notation:FontStyle" xmi:id="_V4P8cKGcEdyiqaZxdx2orw"/>
</children>
<children xmi:type="notation:Node" xmi:id="_V4GLcKGcEdyiqaZxdx2orw" type="5019"/>
<children xmi:type="notation:Node" xmi:id="_V4IAoKGcEdyiqaZxdx2orw" type="7001">
<children xmi:type="notation:Node" xmi:id="_1iS24KGdEdyiqaZxdx2orw" type="3001">
<element xmi:type="uml:Property" href="pythonTree.uml#_1h4nMKGdEdyiqaZxdx2orw"/>
<layoutConstraint xmi:type="notation:Location" xmi:id="_1iS24aGdEdyiqaZxdx2orw"/>
</children>
<children xmi:type="notation:Node" xmi:id="_85lNgKGdEdyiqaZxdx2orw" type="3001">
<element xmi:type="uml:Property" href="pythonTree.uml#_85RrgKGdEdyiqaZxdx2orw"/>
<layoutConstraint xmi:type="notation:Location" xmi:id="_85lNgaGdEdyiqaZxdx2orw"/>
</children>
<children xmi:type="notation:Node" xmi:id="_sIgnkKGeEdyiqaZxdx2orw" type="3001">
<element xmi:type="uml:Property" href="pythonTree.uml#_sINsoKGeEdyiqaZxdx2orw"/>
<layoutConstraint xmi:type="notation:Location" xmi:id="_sIgnkaGeEdyiqaZxdx2orw"/>
</children>
<children xmi:type="notation:Node" xmi:id="_zhDQgKGgEdyiqaZxdx2orw" type="3001">
<element xmi:type="uml:Property" href="pythonTree.uml#_zgt5UKGgEdyiqaZxdx2orw"/>
<layoutConstraint xmi:type="notation:Location" xmi:id="_zhDQgaGgEdyiqaZxdx2orw"/>
</children>
<styles xmi:type="notation:DrawerStyle" xmi:id="_V4IAoaGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:TitleStyle" xmi:id="_V4IAoqGcEdyiqaZxdx2orw" showTitle="true"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_V4IAo6GcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_V4IApKGcEdyiqaZxdx2orw"/>
</children>
<children xmi:type="notation:Node" xmi:id="_V4J10KGcEdyiqaZxdx2orw" type="7002">
<children xmi:type="notation:Node" xmi:id="_5aWtkKGdEdyiqaZxdx2orw" type="3002">
<element xmi:type="uml:Operation" href="pythonTree.uml#_5aDyoKGdEdyiqaZxdx2orw"/>
<layoutConstraint xmi:type="notation:Location" xmi:id="_5aWtkaGdEdyiqaZxdx2orw"/>
</children>
<children xmi:type="notation:Node" xmi:id="_6r2KoKGdEdyiqaZxdx2orw" type="3002">
<element xmi:type="uml:Operation" href="pythonTree.uml#_6rj2wKGdEdyiqaZxdx2orw"/>
<layoutConstraint xmi:type="notation:Location" xmi:id="_6r2KoaGdEdyiqaZxdx2orw"/>
</children>
<styles xmi:type="notation:DrawerStyle" xmi:id="_V4J10aGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:TitleStyle" xmi:id="_V4J10qGcEdyiqaZxdx2orw" showTitle="true"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_V4J106GcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_V4J11KGcEdyiqaZxdx2orw"/>
</children>
<children xmi:type="notation:Node" xmi:id="_V4LD8KGcEdyiqaZxdx2orw" type="7003">
<styles xmi:type="notation:DrawerStyle" xmi:id="_V4LrAKGcEdyiqaZxdx2orw" collapsed="true"/>
<styles xmi:type="notation:TitleStyle" xmi:id="_V4LrAaGcEdyiqaZxdx2orw" showTitle="true"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_V4LrAqGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_V4LrA6GcEdyiqaZxdx2orw"/>
</children>
<styles xmi:type="notation:ShapeStyle" xmi:id="_V4DIIaGcEdyiqaZxdx2orw" fontName="Sans Serif"/>
<element xmi:type="uml:Class" href="pythonTree.uml#_V11hoKGcEdyiqaZxdx2orw"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_V4DIIqGcEdyiqaZxdx2orw" x="442" y="-52"/>
</children>
<children xmi:type="notation:Node" xmi:id="_ZhVjAKGcEdyiqaZxdx2orw" type="2001">
<children xmi:type="notation:Node" xmi:id="_ZhWxIKGcEdyiqaZxdx2orw" type="5003">
<styles xmi:type="notation:FontStyle" xmi:id="_ZhbCkKGcEdyiqaZxdx2orw"/>
</children>
<children xmi:type="notation:Node" xmi:id="_ZhWxIaGcEdyiqaZxdx2orw" type="5019"/>
<children xmi:type="notation:Node" xmi:id="_ZhWxIqGcEdyiqaZxdx2orw" type="7001">
<children xmi:type="notation:Node" xmi:id="_tGo5MKGdEdyiqaZxdx2orw" type="3001">
<element xmi:type="uml:Property" href="pythonTree.uml#_tGRFwqGdEdyiqaZxdx2orw"/>
<layoutConstraint xmi:type="notation:Location" xmi:id="_tGo5MaGdEdyiqaZxdx2orw"/>
</children>
<children xmi:type="notation:Node" xmi:id="_cHOVQKGeEdyiqaZxdx2orw" type="3001">
<element xmi:type="uml:Property" href="pythonTree.uml#_cG6zQKGeEdyiqaZxdx2orw"/>
<layoutConstraint xmi:type="notation:Location" xmi:id="_cHOVQaGeEdyiqaZxdx2orw"/>
</children>
<styles xmi:type="notation:DrawerStyle" xmi:id="_ZhWxI6GcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:TitleStyle" xmi:id="_ZhWxJKGcEdyiqaZxdx2orw" showTitle="true"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_ZhWxJaGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_ZhWxJqGcEdyiqaZxdx2orw"/>
</children>
<children xmi:type="notation:Node" xmi:id="_ZhXYMKGcEdyiqaZxdx2orw" type="7002">
<styles xmi:type="notation:DrawerStyle" xmi:id="_ZhXYMaGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:TitleStyle" xmi:id="_ZhXYMqGcEdyiqaZxdx2orw" showTitle="true"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_ZhXYM6GcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_ZhXYNKGcEdyiqaZxdx2orw"/>
</children>
<children xmi:type="notation:Node" xmi:id="_ZhX_QKGcEdyiqaZxdx2orw" type="7003">
<styles xmi:type="notation:DrawerStyle" xmi:id="_ZhX_QaGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:TitleStyle" xmi:id="_ZhX_QqGcEdyiqaZxdx2orw" showTitle="true"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_ZhX_Q6GcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_ZhX_RKGcEdyiqaZxdx2orw"/>
</children>
<styles xmi:type="notation:ShapeStyle" xmi:id="_ZhVjAaGcEdyiqaZxdx2orw" fontName="Sans Serif"/>
<element xmi:type="uml:Class" href="pythonTree.uml#_Zg8hcKGcEdyiqaZxdx2orw"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_ZhWKEKGcEdyiqaZxdx2orw" x="390" y="286"/>
</children>
<children xmi:type="notation:Node" xmi:id="_asOo0KGcEdyiqaZxdx2orw" type="2001">
<children xmi:type="notation:Node" xmi:id="_asQeAKGcEdyiqaZxdx2orw" type="5003">
<styles xmi:type="notation:FontStyle" xmi:id="_asVWgKGcEdyiqaZxdx2orw"/>
</children>
<children xmi:type="notation:Node" xmi:id="_asRFEKGcEdyiqaZxdx2orw" type="5019"/>
<children xmi:type="notation:Node" xmi:id="_asRFEaGcEdyiqaZxdx2orw" type="7001">
<styles xmi:type="notation:DrawerStyle" xmi:id="_asRFEqGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:TitleStyle" xmi:id="_asRFE6GcEdyiqaZxdx2orw" showTitle="true"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_asRFFKGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_asRFFaGcEdyiqaZxdx2orw"/>
</children>
<children xmi:type="notation:Node" xmi:id="_asRsIKGcEdyiqaZxdx2orw" type="7002">
<children xmi:type="notation:Node" xmi:id="_IvvGsKGfEdyiqaZxdx2orw" type="3002">
<element xmi:type="uml:Operation" href="pythonTree.uml#_Iva9oKGfEdyiqaZxdx2orw"/>
<layoutConstraint xmi:type="notation:Location" xmi:id="_IvvGsaGfEdyiqaZxdx2orw"/>
</children>
<styles xmi:type="notation:DrawerStyle" xmi:id="_asRsIaGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:TitleStyle" xmi:id="_asRsIqGcEdyiqaZxdx2orw" showTitle="true"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_asRsI6GcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_asRsJKGcEdyiqaZxdx2orw"/>
</children>
<children xmi:type="notation:Node" xmi:id="_asSTMKGcEdyiqaZxdx2orw" type="7003">
<styles xmi:type="notation:DrawerStyle" xmi:id="_asSTMaGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:TitleStyle" xmi:id="_asSTMqGcEdyiqaZxdx2orw" showTitle="true"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_asSTM6GcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_asSTNKGcEdyiqaZxdx2orw"/>
</children>
<styles xmi:type="notation:ShapeStyle" xmi:id="_asOo0aGcEdyiqaZxdx2orw" fontName="Sans Serif"/>
<element xmi:type="uml:Class" href="pythonTree.uml#_ar4qkKGcEdyiqaZxdx2orw"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_asOo0qGcEdyiqaZxdx2orw" x="598" y="442"/>
</children>
<children xmi:type="notation:Node" xmi:id="_bwBBEKGcEdyiqaZxdx2orw" type="2001">
<children xmi:type="notation:Node" xmi:id="_bwBoIKGcEdyiqaZxdx2orw" type="5003">
<styles xmi:type="notation:FontStyle" xmi:id="_bwF5kKGcEdyiqaZxdx2orw"/>
</children>
<children xmi:type="notation:Node" xmi:id="_bwBoIaGcEdyiqaZxdx2orw" type="5019"/>
<children xmi:type="notation:Node" xmi:id="_bwCPMKGcEdyiqaZxdx2orw" type="7001">
<styles xmi:type="notation:DrawerStyle" xmi:id="_bwCPMaGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:TitleStyle" xmi:id="_bwCPMqGcEdyiqaZxdx2orw" showTitle="true"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_bwCPM6GcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_bwCPNKGcEdyiqaZxdx2orw"/>
</children>
<children xmi:type="notation:Node" xmi:id="_bwCPNaGcEdyiqaZxdx2orw" type="7002">
<styles xmi:type="notation:DrawerStyle" xmi:id="_bwCPNqGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:TitleStyle" xmi:id="_bwCPN6GcEdyiqaZxdx2orw" showTitle="true"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_bwCPOKGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_bwCPOaGcEdyiqaZxdx2orw"/>
</children>
<children xmi:type="notation:Node" xmi:id="_bwC2QKGcEdyiqaZxdx2orw" type="7003">
<styles xmi:type="notation:DrawerStyle" xmi:id="_bwC2QaGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:TitleStyle" xmi:id="_bwC2QqGcEdyiqaZxdx2orw" showTitle="true"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_bwC2Q6GcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_bwC2RKGcEdyiqaZxdx2orw"/>
</children>
<styles xmi:type="notation:ShapeStyle" xmi:id="_bwBBEaGcEdyiqaZxdx2orw" fontName="Sans Serif"/>
<element xmi:type="uml:Class" href="pythonTree.uml#_bvh44KGcEdyiqaZxdx2orw"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_bwBBEqGcEdyiqaZxdx2orw" x="663" y="260"/>
</children>
<children xmi:type="notation:Node" xmi:id="_dUg5sKGcEdyiqaZxdx2orw" type="2001">
<children xmi:type="notation:Node" xmi:id="_dUhgwKGcEdyiqaZxdx2orw" type="5003">
<styles xmi:type="notation:FontStyle" xmi:id="_dUlyMKGcEdyiqaZxdx2orw"/>
</children>
<children xmi:type="notation:Node" xmi:id="_dUiH0KGcEdyiqaZxdx2orw" type="5019"/>
<children xmi:type="notation:Node" xmi:id="_dUiH0aGcEdyiqaZxdx2orw" type="7001">
<styles xmi:type="notation:DrawerStyle" xmi:id="_dUiH0qGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:TitleStyle" xmi:id="_dUiH06GcEdyiqaZxdx2orw" showTitle="true"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_dUiH1KGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_dUiH1aGcEdyiqaZxdx2orw"/>
</children>
<children xmi:type="notation:Node" xmi:id="_dUiu4KGcEdyiqaZxdx2orw" type="7002">
<styles xmi:type="notation:DrawerStyle" xmi:id="_dUiu4aGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:TitleStyle" xmi:id="_dUiu4qGcEdyiqaZxdx2orw" showTitle="true"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_dUiu46GcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_dUiu5KGcEdyiqaZxdx2orw"/>
</children>
<children xmi:type="notation:Node" xmi:id="_dUiu5aGcEdyiqaZxdx2orw" type="7003">
<styles xmi:type="notation:DrawerStyle" xmi:id="_dUiu5qGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:TitleStyle" xmi:id="_dUiu56GcEdyiqaZxdx2orw" showTitle="true"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_dUjV8KGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_dUjV8aGcEdyiqaZxdx2orw"/>
</children>
<styles xmi:type="notation:ShapeStyle" xmi:id="_dUg5saGcEdyiqaZxdx2orw" fontName="Sans Serif"/>
<element xmi:type="uml:Class" href="pythonTree.uml#_dULigKGcEdyiqaZxdx2orw"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_dUg5sqGcEdyiqaZxdx2orw" x="715" y="65"/>
</children>
<styles xmi:type="notation:DiagramStyle" xmi:id="_M8LOwaGbEdy6I6R2I8Pp5Q"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_M8LOwqGbEdy6I6R2I8Pp5Q"/>
<element xmi:type="uml:Package" href="pythonTree.uml#_Mve2kaGbEdy6I6R2I8Pp5Q"/>
<edges xmi:type="notation:Edge" xmi:id="_7yYm0KGbEdyiqaZxdx2orw" type="4005" source="_SUL1QKGbEdy6I6R2I8Pp5Q" target="_SBmQcKGbEdy6I6R2I8Pp5Q">
<children xmi:type="notation:Node" xmi:id="_7ybDEKGbEdyiqaZxdx2orw" type="6003">
<layoutConstraint xmi:type="notation:Location" xmi:id="_7ybDEaGbEdyiqaZxdx2orw" x="-17" y="6"/>
</children>
<children xmi:type="notation:Node" xmi:id="_7ycRMKGbEdyiqaZxdx2orw" visible="false" type="6004">
<layoutConstraint xmi:type="notation:Location" xmi:id="_7ycRMaGbEdyiqaZxdx2orw" y="-15"/>
</children>
<children xmi:type="notation:Node" xmi:id="_7yetcKGbEdyiqaZxdx2orw" type="6005">
<layoutConstraint xmi:type="notation:Location" xmi:id="_7yetcaGbEdyiqaZxdx2orw" x="-14" y="-10"/>
</children>
<children xmi:type="notation:Node" xmi:id="_7yfUgKGbEdyiqaZxdx2orw" type="6006">
<layoutConstraint xmi:type="notation:Location" xmi:id="_7yfUgaGbEdyiqaZxdx2orw" y="-30"/>
</children>
<children xmi:type="notation:Node" xmi:id="_7yf7kKGbEdyiqaZxdx2orw" type="6007">
<layoutConstraint xmi:type="notation:Location" xmi:id="_7yf7kaGbEdyiqaZxdx2orw" y="-30"/>
</children>
<children xmi:type="notation:Node" xmi:id="_7ygioKGbEdyiqaZxdx2orw" type="6008">
<layoutConstraint xmi:type="notation:Location" xmi:id="_7yhJsKGbEdyiqaZxdx2orw" y="15"/>
</children>
<children xmi:type="notation:Node" xmi:id="_7yhwwKGbEdyiqaZxdx2orw" type="6009">
<layoutConstraint xmi:type="notation:Location" xmi:id="_7yhwwaGbEdyiqaZxdx2orw" x="10" y="13"/>
</children>
<styles xmi:type="notation:RoutingStyle" xmi:id="_7yYm0aGbEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FontStyle" xmi:id="_7yYm0qGbEdyiqaZxdx2orw" fontName="Sans Serif"/>
<element xmi:type="uml:Association" href="pythonTree.uml#_7w9DcKGbEdyiqaZxdx2orw"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_7yYm06GbEdyiqaZxdx2orw" points="[0, -2, -44, 104]$[-14, -107, -58, -1]$[41, -107, -3, -1]"/>
<sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_76RXgKGbEdyiqaZxdx2orw" id="(0.07826087,0.01923077)"/>
<targetAnchor xmi:type="notation:IdentityAnchor" xmi:id="_HKc10KGdEdyiqaZxdx2orw" id="(0.013043478,0.8787879)"/>
</edges>
<edges xmi:type="notation:Edge" xmi:id="_VEztUKGcEdyiqaZxdx2orw" type="4001" source="_SUL1QKGbEdy6I6R2I8Pp5Q" target="_SBmQcKGbEdy6I6R2I8Pp5Q">
<styles xmi:type="notation:ConnectorStyle" xmi:id="_VEztUaGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FontStyle" xmi:id="_VEztUqGcEdyiqaZxdx2orw" fontName="Sans Serif"/>
<element xmi:type="uml:Generalization" href="pythonTree.uml#_VD-m4KGcEdyiqaZxdx2orw"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_VEztU6GcEdyiqaZxdx2orw" points="[18, -17, -82, 79]$[94, -87, -6, 9]"/>
<sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_VE8QMKGcEdyiqaZxdx2orw" id="(0.83913046,0.16346154)"/>
<targetAnchor xmi:type="notation:IdentityAnchor" xmi:id="_VE8QMaGcEdyiqaZxdx2orw" id="(0.32857144,0.9)"/>
</edges>
<edges xmi:type="notation:Edge" xmi:id="_YFtSgKGcEdyiqaZxdx2orw" type="4001" source="_SBmQcKGbEdy6I6R2I8Pp5Q" target="_V4DIIKGcEdyiqaZxdx2orw">
<styles xmi:type="notation:ConnectorStyle" xmi:id="_YFtSgaGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FontStyle" xmi:id="_YFtSgqGcEdyiqaZxdx2orw" fontName="Sans Serif"/>
<element xmi:type="uml:Generalization" href="pythonTree.uml#_YFqPMKGcEdyiqaZxdx2orw"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_YFtSg6GcEdyiqaZxdx2orw" points="[12, -14, -117, 111]$[67, -116, -62, 9]"/>
<sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_YFw84KGcEdyiqaZxdx2orw" id="(0.95,0.1)"/>
</edges>
<edges xmi:type="notation:Edge" xmi:id="_g0CUkKGcEdyiqaZxdx2orw" type="4001" source="_ZhVjAKGcEdyiqaZxdx2orw" target="_V4DIIKGcEdyiqaZxdx2orw">
<styles xmi:type="notation:ConnectorStyle" xmi:id="_g0CUkaGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FontStyle" xmi:id="_g0CUkqGcEdyiqaZxdx2orw" fontName="Sans Serif"/>
<element xmi:type="uml:Generalization" href="pythonTree.uml#_gz_RQKGcEdyiqaZxdx2orw"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_g0CUk6GcEdyiqaZxdx2orw" points="[-12, -45, 40, 131]$[10, -178, 62, -2]"/>
<sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_GNELEKGeEdyiqaZxdx2orw" id="(0.32894737,0.028846154)"/>
<targetAnchor xmi:type="notation:IdentityAnchor" xmi:id="_GdcJYKGeEdyiqaZxdx2orw" id="(0.2,0.9794521)"/>
</edges>
<edges xmi:type="notation:Edge" xmi:id="_hm1DcKGcEdyiqaZxdx2orw" type="4001" source="_asOo0KGcEdyiqaZxdx2orw" target="_V4DIIKGcEdyiqaZxdx2orw">
<styles xmi:type="notation:ConnectorStyle" xmi:id="_hm1DcaGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FontStyle" xmi:id="_hm1DcqGcEdyiqaZxdx2orw" fontName="Sans Serif"/>
<element xmi:type="uml:Generalization" href="pythonTree.uml#_hmyAIKGcEdyiqaZxdx2orw"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_hm1Dc6GcEdyiqaZxdx2orw" points="[-2, -18, 22, 215]$[-53, -215, -29, 18]"/>
<sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_hm4t0KGcEdyiqaZxdx2orw" id="(0.31308413,0.025423728)"/>
<targetAnchor xmi:type="notation:IdentityAnchor" xmi:id="_hm4t0aGcEdyiqaZxdx2orw" id="(0.97333336,0.9683544)"/>
</edges>
<edges xmi:type="notation:Edge" xmi:id="_iB8SIKGcEdyiqaZxdx2orw" type="4001" source="_bwBBEKGcEdyiqaZxdx2orw" target="_V4DIIKGcEdyiqaZxdx2orw">
<styles xmi:type="notation:ConnectorStyle" xmi:id="_iB8SIaGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FontStyle" xmi:id="_iB8SIqGcEdyiqaZxdx2orw" fontName="Sans Serif"/>
<element xmi:type="uml:Generalization" href="pythonTree.uml#_iB514KGcEdyiqaZxdx2orw"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_iB8SI6GcEdyiqaZxdx2orw" points="[-8, -12, 155, 219]$[-145, -224, 18, 7]"/>
<sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_iB_VcKGcEdyiqaZxdx2orw" id="(0.7810219,0.13333334)"/>
<targetAnchor xmi:type="notation:IdentityAnchor" xmi:id="_iB_VcaGcEdyiqaZxdx2orw" id="(0.8548387,0.7)"/>
</edges>
<edges xmi:type="notation:Edge" xmi:id="_iXqqgKGcEdyiqaZxdx2orw" type="4001" source="_dUg5sKGcEdyiqaZxdx2orw" target="_V4DIIKGcEdyiqaZxdx2orw">
<styles xmi:type="notation:ConnectorStyle" xmi:id="_iXqqgaGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FontStyle" xmi:id="_iXqqgqGcEdyiqaZxdx2orw" fontName="Sans Serif"/>
<element xmi:type="uml:Generalization" href="pythonTree.uml#_iXnnMKGcEdyiqaZxdx2orw"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_iXqqg6GcEdyiqaZxdx2orw" points="[-24, -16, 183, 124]$[-181, -139, 26, 1]"/>
<sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_iXtt0KGcEdyiqaZxdx2orw" id="(0.2689655,0.17777778)"/>
<targetAnchor xmi:type="notation:IdentityAnchor" xmi:id="_iXtt0aGcEdyiqaZxdx2orw" id="(0.7903226,0.51111114)"/>
</edges>
<edges xmi:type="notation:Edge" xmi:id="_oCTSEKGcEdyiqaZxdx2orw" type="4005" source="_SBmQcKGbEdy6I6R2I8Pp5Q" target="_ZhVjAKGcEdyiqaZxdx2orw">
<children xmi:type="notation:Node" xmi:id="_oCT5IKGcEdyiqaZxdx2orw" type="6003">
<layoutConstraint xmi:type="notation:Location" xmi:id="_oCT5IaGcEdyiqaZxdx2orw" x="-24" y="-9"/>
</children>
<children xmi:type="notation:Node" xmi:id="_oCT5IqGcEdyiqaZxdx2orw" visible="false" type="6004">
<layoutConstraint xmi:type="notation:Location" xmi:id="_oCT5I6GcEdyiqaZxdx2orw" y="-15"/>
</children>
<children xmi:type="notation:Node" xmi:id="_oCUgMKGcEdyiqaZxdx2orw" type="6005">
<layoutConstraint xmi:type="notation:Location" xmi:id="_oCUgMaGcEdyiqaZxdx2orw" x="10" y="39"/>
</children>
<children xmi:type="notation:Node" xmi:id="_oCUgMqGcEdyiqaZxdx2orw" type="6006">
<layoutConstraint xmi:type="notation:Location" xmi:id="_oCUgM6GcEdyiqaZxdx2orw" y="-30"/>
</children>
<children xmi:type="notation:Node" xmi:id="_oCVHQKGcEdyiqaZxdx2orw" type="6007">
<layoutConstraint xmi:type="notation:Location" xmi:id="_oCVHQaGcEdyiqaZxdx2orw" y="-30"/>
</children>
<children xmi:type="notation:Node" xmi:id="_oCVHQqGcEdyiqaZxdx2orw" type="6008">
<layoutConstraint xmi:type="notation:Location" xmi:id="_oCVHQ6GcEdyiqaZxdx2orw" y="15"/>
</children>
<children xmi:type="notation:Node" xmi:id="_oCVHRKGcEdyiqaZxdx2orw" type="6009">
<layoutConstraint xmi:type="notation:Location" xmi:id="_oCVHRaGcEdyiqaZxdx2orw" x="15" y="-18"/>
</children>
<styles xmi:type="notation:RoutingStyle" xmi:id="_oCTSEaGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FontStyle" xmi:id="_oCTSEqGcEdyiqaZxdx2orw" fontName="Sans Serif"/>
<element xmi:type="uml:Association" href="pythonTree.uml#_oCL9UKGcEdyiqaZxdx2orw"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_oCTSE6GcEdyiqaZxdx2orw" points="[3, -1, -82, -66]$[91, -1, 6, -66]$[91, 65, 6, 0]"/>
<sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_oCam0KGcEdyiqaZxdx2orw" id="(0.98695654,0.1969697)"/>
<targetAnchor xmi:type="notation:IdentityAnchor" xmi:id="_oCam0aGcEdyiqaZxdx2orw" id="(0.118421055,0.0)"/>
</edges>
<edges xmi:type="notation:Edge" xmi:id="_qqifoKGcEdyiqaZxdx2orw" type="4005" source="_SBmQcKGbEdy6I6R2I8Pp5Q" target="_asOo0KGcEdyiqaZxdx2orw">
<children xmi:type="notation:Node" xmi:id="_qqjGsKGcEdyiqaZxdx2orw" type="6003">
<layoutConstraint xmi:type="notation:Location" xmi:id="_qqjGsaGcEdyiqaZxdx2orw" x="38" y="9"/>
</children>
<children xmi:type="notation:Node" xmi:id="_qqjGsqGcEdyiqaZxdx2orw" visible="false" type="6004">
<layoutConstraint xmi:type="notation:Location" xmi:id="_qqjGs6GcEdyiqaZxdx2orw" y="-15"/>
</children>
<children xmi:type="notation:Node" xmi:id="_qqjGtKGcEdyiqaZxdx2orw" type="6005">
<layoutConstraint xmi:type="notation:Location" xmi:id="_qqjGtaGcEdyiqaZxdx2orw" x="39" y="-13"/>
</children>
<children xmi:type="notation:Node" xmi:id="_qqjGtqGcEdyiqaZxdx2orw" type="6006">
<layoutConstraint xmi:type="notation:Location" xmi:id="_qqjGt6GcEdyiqaZxdx2orw" y="-30"/>
</children>
<children xmi:type="notation:Node" xmi:id="_qqjGuKGcEdyiqaZxdx2orw" type="6007">
<layoutConstraint xmi:type="notation:Location" xmi:id="_qqjGuaGcEdyiqaZxdx2orw" y="-30"/>
</children>
<children xmi:type="notation:Node" xmi:id="_qqjtwKGcEdyiqaZxdx2orw" type="6008">
<layoutConstraint xmi:type="notation:Location" xmi:id="_qqjtwaGcEdyiqaZxdx2orw" y="15"/>
</children>
<children xmi:type="notation:Node" xmi:id="_qqjtwqGcEdyiqaZxdx2orw" type="6009">
<layoutConstraint xmi:type="notation:Location" xmi:id="_qqjtw6GcEdyiqaZxdx2orw" x="47" y="13"/>
</children>
<styles xmi:type="notation:RoutingStyle" xmi:id="_qqifoaGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FontStyle" xmi:id="_qqifoqGcEdyiqaZxdx2orw" fontName="Sans Serif"/>
<element xmi:type="uml:Association" href="pythonTree.uml#_qqfcUKGcEdyiqaZxdx2orw"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_qqifo6GcEdyiqaZxdx2orw" points="[-1, 28, -298, -209]$[-1, 230, -298, -7]$[293, 230, -4, -7]"/>
<sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_qqmKAKGcEdyiqaZxdx2orw" id="(0.8742857,0.78846157)"/>
<targetAnchor xmi:type="notation:IdentityAnchor" xmi:id="_qqmKAaGcEdyiqaZxdx2orw" id="(0.0,0.7372881)"/>
</edges>
<edges xmi:type="notation:Edge" xmi:id="_ta5HYKGcEdyiqaZxdx2orw" type="4005" source="_asOo0KGcEdyiqaZxdx2orw" target="_bwBBEKGcEdyiqaZxdx2orw">
<children xmi:type="notation:Node" xmi:id="_ta5ucKGcEdyiqaZxdx2orw" type="6003">
<layoutConstraint xmi:type="notation:Location" xmi:id="_ta5ucaGcEdyiqaZxdx2orw" x="-43" y="-22"/>
</children>
<children xmi:type="notation:Node" xmi:id="_ta5ucqGcEdyiqaZxdx2orw" visible="false" type="6004">
<layoutConstraint xmi:type="notation:Location" xmi:id="_ta5uc6GcEdyiqaZxdx2orw" y="-15"/>
</children>
<children xmi:type="notation:Node" xmi:id="_ta6VgKGcEdyiqaZxdx2orw" type="6005">
<layoutConstraint xmi:type="notation:Location" xmi:id="_ta6VgaGcEdyiqaZxdx2orw" x="11" y="-36"/>
</children>
<children xmi:type="notation:Node" xmi:id="_ta6VgqGcEdyiqaZxdx2orw" type="6006">
<layoutConstraint xmi:type="notation:Location" xmi:id="_ta6Vg6GcEdyiqaZxdx2orw" y="-30"/>
</children>
<children xmi:type="notation:Node" xmi:id="_ta6VhKGcEdyiqaZxdx2orw" type="6007">
<layoutConstraint xmi:type="notation:Location" xmi:id="_ta6VhaGcEdyiqaZxdx2orw" y="-30"/>
</children>
<children xmi:type="notation:Node" xmi:id="_ta68kKGcEdyiqaZxdx2orw" type="6008">
<layoutConstraint xmi:type="notation:Location" xmi:id="_ta68kaGcEdyiqaZxdx2orw" y="15"/>
</children>
<children xmi:type="notation:Node" xmi:id="_ta68kqGcEdyiqaZxdx2orw" type="6009">
<layoutConstraint xmi:type="notation:Location" xmi:id="_ta68k6GcEdyiqaZxdx2orw" x="12" y="13"/>
</children>
<styles xmi:type="notation:RoutingStyle" xmi:id="_ta5HYaGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FontStyle" xmi:id="_ta5HYqGcEdyiqaZxdx2orw" fontName="Sans Serif"/>
<element xmi:type="uml:Association" href="pythonTree.uml#_taxyoKGcEdyiqaZxdx2orw"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_ta5HY6GcEdyiqaZxdx2orw" points="[2, -1, -54, 135]$[63, -1, 7, 135]$[63, -133, 7, 3]"/>
<sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_tbAcIKGcEdyiqaZxdx2orw" id="(0.99065423,0.47115386)"/>
<targetAnchor xmi:type="notation:IdentityAnchor" xmi:id="_tbAcIaGcEdyiqaZxdx2orw" id="(0.9099099,0.97115386)"/>
</edges>
<edges xmi:type="notation:Edge" xmi:id="_wxOKAKGcEdyiqaZxdx2orw" type="4005" source="_bwBBEKGcEdyiqaZxdx2orw" target="_dUg5sKGcEdyiqaZxdx2orw">
<children xmi:type="notation:Node" xmi:id="_wxOxEKGcEdyiqaZxdx2orw" type="6003">
<layoutConstraint xmi:type="notation:Location" xmi:id="_wxOxEaGcEdyiqaZxdx2orw" x="-8" y="-6"/>
</children>
<children xmi:type="notation:Node" xmi:id="_wxOxEqGcEdyiqaZxdx2orw" visible="false" type="6004">
<layoutConstraint xmi:type="notation:Location" xmi:id="_wxOxE6GcEdyiqaZxdx2orw" y="-15"/>
</children>
<children xmi:type="notation:Node" xmi:id="_wxPYIKGcEdyiqaZxdx2orw" type="6005">
<layoutConstraint xmi:type="notation:Location" xmi:id="_wxPYIaGcEdyiqaZxdx2orw" x="2" y="-36"/>
</children>
<children xmi:type="notation:Node" xmi:id="_wxPYIqGcEdyiqaZxdx2orw" type="6006">
<layoutConstraint xmi:type="notation:Location" xmi:id="_wxPYI6GcEdyiqaZxdx2orw" y="-30"/>
</children>
<children xmi:type="notation:Node" xmi:id="_wxPYJKGcEdyiqaZxdx2orw" type="6007">
<layoutConstraint xmi:type="notation:Location" xmi:id="_wxPYJaGcEdyiqaZxdx2orw" y="-30"/>
</children>
<children xmi:type="notation:Node" xmi:id="_wxP_MKGcEdyiqaZxdx2orw" type="6008">
<layoutConstraint xmi:type="notation:Location" xmi:id="_wxP_MaGcEdyiqaZxdx2orw" y="15"/>
</children>
<children xmi:type="notation:Node" xmi:id="_wxP_MqGcEdyiqaZxdx2orw" type="6009">
<layoutConstraint xmi:type="notation:Location" xmi:id="_wxP_M6GcEdyiqaZxdx2orw" y="15"/>
</children>
<styles xmi:type="notation:RoutingStyle" xmi:id="_wxOKAaGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FontStyle" xmi:id="_wxOKAqGcEdyiqaZxdx2orw" fontName="Sans Serif"/>
<element xmi:type="uml:Association" href="pythonTree.uml#_wxHcUKGcEdyiqaZxdx2orw"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_wxOKA6GcEdyiqaZxdx2orw" points="[14, -14, -46, 46]$[63, -46, 3, 14]"/>
<sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_wxVewKGcEdyiqaZxdx2orw" id="(0.7927928,0.009615385)"/>
<targetAnchor xmi:type="notation:IdentityAnchor" xmi:id="_wxVewaGcEdyiqaZxdx2orw" id="(0.82758623,0.93333334)"/>
</edges>
<edges xmi:type="notation:Edge" xmi:id="_7HjrsKGcEdyiqaZxdx2orw" type="4005" source="_SBmQcKGbEdy6I6R2I8Pp5Q" target="_SBmQcKGbEdy6I6R2I8Pp5Q">
<children xmi:type="notation:Node" xmi:id="_7HkSwKGcEdyiqaZxdx2orw" type="6003">
<layoutConstraint xmi:type="notation:Location" xmi:id="_7Hk50KGcEdyiqaZxdx2orw" x="48" y="9"/>
</children>
<children xmi:type="notation:Node" xmi:id="_7Hk50aGcEdyiqaZxdx2orw" visible="false" type="6004">
<layoutConstraint xmi:type="notation:Location" xmi:id="_7Hk50qGcEdyiqaZxdx2orw" x="-28" y="17"/>
</children>
<children xmi:type="notation:Node" xmi:id="_7Hk506GcEdyiqaZxdx2orw" type="6005">
<layoutConstraint xmi:type="notation:Location" xmi:id="_7Hk51KGcEdyiqaZxdx2orw" x="17" y="-44"/>
</children>
<children xmi:type="notation:Node" xmi:id="_7Hlg4KGcEdyiqaZxdx2orw" type="6006">
<layoutConstraint xmi:type="notation:Location" xmi:id="_7Hlg4aGcEdyiqaZxdx2orw" y="-30"/>
</children>
<children xmi:type="notation:Node" xmi:id="_7Hlg4qGcEdyiqaZxdx2orw" type="6007">
<layoutConstraint xmi:type="notation:Location" xmi:id="_7Hlg46GcEdyiqaZxdx2orw" y="-30"/>
</children>
<children xmi:type="notation:Node" xmi:id="_7Hlg5KGcEdyiqaZxdx2orw" type="6008">
<layoutConstraint xmi:type="notation:Location" xmi:id="_7Hlg5aGcEdyiqaZxdx2orw" y="15"/>
</children>
<children xmi:type="notation:Node" xmi:id="_7HmH8KGcEdyiqaZxdx2orw" type="6009">
<layoutConstraint xmi:type="notation:Location" xmi:id="_7HmH8aGcEdyiqaZxdx2orw" x="33" y="-21"/>
</children>
<styles xmi:type="notation:RoutingStyle" xmi:id="_7HjrsaGcEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FontStyle" xmi:id="_7HjrsqGcEdyiqaZxdx2orw" fontName="Sans Serif"/>
<element xmi:type="uml:Association" href="pythonTree.uml#_7Hc-AKGcEdyiqaZxdx2orw"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_7Hjrs6GcEdyiqaZxdx2orw" points="[0, 6, -97, 48]$[-35, 6, -132, 48]$[-35, -100, -132, -58]$[97, -100, 0, -58]$[97, -46, 0, -4]"/>
<sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_7HrAcKGcEdyiqaZxdx2orw" id="(0.0,0.34848484)"/>
<targetAnchor xmi:type="notation:IdentityAnchor" xmi:id="_7HrngKGcEdyiqaZxdx2orw" id="(0.42173913,0.030303031)"/>
</edges>
<edges xmi:type="notation:Edge" xmi:id="_tGWlUKGdEdyiqaZxdx2orw" type="4005" source="_ZhVjAKGcEdyiqaZxdx2orw" target="_asOo0KGcEdyiqaZxdx2orw">
<children xmi:type="notation:Node" xmi:id="_tGXMYKGdEdyiqaZxdx2orw" type="6003">
<layoutConstraint xmi:type="notation:Location" xmi:id="_tGXMYaGdEdyiqaZxdx2orw" x="-30" y="10"/>
</children>
<children xmi:type="notation:Node" xmi:id="_tGXMYqGdEdyiqaZxdx2orw" visible="false" type="6004">
<layoutConstraint xmi:type="notation:Location" xmi:id="_tGXMY6GdEdyiqaZxdx2orw" y="-15"/>
</children>
<children xmi:type="notation:Node" xmi:id="_tGXMZKGdEdyiqaZxdx2orw" type="6005">
<layoutConstraint xmi:type="notation:Location" xmi:id="_tGXMZaGdEdyiqaZxdx2orw" x="-20" y="-14"/>
</children>
<children xmi:type="notation:Node" xmi:id="_tGXzcKGdEdyiqaZxdx2orw" type="6006">
<layoutConstraint xmi:type="notation:Location" xmi:id="_tGXzcaGdEdyiqaZxdx2orw" y="-30"/>
</children>
<children xmi:type="notation:Node" xmi:id="_tGXzcqGdEdyiqaZxdx2orw" type="6007">
<layoutConstraint xmi:type="notation:Location" xmi:id="_tGXzc6GdEdyiqaZxdx2orw" y="-30"/>
</children>
<children xmi:type="notation:Node" xmi:id="_tGXzdKGdEdyiqaZxdx2orw" type="6008">
<layoutConstraint xmi:type="notation:Location" xmi:id="_tGYagKGdEdyiqaZxdx2orw" y="15"/>
</children>
<children xmi:type="notation:Node" xmi:id="_tGYagaGdEdyiqaZxdx2orw" type="6009">
<layoutConstraint xmi:type="notation:Location" xmi:id="_tGYagqGdEdyiqaZxdx2orw" y="15"/>
</children>
<styles xmi:type="notation:RoutingStyle" xmi:id="_tGWlUaGdEdyiqaZxdx2orw"/>
<styles xmi:type="notation:FontStyle" xmi:id="_tGWlUqGdEdyiqaZxdx2orw" fontName="Sans Serif"/>
<element xmi:type="uml:Association" href="pythonTree.uml#_tGP3oKGdEdyiqaZxdx2orw"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_tGWlU6GdEdyiqaZxdx2orw" points="[0, 5, -154, -49]$[0, 54, -154, 0]$[114, 54, -40, 0]"/>
<sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_tGd6EKGdEdyiqaZxdx2orw" id="(0.4122807,0.9576271)"/>
<targetAnchor xmi:type="notation:IdentityAnchor" xmi:id="_tGd6EaGdEdyiqaZxdx2orw" id="(0.18691589,0.10576923)"/>
</edges>
</notation:Diagram>

BIN
pyUml/images/class_obj.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 B

BIN
pyUml/images/manageViews.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 B

BIN
pyUml/images/openuml.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 B

BIN
pyUml/images/package_obj.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 B

BIN
pyUml/images/py2uml.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

BIN
pyUml/images/pyUML_icons.tgz Executable file

Binary file not shown.

BIN
pyUml/images/uml2py.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 B

BIN
pyUml/lib/refactoring.jar Executable file

Binary file not shown.

319
pyUml/license.html Executable file
View File

@ -0,0 +1,319 @@
<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-html40"><head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="ProgId" content="Word.Document">
<meta name="Generator" content="Microsoft Word 9">
<meta name="Originator" content="Microsoft Word 9">
<link rel="File-List" href="http://www.eclipse.org/org/documents/Eclipse%20EPL%202003_11_10%20Final_files/filelist.xml"><title>Eclipse Public License - Version 1.0</title><!--[if gte mso 9]><xml>
<o:DocumentProperties>
<o:Revision>2</o:Revision>
<o:TotalTime>3</o:TotalTime>
<o:Created>2004-03-05T23:03:00Z</o:Created>
<o:LastSaved>2004-03-05T23:03:00Z</o:LastSaved>
<o:Pages>4</o:Pages>
<o:Words>1626</o:Words>
<o:Characters>9270</o:Characters>
<o:Lines>77</o:Lines>
<o:Paragraphs>18</o:Paragraphs>
<o:CharactersWithSpaces>11384</o:CharactersWithSpaces>
<o:Version>9.4402</o:Version>
</o:DocumentProperties>
</xml><![endif]--><!--[if gte mso 9]><xml>
<w:WordDocument>
<w:TrackRevisions/>
</w:WordDocument>
</xml><![endif]-->
<style>
<!--
/* Font Definitions */
@font-face
{font-family:Tahoma;
panose-1:2 11 6 4 3 5 4 4 2 4;
mso-font-charset:0;
mso-generic-font-family:swiss;
mso-font-pitch:variable;
mso-font-signature:553679495 -2147483648 8 0 66047 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-parent:"";
margin:0in;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:"Times New Roman";}
p
{margin-right:0in;
mso-margin-top-alt:auto;
mso-margin-bottom-alt:auto;
margin-left:0in;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:"Times New Roman";}
p.BalloonText, li.BalloonText, div.BalloonText
{mso-style-name:"Balloon Text";
margin:0in;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:8.0pt;
font-family:Tahoma;
mso-fareast-font-family:"Times New Roman";}
@page Section1
{size:8.5in 11.0in;
margin:1.0in 1.25in 1.0in 1.25in;
mso-header-margin:.5in;
mso-footer-margin:.5in;
mso-paper-source:0;}
div.Section1
{page:Section1;}
-->
</style></head>
<body style="" lang="EN-US">
<div class="Section1">
<p style="text-align: center;" align="center"><b>Eclipse Public License - v 1.0</b>
</p>
<p><span style="font-size: 10pt;">THE ACCOMPANYING PROGRAM IS PROVIDED UNDER
THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE,
REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE
OF THIS AGREEMENT.</span> </p>
<p><b><span style="font-size: 10pt;">1. DEFINITIONS</span></b> </p>
<p><span style="font-size: 10pt;">"Contribution" means:</span> </p>
<p class="MsoNormal" style="margin-left: 0.5in;"><span style="font-size: 10pt;">a)
in the case of the initial Contributor, the initial code and documentation
distributed under this Agreement, and<br clear="left">
b) in the case of each subsequent Contributor:</span></p>
<p class="MsoNormal" style="margin-left: 0.5in;"><span style="font-size: 10pt;">i)
changes to the Program, and</span></p>
<p class="MsoNormal" style="margin-left: 0.5in;"><span style="font-size: 10pt;">ii)
additions to the Program;</span></p>
<p class="MsoNormal" style="margin-left: 0.5in;"><span style="font-size: 10pt;">where
such changes and/or additions to the Program originate from and are distributed
by that particular Contributor. A Contribution 'originates' from a Contributor
if it was added to the Program by such Contributor itself or anyone acting on
such Contributor's behalf. Contributions do not include additions to the
Program which: (i) are separate modules of software distributed in conjunction
with the Program under their own license agreement, and (ii) are not derivative
works of the Program. </span></p>
<p><span style="font-size: 10pt;">"Contributor" means any person or
entity that distributes the Program.</span> </p>
<p><span style="font-size: 10pt;">"Licensed Patents " mean patent
claims licensable by a Contributor which are necessarily infringed by the use
or sale of its Contribution alone or when combined with the Program. </span></p>
<p><span style="font-size: 10pt;">"Program" means the Contributions
distributed in accordance with this Agreement.</span> </p>
<p><span style="font-size: 10pt;">"Recipient" means anyone who
receives the Program under this Agreement, including all Contributors.</span> </p>
<p><b><span style="font-size: 10pt;">2. GRANT OF RIGHTS</span></b> </p>
<p class="MsoNormal" style="margin-left: 0.5in;"><span style="font-size: 10pt;">a)
Subject to the terms of this Agreement, each Contributor hereby grants Recipient
a non-exclusive, worldwide, royalty-free copyright license to<span style="color: red;"> </span>reproduce, prepare derivative works of, publicly
display, publicly perform, distribute and sublicense the Contribution of such
Contributor, if any, and such derivative works, in source code and object code
form.</span></p>
<p class="MsoNormal" style="margin-left: 0.5in;"><span style="font-size: 10pt;">b)
Subject to the terms of this Agreement, each Contributor hereby grants
Recipient a non-exclusive, worldwide,<span style="color: green;"> </span>royalty-free
patent license under Licensed Patents to make, use, sell, offer to sell, import
and otherwise transfer the Contribution of such Contributor, if any, in source
code and object code form. This patent license shall apply to the combination
of the Contribution and the Program if, at the time the Contribution is added
by the Contributor, such addition of the Contribution causes such combination
to be covered by the Licensed Patents. The patent license shall not apply to
any other combinations which include the Contribution. No hardware per se is
licensed hereunder. </span></p>
<p class="MsoNormal" style="margin-left: 0.5in;"><span style="font-size: 10pt;">c)
Recipient understands that although each Contributor grants the licenses to its
Contributions set forth herein, no assurances are provided by any Contributor
that the Program does not infringe the patent or other intellectual property
rights of any other entity. Each Contributor disclaims any liability to Recipient
for claims brought by any other entity based on infringement of intellectual
property rights or otherwise. As a condition to exercising the rights and
licenses granted hereunder, each Recipient hereby assumes sole responsibility
to secure any other intellectual property rights needed, if any. For example,
if a third party patent license is required to allow Recipient to distribute
the Program, it is Recipient's responsibility to acquire that license before
distributing the Program.</span></p>
<p class="MsoNormal" style="margin-left: 0.5in;"><span style="font-size: 10pt;">d)
Each Contributor represents that to its knowledge it has sufficient copyright
rights in its Contribution, if any, to grant the copyright license set forth in
this Agreement. </span></p>
<p><b><span style="font-size: 10pt;">3. REQUIREMENTS</span></b> </p>
<p><span style="font-size: 10pt;">A Contributor may choose to distribute the
Program in object code form under its own license agreement, provided that:</span>
</p>
<p class="MsoNormal" style="margin-left: 0.5in;"><span style="font-size: 10pt;">a)
it complies with the terms and conditions of this Agreement; and</span></p>
<p class="MsoNormal" style="margin-left: 0.5in;"><span style="font-size: 10pt;">b)
its license agreement:</span></p>
<p class="MsoNormal" style="margin-left: 0.5in;"><span style="font-size: 10pt;">i)
effectively disclaims on behalf of all Contributors all warranties and
conditions, express and implied, including warranties or conditions of title
and non-infringement, and implied warranties or conditions of merchantability
and fitness for a particular purpose; </span></p>
<p class="MsoNormal" style="margin-left: 0.5in;"><span style="font-size: 10pt;">ii)
effectively excludes on behalf of all Contributors all liability for damages,
including direct, indirect, special, incidental and consequential damages, such
as lost profits; </span></p>
<p class="MsoNormal" style="margin-left: 0.5in;"><span style="font-size: 10pt;">iii)
states that any provisions which differ from this Agreement are offered by that
Contributor alone and not by any other party; and</span></p>
<p class="MsoNormal" style="margin-left: 0.5in;"><span style="font-size: 10pt;">iv)
states that source code for the Program is available from such Contributor, and
informs licensees how to obtain it in a reasonable manner on or through a
medium customarily used for software exchange.<span style="color: blue;"> </span></span></p>
<p><span style="font-size: 10pt;">When the Program is made available in source
code form:</span> </p>
<p class="MsoNormal" style="margin-left: 0.5in;"><span style="font-size: 10pt;">a)
it must be made available under this Agreement; and </span></p>
<p class="MsoNormal" style="margin-left: 0.5in;"><span style="font-size: 10pt;">b) a
copy of this Agreement must be included with each copy of the Program. </span></p>
<p><span style="font-size: 10pt;">Contributors may not remove or alter any
copyright notices contained within the Program. </span></p>
<p><span style="font-size: 10pt;">Each Contributor must identify itself as the
originator of its Contribution, if any, in a manner that reasonably allows
subsequent Recipients to identify the originator of the Contribution. </span></p>
<p><b><span style="font-size: 10pt;">4. COMMERCIAL DISTRIBUTION</span></b> </p>
<p><span style="font-size: 10pt;">Commercial distributors of software may
accept certain responsibilities with respect to end users, business partners
and the like. While this license is intended to facilitate the commercial use
of the Program, the Contributor who includes the Program in a commercial
product offering should do so in a manner which does not create potential
liability for other Contributors. Therefore, if a Contributor includes the
Program in a commercial product offering, such Contributor ("Commercial
Contributor") hereby agrees to defend and indemnify every other
Contributor ("Indemnified Contributor") against any losses, damages and
costs (collectively "Losses") arising from claims, lawsuits and other
legal actions brought by a third party against the Indemnified Contributor to
the extent caused by the acts or omissions of such Commercial Contributor in
connection with its distribution of the Program in a commercial product
offering. The obligations in this section do not apply to any claims or Losses
relating to any actual or alleged intellectual property infringement. In order
to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
Contributor in writing of such claim, and b) allow the Commercial Contributor
to control, and cooperate with the Commercial Contributor in, the defense and
any related settlement negotiations. The Indemnified Contributor may participate
in any such claim at its own expense.</span> </p>
<p><span style="font-size: 10pt;">For example, a Contributor might include the
Program in a commercial product offering, Product X. That Contributor is then a
Commercial Contributor. If that Commercial Contributor then makes performance
claims, or offers warranties related to Product X, those performance claims and
warranties are such Commercial Contributor's responsibility alone. Under this
section, the Commercial Contributor would have to defend claims against the
other Contributors related to those performance claims and warranties, and if a
court requires any other Contributor to pay any damages as a result, the
Commercial Contributor must pay those damages.</span> </p>
<p><b><span style="font-size: 10pt;">5. NO WARRANTY</span></b> </p>
<p><span style="font-size: 10pt;">EXCEPT AS EXPRESSLY SET FORTH IN THIS
AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,
WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
responsible for determining the appropriateness of using and distributing the
Program and assumes all risks associated with its exercise of rights under this
Agreement , including but not limited to the risks and costs of program errors,
compliance with applicable laws, damage to or loss of data, programs or
equipment, and unavailability or interruption of operations. </span></p>
<p><b><span style="font-size: 10pt;">6. DISCLAIMER OF LIABILITY</span></b> </p>
<p><span style="font-size: 10pt;">EXCEPT AS EXPRESSLY SET FORTH IN THIS
AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF
THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGES.</span> </p>
<p><b><span style="font-size: 10pt;">7. GENERAL</span></b> </p>
<p><span style="font-size: 10pt;">If any provision of this Agreement is invalid
or unenforceable under applicable law, it shall not affect the validity or
enforceability of the remainder of the terms of this Agreement, and without
further action by the parties hereto, such provision shall be reformed to the
minimum extent necessary to make such provision valid and enforceable.</span> </p>
<p><span style="font-size: 10pt;">If Recipient institutes patent litigation
against any entity (including a cross-claim or counterclaim in a lawsuit)
alleging that the Program itself (excluding combinations of the Program with
other software or hardware) infringes such Recipient's patent(s), then such
Recipient's rights granted under Section 2(b) shall terminate as of the date
such litigation is filed. </span></p>
<p><span style="font-size: 10pt;">All Recipient's rights under this Agreement
shall terminate if it fails to comply with any of the material terms or
conditions of this Agreement and does not cure such failure in a reasonable
period of time after becoming aware of such noncompliance. If all Recipient's
rights under this Agreement terminate, Recipient agrees to cease use and
distribution of the Program as soon as reasonably practicable. However,
Recipient's obligations under this Agreement and any licenses granted by
Recipient relating to the Program shall continue and survive. </span></p>
<p><span style="font-size: 10pt;">Everyone is permitted to copy and distribute
copies of this Agreement, but in order to avoid inconsistency the Agreement is
copyrighted and may only be modified in the following manner. The Agreement
Steward reserves the right to publish new versions (including revisions) of
this Agreement from time to time. No one other than the Agreement Steward has
the right to modify this Agreement. The Eclipse Foundation is the initial
Agreement Steward. The Eclipse Foundation may assign the responsibility to
serve as the Agreement Steward to a suitable separate entity. Each new version
of the Agreement will be given a distinguishing version number. The Program
(including Contributions) may always be distributed subject to the version of
the Agreement under which it was received. In addition, after a new version of
the Agreement is published, Contributor may elect to distribute the Program
(including its Contributions) under the new version. Except as expressly stated
in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to
the intellectual property of any Contributor under this Agreement, whether
expressly, by implication, estoppel or otherwise. All rights in the Program not
expressly granted under this Agreement are reserved.</span> </p>
<p><span style="font-size: 10pt;">This Agreement is governed by the laws of the
State of New York and the intellectual property laws of the United States of
America. No party to this Agreement will bring a legal action under this
Agreement more than one year after the cause of action arose. Each party waives
its rights to a jury trial in any resulting litigation.</span> </p>
<p class="MsoNormal"><!--[if !supportEmptyParas]-->&nbsp;<!--[endif]--><o:p></o:p></p>
</div>
</body></html>

121
pyUml/plugin.xml Executable file
View File

@ -0,0 +1,121 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.2"?>
<plugin>
<extension
point="org.eclipse.ui.popupMenus">
<objectContribution
adaptable="false"
id="pyUml.projectMenu"
objectClass="org.eclipse.core.internal.resources.Project">
<action
class="pyUML.actions.SyncCodeAction"
definitionId="1"
id="pyUML.1-createCode"
label="Create/Synchronize Code">
</action>
<action
class="pyUML.actions.SyncModelAction"
definitionId="2"
id="pyUML.2-testParsingAction"
label="Create/Synchronize UML Model">
</action>
<action
class="pyUML.actions.ManageViewsAction"
id="pyUML.3-manageViews"
label="Manage Views">
</action>
<action
class="pyUML.actions.OpenModelAction"
id="pyUML.4-OpenModel"
label="Open Model without Sync Run">
</action>
</objectContribution>
<objectContribution
id="pyUML.umlModelMenu"
nameFilter="*.uml"
objectClass="org.eclipse.core.resources.IFile">
<action
class="pyUML.actions.SyncCodeAction"
id="pydev-steering.createCode"
label="Create Code from Model">
</action>
<action
class="pyUML.views.SynchronizeModelByView"
id="pyUML.snycModelByView"
label="Synchronize Model by this View">
</action>
</objectContribution>
</extension>
<extension
point="org.eclipse.ui.menus">
<menuContribution
locationURI="toolbar:org.eclipse.ui.main.toolbar?after=additions">
<toolbar
id="pyUml.mainToolbar">
<command
commandId="pyUml.syncModelCommand"
icon="images/py2uml.png"
id="pyuml.toolbars.synchronizeModel"
tooltip="This starts a synchronization Run to update the UML model by the Python Code in a project.">
</command>
<command
commandId="pyUml.syncCodeCommand"
icon="images/uml2py.png"
id="pyuml.toolbars.synchronizeCode"
tooltip="This starts a synchronization Run to update the UML code by the UML diagram in a project.">
</command>
<command
commandId="pyUml.manageViewsCommand"
icon="images/manageViews.png"
id="pyuml.toolbars.manageViews"
tooltip="Manage Model Views synchronized with Main model">
</command>
<command
commandId="pyUml.openModelCommand"
icon="images/openuml.png"
id="pyuml.toolbars.openModel"
tooltip="Open the (old) UML model for a project without prior Synchronization run.">
</command>
</toolbar>
</menuContribution>
</extension>
<extension
point="org.eclipse.ui.commands">
<command
id="pyUml.syncModelCommand"
name="Synchronize Model by Code">
</command>
<command
id="pyUml.syncCodeCommand"
name="Synchronize Code By Model">
</command>
<command
id="pyUml.manageViewsCommand"
name="Manage Views">
</command>
<command
id="pyUml.openModelCommand"
name="Open UML Diagram without Synchronization">
</command>
</extension>
<extension
point="org.eclipse.ui.handlers">
<handler
class="pyUML.actions.SyncModelHandler"
commandId="pyUml.syncModelCommand">
</handler>
<handler
class="pyUML.actions.SyncCodeHandler"
commandId="pyUml.syncCodeCommand">
</handler>
<handler
class="pyUML.actions.ManageViewsHandler"
commandId="pyUml.manageViewsCommand">
</handler>
<handler
class="pyUML.actions.OpenModelHandler"
commandId="pyUml.openModelCommand">
</handler>
</extension>
</plugin>

View File

@ -0,0 +1,92 @@
package pyUML.actions;
import org.eclipse.core.resources.IProject;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.uml2.uml.Model;
import org.python.pydev.navigator.elements.PythonFile;
import pyUML.backend.GlobalConstants;
import pyUML.views.ManageViewsPage;
public class ManageViewsAction implements IObjectActionDelegate{
IWorkbenchPart part;
ISelection selection;
IProject project;
/**
* @see IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart)
*/
public void setActivePart(IAction action, IWorkbenchPart part) {
this.part = part;
}
/**
* Manual way to open a window to manage pyUML.views
* A project is needed to open a ManagViews Window
* @param project An eclipse project
*/
public static void run(IProject project) {
ManageViewsAction manageViews = new ManageViewsAction();
manageViews.project = project;
manageViews.run((IAction) null);
}
/**
* The run method used when the action is executed
* -> a new manage pyUML.views window is opened
*/
public void run(IAction action) {
try{
String umlFileName=project.getLocation().
append(GlobalConstants.getPyUmlDir()).
append(project.getName()+".uml").toOSString();
EObject diagramRoot = null;
try {
Resource resource = new ResourceSetImpl().getResource(URI.createFileURI(umlFileName), true);
diagramRoot = (EObject) resource.getContents().get(0);
} catch (WrappedException ex) {
MessageDialog.openError(null,"Error opening UML model",
"Unable to load model: " + umlFileName + "\n" +
"You must create a model before you can create pyUML.views!");
return;
}
Model model = (Model) diagramRoot;
ManageViewsPage page = new ManageViewsPage((Shell) null, model, project);
if (page != null)
page.open();
}catch (Throwable t) {
MessageDialog.openError(null,t.getClass().getName(),"Error Managing Views:\n"+t.getClass().getName()+"\n"+t.getMessage());
t.printStackTrace();
}
}
public void selectionChanged(IAction action, ISelection selection) {
if (selection instanceof TreeSelection) {
TreeSelection ts = (TreeSelection) selection;
Object selectedElement = ts.getFirstElement();
this.project = (IProject) selectedElement;
}
}
}

View File

@ -0,0 +1,28 @@
package pyUML.actions;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IProject;
import pyUML.backend.EclipseHelperMethods;
/**
* An action Handler that calls ManageViewsAction for a user-selected project
*/
public class ManageViewsHandler extends AbstractHandler{
public static IProject selectedProject = null;
@Override
public Object execute(ExecutionEvent arg0) throws ExecutionException {
EclipseHelperMethods.saveAllOpenEditors();
IProject project = EclipseHelperMethods.selectProject();
if (project == null)
return null;
ManageViewsAction.run(project);
return null;
}
}

View File

@ -0,0 +1,88 @@
package pyUML.actions;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import pyUML.backend.EclipseHelperMethods;
import pyUML.backend.GlobalConstants;
import pyUML.backend.UMLToolsHelperMethods;
import pyUML.listeners.ModelChangeListener;
public class OpenModelAction implements IWorkbenchWindowActionDelegate{
IProject project = null;
public void dispose() {
// Auto-generated method stub
}
public void init(IWorkbenchWindow window) {
// Auto-generated method stub
}
/**
* Opens the UML diagram for the given project
* @param project
*/
public static void runOpenModel(IProject project) {
OpenModelAction delegate = new OpenModelAction();
delegate.project = project;
delegate.run((IAction) null);
}
public void run(IAction action) {
this.openModel();
}
/**
* This is the central method -
* A UML diagram is opened. The project set
* in this object is used
*/
public void openModel() {
// Ensure a project was given
if (this.project == null) {
return;
}
// save all open editors
EclipseHelperMethods.saveAllOpenEditors();
// open diagram
IFile diagramFile = this.project.getWorkspace()
.getRoot().getFile(this.project.getFullPath()
.append(GlobalConstants.getPyUmlDir())
.append(project.getName()+GlobalConstants
.getDiagramExtension()));
if (! diagramFile.exists()) {
MessageDialog.openWarning(null, "Opening UML diagram failed",
"Failed to open UML diagram, because it does not seem to exist.\n" +
"Please use 'synchronize Model' to create a new Diagram!");
return;
}else {
IEditorPart modelEditor = UMLToolsHelperMethods.openDiagram(project, diagramFile, project.getName()+".uml", true);
modelEditor.addPropertyListener(new ModelChangeListener(project));
}
}
public void selectionChanged(IAction action, ISelection selection) {
if (selection instanceof TreeSelection) {
TreeSelection ts = (TreeSelection) selection;
Object selectedElement = ts.getFirstElement();
this.project = (IProject) selectedElement;
}
}
}

View File

@ -0,0 +1,27 @@
package pyUML.actions;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IProject;
import pyUML.backend.EclipseHelperMethods;
/**
* An action Handler that calls OpenModelAction for a user-selected project
*/
public class OpenModelHandler extends AbstractHandler{
public static IProject selectedProject = null;
@Override
public Object execute(ExecutionEvent arg0) throws ExecutionException {
EclipseHelperMethods.saveAllOpenEditors();
IProject project = EclipseHelperMethods.selectProject();
OpenModelAction.runOpenModel(project);
return null;
}
}

View File

@ -0,0 +1,233 @@
package pyUML.actions;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Model;
import org.eclipse.uml2.uml.resource.UMLResource;
import pyUML.backend.EclipseHelperMethods;
import pyUML.backend.GlobalConstants;
import pyUML.backend.JavaHelperMethods;
import pyUML.backend.UMLToolsHelperMethods;
import pyUML.exceptions.PyUMLCancelledException;
import pyUML.exceptions.PyUMLParseException;
import pyUML.pythonTree.PythonTreeRoot;
public class SyncCodeAction implements IObjectActionDelegate, IRunnableWithProgress{
private IProject project;
private PythonTreeRoot pythonRoot = null;
public void setActivePart(IAction action, IWorkbenchPart targetPart) {
// Auto-generated method stub
}
/**
* Run this action manually with a Progress Monitor.
* If the monitor is null, it will be created
* A PythonTreeRoot object can be given so that
* The code will not be re-analyzed for better performance.
* @param project The synchronized project
* @param root The PythonTreeRoot created before (optional)
* @param monitor A progress monitor
*/
public static void run(IProject project, PythonTreeRoot root, IProgressMonitor monitor) {
SyncCodeAction createCode = new SyncCodeAction();
createCode.setProject(project);
createCode.setRoot(root);
if (monitor == null) {
ProgressMonitorDialog dialog = new ProgressMonitorDialog(null);
try {
dialog.run(false, true, createCode);
} catch (InterruptedException e) {e.printStackTrace();}
catch (InvocationTargetException e) {e.printStackTrace();}
} else {
createCode.doSync(monitor);
}
}
/**
* run this action (
*/
public void run(IAction action) {
ProgressMonitorDialog monitor = new ProgressMonitorDialog(null);
try {
monitor.run(false, true, this);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Do a synchronize run. This is the central method.
* It is called in automatic or manual mode
* @param monitor a ProgressMonitor
*/
public void doSync(IProgressMonitor monitor) {
// read project
IPath projectPath = project.getLocation();
String umlFileName=projectPath.
append(GlobalConstants.getPyUmlDir()).
append(project.getName()+".uml").toOSString();
String umlSavedFileName=projectPath.
append(GlobalConstants.getPyUmlDir()).
append(project.getName()+"-backup.uml").toOSString();
File savedModel = new File(umlSavedFileName);
File modelToCopy = new File(umlFileName);
// read newest Model
EObject diagramRoot = UMLToolsHelperMethods.loadUMLDiagram(umlFileName);
// read backuped Model if it exists
// to be able to see what changed between models
EObject diagramRootBackup = null;
if (savedModel.exists())
diagramRootBackup = UMLToolsHelperMethods.loadUMLDiagram(umlSavedFileName);
Model model = (Model) diagramRoot;
// get model -> xmi-id dictionary
UMLResource res = (UMLResource) model.eResource();
Map<EObject, String> modelXmiDict = res.getEObjectToIDMap();
// do the same for the backupModel:
// get model -> xmi-id dictionary
Map<String, EObject> xmiModelDictOld = new HashMap<String, EObject>();
int classCount = 0; // count classes for progression bar
if (diagramRootBackup != null) {
UMLResource resBack = (UMLResource) ((Model)diagramRootBackup).eResource();
Map<EObject, String> modelXmiDictOld = resBack.getEObjectToIDMap();
// create reverse dict, so that xmi_id can be the key
for (EObject modelObject : modelXmiDictOld.keySet()) {
String xmi_id = modelXmiDictOld.get(modelObject);
xmiModelDictOld.put(xmi_id, modelObject);
if (modelObject instanceof Classifier)
classCount++;
}
}
// create PythonTree from PythonCode
if (this.pythonRoot == null)
try {
this.pythonRoot = new PythonTreeRoot(this.project, true, monitor);
}
catch (PyUMLCancelledException e) {
MessageDialog.openWarning(null, "Operation cancelled",
"The Operation was cancelled by the user");
return;
}
catch (PyUMLParseException e) {
MessageDialog.openError(null, "Error parsing project code",
"There was an error parsing the python code of the current\n" +
"project.\n" +
"PyUML can not work as long as there are errors in the project code!\n" +
"Please resolve the error and try again!\n\n" +
"Error message was:\n\n"+
e.getMessage());
return;
}
// ######## Synchronize the Code ############################
monitor.beginTask("Synchronize the Python Code", IProgressMonitor.UNKNOWN);
try {
pythonRoot.synchronizeCode(model, modelXmiDict, xmiModelDictOld, monitor, classCount);
}
catch (PyUMLCancelledException e) {
MessageDialog.openWarning(null, "Operation cancelled",
"The Operation was cancelled by the user");
return;
} catch (Throwable t) {
t.printStackTrace();
MessageDialog.openError(null,"Error synchronizing Code!",
t.getClass().getName() + " while synchronizing Code!: \n\n"
+ t.getMessage());
}
// ##########################################################
// backup model -> copy new current model over old one
try{
JavaHelperMethods.copy(modelToCopy, savedModel);
EclipseHelperMethods.updateFile(savedModel.getAbsolutePath(), this.project);
} catch (IOException ex) {
MessageDialog.openError(null,ex.getMessage(),"Unable to copy model file to: " + umlSavedFileName
+"\nCode creation may not work properly!");
}
monitor.done();
}
/**
* Called by Eclipse. If a project is selected, it is saved
*/
public void selectionChanged(IAction action, ISelection selection) {
if (selection instanceof TreeSelection) {
TreeSelection ts = (TreeSelection) selection;
Object selectedElement = ts.getFirstElement();
if (selectedElement instanceof IProject) {
IProject project = (IProject) selectedElement;
this.project = project;
}
}
}
/**
* Get the used project
* @return
*/
public IProject getProject() {
return project;
}
/**
* Manually set the project to use
* @param project
*/
public void setProject(IProject project) {
this.project = project;
}
/**
* Manually set a PythonTreeRoot to use (if given,
* it will not be created again)
* @param root
*/
public void setRoot(PythonTreeRoot root) {
this.pythonRoot = root;
}
public void run(IProgressMonitor monitor) throws InvocationTargetException,
InterruptedException {
doSync(monitor);
}
}

View File

@ -0,0 +1,24 @@
package pyUML.actions;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IProject;
import pyUML.backend.EclipseHelperMethods;
/**
* An action Handler that calls SyncCodeAction for a user-selected project
*/
public class SyncCodeHandler extends AbstractHandler{
public static IProject selectedProject = null;
@Override
public Object execute(ExecutionEvent arg0) throws ExecutionException {
EclipseHelperMethods.saveAllOpenEditors();
IProject project = EclipseHelperMethods.selectProject();
SyncCodeAction.run(project, null, null);
return null;
}
}

View File

@ -0,0 +1,328 @@
package pyUML.actions;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import org.eclipse.ui.PlatformUI;
import org.eclipse.uml2.uml.Model;
import org.eclipse.uml2.uml.Profile;
import org.eclipse.uml2.uml.ProfileApplication;
import org.eclipse.uml2.uml.internal.impl.UMLFactoryImpl;
import org.eclipse.uml2.uml.resource.UMLResource;
import pyUML.backend.EclipseHelperMethods;
import pyUML.backend.GlobalConstants;
import pyUML.backend.PyUMLProfile;
import pyUML.backend.UMLToolsHelperMethods;
import pyUML.exceptions.PyUMLCancelledException;
import pyUML.exceptions.PyUMLParseException;
import pyUML.listeners.ModelChangeListener;
import pyUML.pythonTree.PythonTreeRoot;
public class SyncModelAction implements IWorkbenchWindowActionDelegate, IRunnableWithProgress{
IProject project = null;
public void dispose() {
// Auto-generated method stub
}
public void init(IWorkbenchWindow window) {
// Auto-generated method stub
}
/**
* Static method to manually run a Model synchronization
* @param project The model to use
*/
public static void runModelSync(IProject project) {
SyncModelAction delegate = new SyncModelAction();
delegate.project = project;
delegate.run((IAction) null);
}
public void run(IAction action) {
ProgressMonitorDialog monitor = new ProgressMonitorDialog(null);
try {
monitor.run(false, true, this);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* The central method - synchronizes the model by the python code
* @param monitor a ProgressMonitor
*/
public void doSync(IProgressMonitor monitor) {
// Ensure a project was given
if (this.project == null) {
return;
}
if (monitor != null) {
monitor.beginTask("Look for existing Model", IProgressMonitor.UNKNOWN);
}
// save all open editors
EclipseHelperMethods.saveAllOpenEditors();
// initialize XMI dictionaries as empty -> they are filled, if a
// model already exists
Map<EObject, String> modelXmiDict = new HashMap<EObject, String>();
Map<String, EObject> xmiModelDict = new HashMap<String, EObject>();
// read project
IPath projectPath = project.getLocation();
// define uml file name
String umlFileName=projectPath.
append(GlobalConstants.getPyUmlDir()).
append(project.getName()+".uml").toOSString();
// look for model file
Model model;
Resource resource;
File modelFile = new File(umlFileName);
if (modelFile.exists()) {
// read Model
EObject diagramRoot = UMLToolsHelperMethods.loadUMLDiagram(umlFileName);
model = (Model) diagramRoot;
resource = model.eResource();
// get model -> xmi-id dictionary
UMLResource r = (UMLResource) resource;
modelXmiDict = r.getEObjectToIDMap();
// create reverse dict, so that xmi_id can be the key
for (EObject modelObject : modelXmiDict.keySet()) {
String xmi_id = modelXmiDict.get(modelObject);
xmiModelDict.put(xmi_id, modelObject);
}
} else {
// Model file does *not* exist ->
// A model has to be created
resource = new ResourceSetImpl().createResource(
URI.createFileURI(umlFileName));
model = UMLFactoryImpl.eINSTANCE.createModel();
model.setName(project.getName());
resource.getContents().add(model);
try {
resource.save(null);
} catch (IOException e) {
e.printStackTrace();
}
// update model in eclipse
EclipseHelperMethods.updateFile(resource.getURI().toFileString(), project);
}
// define profile file name
String profileFileName=projectPath.
append(GlobalConstants.getPyUmlDir()).
append("PyUMLProfile.uml").toOSString();
// look for UML profile file
Profile profile;
Resource profileResource;
File profileFile = new File(profileFileName);
if (! profileFile.exists()) {
IFile profileIFile = EclipseHelperMethods.createFile(profileFile.getPath(), project);
try {
profileIFile.create(null, true, null);
}catch (CoreException e) {
e.printStackTrace();
}
EclipseHelperMethods.StringToIFile(profileIFile, PyUMLProfile.getProfileString());
}
// read and add Profile
EObject profileRoot = UMLToolsHelperMethods.loadUMLDiagram(profileFileName);
profile = (Profile) profileRoot;
if (model.getProfileApplication(profile) == null) {
ProfileApplication profApplication = model.createProfileApplication();
profApplication.setAppliedProfile(profile);
EAnnotation eannot = profApplication.createEAnnotation("http://www.eclipse.org/uml2/2.0.0/UML");
}
// generate PythonTree out of PythonCode
PythonTreeRoot pythonRoot = null;
try {
pythonRoot = new PythonTreeRoot(this.project, true, monitor);
}
catch (PyUMLParseException e) {
MessageDialog.openError(null, "Error parsing project code",
"There was an error parsing the python code of the current\n" +
"project.\n" +
"PyUML can not work as long as there are errors in the project code!\n" +
"Please resolve the error and try again!\n\n" +
"Error message was:\n\n"+
e.getMessage());
return;
}
catch (PyUMLCancelledException e) {
MessageDialog.openWarning(null, "Operation cancelled",
"The Operation was cancelled by the user");
return;
}
catch (Exception e) {
e.printStackTrace();
MessageDialog.openError(null, "Error parsing project code",
"There was an error parsing the python code of the current\n" +
"project.\n" +"Error message was:\n\n"+
e.getMessage());
return;
}
if (monitor != null)
monitor.beginTask("Synchronize the Model with the given Code", IProgressMonitor.UNKNOWN);
// ### Synchronize model with code ###
boolean syncSuccess = false;
String errMsg = null;
boolean normalRun = false;
try {
syncSuccess = pythonRoot.synchronizeModel(model, xmiModelDict);
normalRun=true;
}catch(Exception e) {
e.printStackTrace();
errMsg = e.getClass().getName() + "\n" +e.getMessage();
}
if (!syncSuccess) {
if (! normalRun) {
// if no error happened, but model was not synchronized,
// we assume there already was an adequate message and leave.
// otherwise, we print a generic message and leave afterwards
String message = "There was an error synchronizing the Model.\n";
if (errMsg != null)
message += "The error message was:\n"+errMsg;
MessageDialog.openError(null, "Synchronizing Model Failed", message);
}
return;
}
// save new or changed model to .uml file,
// if synchronization was successful
if (syncSuccess) try {
resource.save(null);
// update model in eclipse
EclipseHelperMethods.updateFile(resource.getURI().toFileString(), project);
System.out.println(("Saving model file done."));
} catch (IOException ioe) {
MessageDialog.openError(null,"IOException",
"Error saving uml file: \n" + ioe.getMessage());
}
// Synchronize Code
if (syncSuccess) {
try{
// after creating the model, synchronize the code
// so that all model xmi_ids will be part of the code
// re-use existing pythonRoot, so that code will not have
// to be read-in again.
SyncCodeAction.run(project, pythonRoot, monitor);
}catch (Throwable t) {
MessageDialog.openError(null,"Error synchronizing Code!",
t.getClass().getName() + " while synchronizing Code!: \n\n"
+ t.getMessage());
t.printStackTrace();
}
}
monitor.beginTask("Update UML diagram", IProgressMonitor.UNKNOWN);
// if model diagram does not exist, create it!
// create graphical diagram, if it does not already exist
// after creation, open it; if it is opened, refresh view.
IFile diagramFile = this.project.getWorkspace()
.getRoot().getFile(this.project.getFullPath()
.append(GlobalConstants.getPyUmlDir())
.append(project.getName()+GlobalConstants
.getDiagramExtension()));
if (! diagramFile.exists()) {
UMLToolsHelperMethods.createModelDiagram(model, diagramFile);
}else {
}
monitor.beginTask("Open UML diagram", IProgressMonitor.UNKNOWN);
// after creating model, be sure the diagram view is reloaded
boolean diagramOpened = null != EclipseHelperMethods
.firstOpenEditorByName(project.getName()+GlobalConstants.getDiagramExtension());
if (diagramOpened) {
// set focus to updated diagram only if no diagram is currently active
boolean keepFocus = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getActivePage().getActiveEditor().getTitle()
.matches(".*"+GlobalConstants.getDiagramExtension());
// close all sub-package pyUML.views of global model diagram
for ( IEditorReference editor :
EclipseHelperMethods.lookForOpenEditorByName(project.getName()+"::.*")) {
PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getActivePage().closeEditor(editor.getEditor(true), true);
}
IEditorPart modelEditor = UMLToolsHelperMethods.refreshDiagramEditor(project, diagramFile, keepFocus);
modelEditor.addPropertyListener(new ModelChangeListener(project));
}
else {
IEditorPart modelEditor = UMLToolsHelperMethods.openDiagram(project, diagramFile, project.getName()+".uml", true);
modelEditor.addPropertyListener(new ModelChangeListener(project));
}
UMLToolsHelperMethods.updateModelAndViewPages(this.project);
monitor.done();
}
public void selectionChanged(IAction action, ISelection selection) {
if (selection instanceof TreeSelection) {
TreeSelection ts = (TreeSelection) selection;
Object selectedElement = ts.getFirstElement();
this.project = (IProject) selectedElement;
}
}
public void run(IProgressMonitor monitor) throws InvocationTargetException,
InterruptedException {
monitor.setTaskName("Starting Model Synchronization");
this.doSync(monitor);
}
}

View File

@ -0,0 +1,27 @@
package pyUML.actions;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IProject;
import pyUML.backend.EclipseHelperMethods;
/**
* An action Handler that calls SyncModelAction for a user-selected project
*/
public class SyncModelHandler extends AbstractHandler{
public static IProject selectedProject = null;
@Override
public Object execute(ExecutionEvent arg0) throws ExecutionException {
EclipseHelperMethods.saveAllOpenEditors();
IProject project = EclipseHelperMethods.selectProject();
SyncModelAction.runModelSync(project);
return null;
}
}

View File

@ -0,0 +1,126 @@
package pyUML.backend;
import java.util.Vector;
import org.eclipse.core.resources.IProject;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Shell;
/**
* This is a SWT dialog the lets the user choose one of
* the given projects.
* By the next run, the lately selected project in preselected
*/
public class ChooseProjectDialog extends Dialog{
public static IProject preSelectedProject = null;
private java.util.List<IProject> projects;
private List selectProjectBox;
private IProject selectedProject = null;
private java.util.List<String> projectsList;
public ChooseProjectDialog(Shell parent, java.util.List<IProject> projects) {
super(parent);
this.projects = projects;
}
/**
* Initializes a ChooseProjectDialog and lets the user choose
* one of the given projects.
* After "Use" or "Cancel" is pressed, the selected
* Project is returned, or null if cancel was pressed.
* @param parent
* @param projects
* @return
*/
public static IProject runChooseProject(Shell parent, java.util.List<IProject> projects) {
if (preSelectedProject != null && (! preSelectedProject.isOpen()))
preSelectedProject = null;
// Create dialog
ChooseProjectDialog dialog = new ChooseProjectDialog(parent, projects);
dialog.create();
// Pre-select project that was selected before
if (ChooseProjectDialog.preSelectedProject != null) {
String preSelectedProjectName = ChooseProjectDialog.preSelectedProject.getName();
if (dialog.getProjectsList().contains(preSelectedProjectName)) {
int index = dialog.getProjectsList().indexOf(preSelectedProjectName);
dialog.selectProjectBox.setSelection(index);
}
}
dialog.open();
ChooseProjectDialog.preSelectedProject = dialog.selectedProject;
return dialog.selectedProject;
}
protected Control createDialogArea(Composite parent) {
Composite composite = (Composite) super.createDialogArea(parent);
setShellStyle(SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MAX);
createControls(composite);
//add controls to composite as necessary
return composite;
}
public void createControls (Composite composite) {
// create graphical components
Shell shell = composite.getShell();
shell.setText("Select Python Project To Use");
Group selectBoxGroup = new Group(composite, SWT.None);
selectBoxGroup.setText("Please select a project to be used by PyUML:");
selectBoxGroup.setLayoutData(new GridData(GridData.FILL_BOTH));
selectBoxGroup.setLayout(new GridLayout(1, true));
this.selectProjectBox = new List( selectBoxGroup, SWT.BORDER|SWT.SINGLE|SWT.V_SCROLL|SWT.H_SCROLL );
selectProjectBox.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
this.projectsList = new Vector<String>();
for (IProject project : this.projects) {
this.selectProjectBox.add(project.getName());
projectsList.add(project.getName());
}
selectProjectBox.setSize(300,300);
//buttonGroup.pack();
selectBoxGroup.pack();
composite.pack();
}
public void widgetDefaultSelected(SelectionEvent e) {
// Not needed in this dialog
}
protected void buttonPressed(int buttonId) {
if (IDialogConstants.OK_ID == buttonId) {
int selectedIndex = this.selectProjectBox.getSelectionIndex();
if (selectedIndex < 0)
return;
this.selectedProject = this.projects.get(selectedIndex);
this.close();
} else if (IDialogConstants.CANCEL_ID == buttonId) {
cancelPressed();
}
}
public java.util.List<String> getProjectsList() {
return projectsList;
}
}

View File

@ -0,0 +1,296 @@
package pyUML.backend;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;
import org.python.pydev.plugin.nature.PythonNature;
/**
* Some Helper methods for Eclipse-specific tasks
*/
public class EclipseHelperMethods {
/**
* Closes an open Editor, if it is already opened
* @param project the current project
* @param editorName the Name of the editor to close (or a REGEX)
* @return true, if an editor was closed, false, if nothing was done
*/
public static boolean closeEditorByName(IProject project, String editorName){
IEditorReference editor = firstOpenEditorByName(editorName);
if (editor == null)
return false;
IWorkbenchPage page =
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
return page.closeEditor(editor.getEditor(true), true);
}
/**
* Looks for an open editor with a name that matches the given regex.
* Returns a list of matching editors or an empty list, if no such editor is open.
* @param editorNameRegex
* @return
*/
public static List<IEditorReference> lookForOpenEditorByName(String editorNameRegex) {
IWorkbenchPage page =
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
List<IEditorReference> editorList = new Vector<IEditorReference>();
for (IEditorReference editor : page.getEditorReferences()) {
if (editor.getTitle().matches(editorNameRegex)) {
editorList.add(editor);
}
}
return editorList;
}
/**
* Looks for an open editor with a name that matches the given regex.
* Returns the first matching editors or null, if no such editor is open.
* @param editorNameRegex
* @return
*/
public static IEditorReference firstOpenEditorByName(String editorNameRegex) {
List<IEditorReference> editorList = lookForOpenEditorByName(editorNameRegex);
if (editorList.size() == 0)
return null;
else
return editorList.get(0);
}
/**
* Reads the content of an IFile and returns teh String of the content
* @param file the IFile to read
* @return The file content String, null on error
*/
public static String iFileToString(IFile file){
String fileContents = "";
try{
BufferedReader reader = new BufferedReader(new InputStreamReader(file.getContents()));
String line;
while ((line = reader.readLine()) != null) {
fileContents+= line+"\n";
}
return fileContents;
}
catch (IOException e) {
MessageDialog.openError(null, "Error Reading File",
"Cannot Read file "+file+"\nReason:\n"+e.getMessage());
}
catch (CoreException e) {
MessageDialog.openError(null, "Error Reading File",
"Cannot Read file "+file+"\nReason:\n"+e.getMessage());
}
return null;
}
/**
* Writes a string to an IFile. The old file content is replaced completely.
*
* @param file the IFile to update
* @param s the string to write to the file
* @return true on success, false otherwise
*/
public static boolean StringToIFile(IFile file, String s) {
try{
file.setContents(JavaHelperMethods.stringToStream(s),
IResource.FORCE, null);
EclipseHelperMethods.updateFile(file);
return true;
} catch (CoreException err) {
MessageDialog.openError(null, "Error writing file", err.getMessage());
}
return false;
}
/**
* marks the ressource as updated in eclipse
* @param file the changed IFile
*/
public static void updateFile(IFile file) {
try {
file.refreshLocal(1, null);
} catch (CoreException e) {
System.out.println("Error updating ressource "+file.getName());
}
}
/**
* marks the resource as updated in eclipse
* @param path the full path of the changed file
*/
public static void updateFile(String path, IProject project) {
try {
IFile file = createFile(path, project);
file.refreshLocal(1, null);
} catch (CoreException e) {
System.out.println("Error updating ressource "+path);
e.printStackTrace();
}
}
/**
* marks the folder as updated in eclipse
* @param path the full path of the changed file
*/
public static void updateFolder(String path, IProject project) {
try {
IFolder file = createFolder(path, project);
file.refreshLocal(IResource.DEPTH_INFINITE, null);
} catch (CoreException e) {
System.out.println("Error updating folder "+path);
e.printStackTrace();
}
}
/**
* creates an IFile resource out of an absolute Path and a project
* (the file is not created on the file system, only an IFile Object
* with appropriate path is created)
*/
public static IFile createFile(String path, IProject project) {
// cut everything in front of project name
String localPath = path.replace(project.getLocation().toOSString(), "");
IPath relativeFilePath = project.getFullPath().append(localPath);
return project.getWorkspace().getRoot().getFile(relativeFilePath);
}
/**
* creates an IFolder resource out of an absolute Path and a project
* (the folder is not created on the file system, only an IFolder Object
* with appropriate path is created)
*/
public static IFolder createFolder(String path, IProject project) {
// cut everything in front of project name
String localPath = path.replace(project.getLocation().toOSString(), "");
IPath relativeFilePath = project.getFullPath().append(localPath);
return project.getWorkspace().getRoot().getFolder(relativeFilePath);
}
/**
* Saves all Editors opened in the Workbench.
*/
public static void saveAllOpenEditors() {
// save all open editors
// (this may fail if the process is forked)
// (-> catch NullpointerException and do not save, then)
try {
IWorkbenchPage page =
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
page.saveAllEditors(false);
} catch (NullPointerException e) {}
}
public static boolean isPythonProject(IProject project) {
PythonNature store = new PythonNature();
store.setProject(project);
try {
store.getPythonPathNature().getProjectSourcePathSet(false);
} catch (CoreException e) {
return false;
}
catch (NullPointerException e) {
return false;
}
catch (Exception e) {
e.printStackTrace();
}
return true;
}
/**
* Finds the source folder(s) of this python project.
* If an error occurs (e.g. the project is no python
* project), the project location is returned.
* Source folders contained in other source folders are
* removed from list.
*
* @param project
* @return
*/
public static Set<IPath> getPythonSrcDirs(IProject project) {
PythonNature store = new PythonNature();
store.setProject(project);
Set<IPath> srcPaths = new HashSet<IPath>();
Set<String> srcStrings = null;
try {
srcStrings = store.getPythonPathNature().getProjectSourcePathSet(true);
}
catch (CoreException e) {
srcPaths.add(project.getLocation());
return srcPaths;
}
catch (Exception e) {
e.printStackTrace();
}
srcDirLoop:
for (String dirString : srcStrings) {
// continue, if this dir is already contained in any other dir
for (String dirString2 : srcStrings) {
if (dirString != dirString2 && dirString2.startsWith(dirString))
continue srcDirLoop;
}
IPath srcPath = new Path(dirString);
IPath srcDir = srcPath.removeFirstSegments(1); //remove project dir
IPath completeSrcPath = project.getLocation().append(srcDir);
srcPaths.add(completeSrcPath);
}
return srcPaths;
}
/**
* This method chooses from the list of available Projects
* in the Workspace the project to work with, which is
* -> a python project
* -> if there are several, the user us asked which one to use
* -> if there is no project selected, the user asked to select one
*
* @return the pyDev project that was selected
* null, if no project could be chosen
*/
public static IProject selectProject() {
IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
List<IProject> pyDevProjects = new Vector<IProject>();
// find all pyDev-Projects
for (IProject project : projects) {
if (project.isOpen() && isPythonProject(project))
pyDevProjects.add(project);
}
if (pyDevProjects.size() == 0)
return null;
if (pyDevProjects.size() == 1)
return (pyDevProjects.get(0));
// let user choose the project to use
return ChooseProjectDialog.runChooseProject((Shell) null, pyDevProjects);
}
}

View File

@ -0,0 +1,51 @@
package pyUML.backend;
import java.util.Arrays;
import java.util.List;
/**
*
* This class holds global parameters used by different classes
* of PyUML
*
*/
public class GlobalConstants {
private final static String pyUmlDir="PyUML";
private final static String viewUmlExtension = ".pyUmlView.uml";
private final static String viewConfExtension = ".pyUmlViewConfig";
private final static String diagramExtension = ".umlclass_diagram";
private final static String unknownExpression = "\"??unknown??\"";
private final static String fullDefault = "PyUML:FullDefault:";
public final static String STEREOTYPE_BEANCLASS = "BeanClass";
private final static String[] possibleStereotypes = {GlobalConstants.STEREOTYPE_BEANCLASS};
public static String getViewUmlExtension() {
return viewUmlExtension;
}
public static String getPyUmlDir() {
return pyUmlDir;
}
public static String getViewConfExtension() {
return viewConfExtension;
}
public static String getDiagramExtension() {
return diagramExtension;
}
public static String getUnknownExpression() {
return unknownExpression;
}
public static String getFullDefault() {
return fullDefault;
}
public static List<String> getPossibleStereoTypes() {
return Arrays.asList(possibleStereotypes);
}
}

View File

@ -0,0 +1,84 @@
package pyUML.backend;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* some helper methods for common java problems, i.e. file copying
*/
public class JavaHelperMethods {
/**
* Fast & simple file copy.
* copies source file to destination file
*/
public static void copy(File source, File dest) throws IOException {
InputStream in = new FileInputStream(source);
OutputStream out = new FileOutputStream(dest);
final int bufferSize = 4096;
try {
byte[] buffer = new byte[bufferSize];
int bytesRead;
while ((bytesRead = in.read(buffer)) >= 0) {
out.write(buffer, 0, bytesRead);
}
} finally {
out.close();
in.close();
}
}
public static InputStream stringToStream(String s) {
return new ByteArrayInputStream(s.getBytes());
}
/**
* Joins an Array of Strings to one big String separated by
* a separator
* @param array The String array to join
* @param separator The separator
* @return the joined String
*/
public static String join(String[] array, String separator) {
if (array==null) return "";
StringBuffer sb = new StringBuffer(array[0]);
for(int i=1; i<array.length; i++) {
sb.append(separator + array[i]);
}
return sb.toString();
}
/**
* Returns the number of files present in a directory-tree
* matching the given regex.
* This can be used to count the packages (__init__.py)
* for progress monitoring.
* @param parentDir The directory to start with
* @param regex The regex to match
* @return the Number of occurrence of the file in the dir tree
*/
public static int getFileCount(File parentDir, String regex)
{
File[] filesAndDirs = parentDir.listFiles();
int count=0;
for( File file: filesAndDirs )
{
if( file.getName().matches(regex))
{
count ++;
}
if (file.isDirectory())
{
count += getFileCount(file, regex);
}
}
return count;
}
}

View File

@ -0,0 +1,194 @@
package pyUML.backend;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Model;
import org.python.pydev.parser.jython.ast.Name;
import org.python.pydev.parser.jython.ast.Num;
import org.python.pydev.parser.jython.ast.Str;
import org.python.pydev.parser.jython.ast.exprType;
import pyUML.pythonTree.PythonTreeFile;
import pyUML.pythonTree.PythonTreePackage;
import pyUML.pythonTree.PythonTreeRoot;
/**
* Some Helper methods needed for parsing Pything Code
* and handling the Python Abstract Syntax Tree
*/
public class ParseHelpers {
/**
* Reads out a file and returns the file content as a string
*
* @param file the file to read
* @return a String representing the file's content
* null on Error
*/
public static String fileToString(File file, IProject project) {
IFile iFile = EclipseHelperMethods.createFile(file.getAbsolutePath(), project);
return EclipseHelperMethods.iFileToString(iFile);
}
/**
* (Re-)Writes a string to a file and updates the file in the project,
* if the project is != null
* @param file the file to write to
* @param str the String to write to the File
* @param project (optional) the project where the file is located in
*/
public static void stringToFile(File file, String str, IProject project) {
try {
file.createNewFile();
BufferedWriter writer = new BufferedWriter(new FileWriter(file));
writer.write(str);
writer.close();
EclipseHelperMethods.updateFile(file.getAbsolutePath(), project);
}catch (IOException e) {
MessageDialog.openError(null, "IOException",
"Error writing to file "+ file.getPath());
e.printStackTrace();
}
}
/**
* Extracts a String representation of a python expression,
* if the expression is of type String or Num.
* The quotes of Strings are preserved
*
* @param expr The Python AST expression
* @param fileContent the content of the file where the expression
* is to be read
* @param attribute if true, expressions other than Strings or numbers are
* read by just reading the pure file content to the end of the line
* (or to a # sign). This works ONLY for attributes, not for expressions in
* function definitions.
* @param abbreviate if true, long values are abbreviated; at the end "(...)"
* is appended
* @param ONLY if this reads an attribute value: the value of the next line
* (needed to read multi-line attributes)
* if this is no attribute, this value is ignored.
*
* @return The String representation of this expression, null if expr is null
*/
public static String getStringOfExpr(exprType expr, PythonTreeFile pyFile, boolean attribute, boolean abbreviate, int nextLine){
if (expr == null)
return null;
String exprString;
if (expr instanceof Str) {
Str defaultValStr = (Str) expr;
exprString = defaultValStr.s;
if (defaultValStr.type == Str.SingleDouble) {
exprString = "\"" + exprString + "\"";
}
else if (defaultValStr.type == Str.SingleSingle) {
exprString = "'" + exprString + "'";
}
} else if (expr instanceof Name) {
Name defaultValNum = (Name) expr;
exprString = defaultValNum.id;
} else if (expr instanceof Num) {
Num defaultValNum = (Num) expr;
exprString = defaultValNum.num;
} else if (attribute){
exprString = readExprAsText(expr, pyFile, nextLine);
} else {
return GlobalConstants.getUnknownExpression();
}
// cut default value, if it is too long
if (abbreviate && exprString.length() > 19) {
exprString = exprString.substring(0,14) + "(...)";
}
return exprString;
}
/**
* Helper method for getStringOfExpr()
* Can read a multi-line-expression of an attribute
*
* @param expr
* @param pyFile
* @param nextLine
* @return
*/
public static String readExprAsText(exprType expr, PythonTreeFile pyFile, int nextLine) {
String[] lines = pyFile.getSplittedFileContent();
String exprString = lines[expr.beginLine-1];
exprString = exprString.substring(exprString.indexOf("=")+1);
exprString = exprString.replaceAll("^[\\s]*","");
exprString = exprString.replaceAll(" # created by PyUML.*$", "");
exprString = exprString.replaceAll("[\\s]*$", "");
for (int i=expr.beginLine; i < nextLine - 1; i++) {
String line = lines[i];
// docString comments of static attributes have a wrong "beginLine" value
// -> manually define here to ignore docStrings!
if (line.matches("^[\\s]*\"\"\".*"))
break;
line = line.replaceAll("# created by PyUML.*$", "");
line = " " +line.replaceAll("^[\\s]*", "");
exprString += line;
exprString = exprString.replaceAll("[\\s]*$", "");
}
// if there are called other classes/packages, the index
// is on the value, not on the "a.b.c"-prefix.
// if that's the case, add the prefix afterwards:
return exprString;
}
/**
* Simple method to extract the XMI-ID out of a line
* containing the PyUML string "# PyUML: XMI_ID: ..."
* @param content
* @return
*/
public static String extractXmiFromString(String content) {
String xmi_id = null;
String[] lines = content.split("\n");
for (String line : lines) {
if (line.matches("\\s*# PyUML:.*")) {
String[] splittedLine = line.split("XMI_ID:");
if (splittedLine.length == 2) {
xmi_id = splittedLine[1];
}
}
}
return xmi_id;
}
/**
* This creates a string containing the model package structure as
* "/packSup/packSub/" , where the last package contains the
* current class.
* @param cl The class in the model to find the package structure for
* @return a string containing the parent package structure
* of this class
*
*/
public static String getModelPackageStructure(org.eclipse.uml2.uml.Type cl) {
org.eclipse.uml2.uml.Package pack = cl.getPackage();
String structure = "";
while (! (pack instanceof Model))
{
structure = "/"+pack.getName() + structure ;
pack = pack.getNestingPackage();
}
return structure + "/";
}
}

View File

@ -0,0 +1,59 @@
package pyUML.backend;
public class PyUMLProfile {
/**
* @return the pyUML XMLProfile as a string;
* the hard-coded profile String can be replaces by a method
* loading a profile UML file
*/
public static String getProfileString() {
return profileString;
}
private static String profileString =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<uml:Profile xmi:version=\"2.1\" xmlns:xmi=\"http://schema.omg.org/spec/XMI/2.1\" xmlns:ecore=\"http://www.eclipse.org/emf/2002/Ecore\" xmlns:uml=\"http://www.eclipse.org/uml2/2.1.0/UML\" xmi:id=\"_7Y-UAKi8Edyr_pXRyLU3wA\" name=\"PyUMLProfile\" metaclassReference=\"_ZtOxIKjHEdym48zZ96s2nA\" metamodelReference=\"_bkzWwKjHEdym48zZ96s2nA\">\n" +
" <eAnnotations xmi:id=\"_oyijYKjHEdym48zZ96s2nA\" source=\"http://www.eclipse.org/uml2/2.0.0/UML\">\n" +
" <contents xmi:type=\"ecore:EPackage\" xmi:id=\"_bm4k8KjIEdym48zZ96s2nA\" name=\"PyUMLProfile\" nsURI=\"http:///schemas/PyUMLProfile/_bm06kKjIEdym48zZ96s2nA/1\" nsPrefix=\"PyUMLProfile\">\n" +
" <eClassifiers xmi:type=\"ecore:EClass\" xmi:id=\"_bm4k8ajIEdym48zZ96s2nA\" name=\"BeanClass\">\n" +
" <eAnnotations xmi:id=\"_bm4k8qjIEdym48zZ96s2nA\" source=\"http://www.eclipse.org/uml2/2.0.0/UML\" references=\"_e8aLwKjHEdym48zZ96s2nA\"/>\n" +
" <eAnnotations xmi:id=\"_bm4k86jIEdym48zZ96s2nA\" source=\"duplicates\">\n" +
" <contents xmi:type=\"ecore:EReference\" xmi:id=\"_bm4k9KjIEdym48zZ96s2nA\" name=\"base_Class\" ordered=\"false\" lowerBound=\"1\">\n" +
" <eAnnotations xmi:id=\"_bm4k9ajIEdym48zZ96s2nA\" source=\"redefines\" references=\"_bm4k-ajIEdym48zZ96s2nA\"/>\n" +
" <eType xmi:type=\"ecore:EClass\" href=\"http://www.eclipse.org/uml2/2.1.0/UML#//Class\"/>\n" +
" </contents>\n" +
" </eAnnotations>\n" +
" <eStructuralFeatures xmi:type=\"ecore:EAttribute\" xmi:id=\"_bm4k96jIEdym48zZ96s2nA\" name=\"TestProperty\" ordered=\"false\" lowerBound=\"1\">\n" +
" <eType xmi:type=\"ecore:EDataType\" href=\"http://www.eclipse.org/emf/2002/Ecore#//EString\"/>\n" +
" </eStructuralFeatures>\n" +
" <eStructuralFeatures xmi:type=\"ecore:EReference\" xmi:id=\"_bm4k-ajIEdym48zZ96s2nA\" name=\"base_Class\" ordered=\"false\" lowerBound=\"1\">\n" +
" <eType xmi:type=\"ecore:EClass\" href=\"http://www.eclipse.org/uml2/2.1.0/UML#//Class\"/>\n" +
" </eStructuralFeatures>\n" +
" </eClassifiers>\n" +
" </contents>\n" +
" <contents xmi:type=\"ecore:EPackage\" xmi:id=\"_oyjKcKjHEdym48zZ96s2nA\" name=\"PyUMLProfile\" nsURI=\"http:///schemas/PyUMLProfile/_oyfgEKjHEdym48zZ96s2nA/0\" nsPrefix=\"PyUMLProfile\">\n" +
" <eClassifiers xmi:type=\"ecore:EClass\" xmi:id=\"_oyjKcajHEdym48zZ96s2nA\" name=\"BeanClass\">\n" +
" <eAnnotations xmi:id=\"_oyjKcqjHEdym48zZ96s2nA\" source=\"http://www.eclipse.org/uml2/2.0.0/UML\" references=\"_e8aLwKjHEdym48zZ96s2nA\"/>\n" +
" </eClassifiers>\n" +
" </contents>\n" +
" </eAnnotations>\n" +
" <elementImport xmi:id=\"_ZtOxIKjHEdym48zZ96s2nA\">\n" +
" <importedElement xmi:type=\"uml:Class\" href=\"pathmap://UML_METAMODELS/UML.metamodel.uml#Class\"/>\n" +
" </elementImport>\n" +
" <packageImport xmi:id=\"_bkzWwKjHEdym48zZ96s2nA\">\n" +
" <importedPackage xmi:type=\"uml:Model\" href=\"pathmap://UML_METAMODELS/UML.metamodel.uml#_0\"/>\n" +
" </packageImport>\n" +
" <packagedElement xmi:type=\"uml:Stereotype\" xmi:id=\"_e8aLwKjHEdym48zZ96s2nA\" name=\"BeanClass\">\n" +
" <ownedAttribute xmi:id=\"_OAXE4KjIEdym48zZ96s2nA\" name=\"base_Class\">\n" +
" <type xmi:type=\"uml:Class\" href=\"pathmap://UML_METAMODELS/UML.metamodel.uml#Class\"/>\n" +
" </ownedAttribute>\n" +
" <ownedAttribute xmi:id=\"_S_NkgKjIEdym48zZ96s2nA\" name=\"base_Class\" association=\"_S_MWYKjIEdym48zZ96s2nA\">\n" +
" <type xmi:type=\"uml:Class\" href=\"pathmap://UML_METAMODELS/UML.metamodel.uml#Class\"/>\n" +
" </ownedAttribute>\n" +
" </packagedElement>\n" +
" <packagedElement xmi:type=\"uml:Extension\" xmi:id=\"_S_MWYKjIEdym48zZ96s2nA\" name=\"Class_BeanClass\" memberEnd=\"_S_M9cKjIEdym48zZ96s2nA _S_NkgKjIEdym48zZ96s2nA\">\n" +
" <ownedEnd xmi:type=\"uml:ExtensionEnd\" xmi:id=\"_S_M9cKjIEdym48zZ96s2nA\" name=\"extension_BeanClass\" type=\"_e8aLwKjHEdym48zZ96s2nA\" aggregation=\"composite\" association=\"_S_MWYKjIEdym48zZ96s2nA\"/>\n" +
" </packagedElement>\n" +
"</uml:Profile>\n" ;
}

View File

@ -0,0 +1,311 @@
package pyUML.backend;
import java.io.IOException;
import java.util.List;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.commands.operations.OperationHistoryFactory;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.gmf.runtime.common.core.command.CommandResult;
import org.eclipse.gmf.runtime.diagram.core.services.ViewService;
import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand;
import org.eclipse.gmf.runtime.emf.core.GMFEditingDomainFactory;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;
import org.eclipse.uml2.diagram.clazz.edit.parts.PackageEditPart;
import org.eclipse.uml2.diagram.clazz.part.Messages;
import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditor;
import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditorPlugin;
import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditorUtil;
import org.eclipse.uml2.diagram.clazz.part.UMLVisualIDRegistry;
import pyUML.listeners.LiveValidationListener;
import pyUML.listeners.ViewChangeListener;
import pyUML.views.EditView;
import pyUML.views.EditViewWizard;
/**
* This class contains methods for reading and writing eclipse
* UML models and for model handling
*/
public class UMLToolsHelperMethods {
/**
* Loads an eclipse UML2 model
*
* @param umlFileName a String containing the filename of the eclipse uml2 diagram
* @return the model root as EObject, null if an exception occured
*/
public static EObject loadUMLDiagram(String umlFileName) {
try {
Resource resource = new ResourceSetImpl().getResource(URI.createFileURI(umlFileName), true);
return resource.getContents().get(0);
/*for (EObject content : resource.getContents()) {
if (content instanceof Model)
return content;
}*/
//return null;
} catch (WrappedException ex) {
MessageDialog.openError(null,ex.getMessage(),"Unable to load model: " + umlFileName+"\n"+ex.getMessage());
return null;
}
}
/**
* opens a eclipse uml2tools UML diagram in the editor
* Will edit the diagram file, if a wrong path to a UML model is set
* (Unfortunately, UML diagrams save absolute paths of the corresponding
* UML file)
* @param project the current project
* @param diagramFile the fileName in the pyUml directory
* @param putToFront if the editor is already opened, with putToFront==true
* the editor is given the focus, with putToFront==false nothing is done
* @param umlModelName The name of the corresponding UML model to this model
* This is needed to ensure the diagram has a correct UML file path set
* @return the IEitorPat of the newly opened Diagram, null on Error
* @throws PartInitException
*/
public static IEditorPart openDiagram(IProject project, IFile diagramFile, String umlModelFileName, boolean putToFront) {
// see, if UML model path is set correctly
String absoluteUmlPath = project.getLocation().append(GlobalConstants.getPyUmlDir())
.append(umlModelFileName).toOSString();
String[] diagramFileContent = EclipseHelperMethods.iFileToString(diagramFile).split("\n");
for (int i =0; i< diagramFileContent.length; i++) {
String line = diagramFileContent[i];
Pattern pattern = Pattern.compile("(\\s*<element\\s*xmi:type=\"uml:Model\" href=\"file:)([^#]*)(#.*)");
Matcher matcher = pattern.matcher(line);
if (matcher.find()) {
line = matcher.group(1) + absoluteUmlPath + matcher.group(3);
if (! diagramFileContent[i].equals(line)) {
diagramFileContent[i] = line;
EclipseHelperMethods.StringToIFile(diagramFile,
JavaHelperMethods.join(diagramFileContent, "\n"));
}
break;
}
}
IWorkbenchPage page =
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
// if putToFront == false, return if editor is already opened
if (putToFront == false)
for (IEditorReference editor : page.getEditorReferences())
if (editor.getTitle().equals(diagramFile.getName()))
return editor.getEditor(false);
try{
IEditorPart ed = IDE.openEditor(page, diagramFile, UMLDiagramEditor.ID, false);
if (! diagramFile.toString().matches(".*"+project.getName()+GlobalConstants.getDiagramExtension())) {
ed.addPropertyListener(new ViewChangeListener(project));
}
ed.addPropertyListener(LiveValidationListener.getListenerSingleton());
LiveValidationListener.startLiveValidationInBackground();
/*
UMLDiagramEditor umlEd = (UMLDiagramEditor) ed;
umlEd.getDiagram().eResource().load(JavaHelperMethods.stringToStream(PyUMLProfile.getProfileString()), null);
umlEd.refresh();*/
return ed;
} catch (PartInitException e) {
e.printStackTrace();
} catch (Throwable t) {
t.printStackTrace();
}
return null;
}
/**
* Updates an opened Diagram, if it is already opened
* @param project the current project
* @param diagramFile the IFile of the diagram to refresh
* @param keepFocus if true, workbench focus (currently opened document) is kept open.
* @return true, if a diagram was found and updated
*/
public static IEditorPart refreshDiagramEditor(IProject project, IFile diagramFile, boolean keepFocus){
IWorkbenchPage page =
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
// save active Editor to keep focus
IEditorPart activeEditor = page.getActiveEditor();
//activeEditor.getEditorSite().getId();
String activeEditorName = null;
if (activeEditor != null)
activeEditorName = activeEditor.getTitle();
// look for editor to update
IEditorReference editor = EclipseHelperMethods.firstOpenEditorByName(diagramFile.getName());
if (editor == null)
return null;
// close and open editor again
page.closeEditor(editor.getEditor(true), true);
try{
IEditorPart newEditor = IDE.openEditor(page, diagramFile, UMLDiagramEditor.ID, true);
if (! diagramFile.toString().matches(".*"+project.getName()+GlobalConstants.getDiagramExtension())) {
newEditor.addPropertyListener(new ViewChangeListener(project));
}
EclipseHelperMethods.saveAllOpenEditors();
// activate old active editor
if (keepFocus && activeEditor != null && (! newEditor.getTitle().equals(activeEditorName)))
page.activate(activeEditor);
return newEditor;
} catch (PartInitException e) {
e.printStackTrace();
return null;
}
catch (Throwable t) {
t.printStackTrace();
}
return null;
}
/**
* creates a graphical eclipse UML2TOOLS UML model diagram out of
* a Eclipse UML2 File.
*/
public static void createModelDiagram(EObject modelObject, IFile newDiagramFile) {
org.eclipse.emf.transaction.TransactionalEditingDomain editingDomain =
GMFEditingDomainFactory.INSTANCE.createEditingDomain();
List<IFile> affectedFiles = new Vector<IFile>();
final org.eclipse.uml2.uml.Package model
= (org.eclipse.uml2.uml.Package) modelObject;
URI diagramModelURI = URI.createPlatformResourceURI(newDiagramFile.getFullPath().toString(), true);
ResourceSet resourceSet = editingDomain.getResourceSet();
final Resource diagramResource = resourceSet.createResource(diagramModelURI);
affectedFiles.add(newDiagramFile);
// create diagram from model
AbstractTransactionalCommand command = new AbstractTransactionalCommand(editingDomain, Messages.UMLNewDiagramFileWizard_InitDiagramCommand, affectedFiles) {
public CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) {
int diagramVID = UMLVisualIDRegistry.getDiagramVisualID(model);
if (diagramVID != PackageEditPart.VISUAL_ID) {
return CommandResult.newErrorCommandResult(Messages.UMLNewDiagramFileWizard_IncorrectRootError);
}
Diagram diagram = ViewService.createDiagram(model, PackageEditPart.MODEL_ID, UMLDiagramEditorPlugin.DIAGRAM_PREFERENCES_HINT);
diagramResource.getContents().add(diagram);
return CommandResult.newOKCommandResult();
}
};
// save the created diagram file
try {
OperationHistoryFactory.getOperationHistory().execute(command, new NullProgressMonitor(), null);
diagramResource.save(UMLDiagramEditorUtil.getSaveOptions());
} catch (org.eclipse.core.commands.ExecutionException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
// change full path file name to relative path
String diagramFileContent = EclipseHelperMethods.iFileToString(newDiagramFile);//.split("\n");
Pattern pattern = Pattern.compile( "(.*<element xmi:type=\"uml:Model\" href=\")file:([^#]*)(.*)");
Matcher matcher = pattern.matcher(diagramFileContent);
if (! matcher.find()){
return;
}
// write the new method definition line
String newDiagramLine = matcher.group(1) + model.getName()+".uml" + matcher.group(3);
// replace line
String newDiagramFileContent = "";
String[] fileContentLines = diagramFileContent.split("\n");
for (int i=0; i<fileContentLines.length; i++) {
if (fileContentLines[i].equals(matcher.group(0)))
newDiagramFileContent += newDiagramLine + "\n";
else
newDiagramFileContent += fileContentLines[i] + "\n";
}
EclipseHelperMethods.StringToIFile(newDiagramFile, newDiagramFileContent);
}
/**
* As a UML diagram is not updated automatically, when .uml file changed,
* we need to manually reload the diagram
* @param project
* @param exceptViewName A name of a view to be excluded from refresh.
* This is useful if a view change is the source of the refreshes.
* Can be null.
* @param onlyIfViewsNotLocked if false, the update will be done any time.
* if false, it will be only done if views are not locked.
*/
public static void updateModelAndViewPages(IProject project) {
// refresh all pyUML.views
IFolder pyUmlDir = project.getFolder(GlobalConstants.getPyUmlDir());
// keep active editor name to activate it afterwards
String activeEditorName = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getActivePage().getActiveEditor().getTitle();
try {
for (IResource entry :pyUmlDir.members()) {
if (entry instanceof IFile) {
IFile file = (IFile) entry;
if (file.getName().matches("^.*"+GlobalConstants.getViewConfExtension()+"$")) {
String viewDiagramName = updateViewModel(project, file);
refreshDiagramEditor(project,
project.getFile(new org.eclipse.core.runtime.Path(GlobalConstants.getPyUmlDir()).append(viewDiagramName).toOSString())
, true);
}
}
}
// set focus to formerly opened editor page
IEditorReference formerlyOpenedEditor = EclipseHelperMethods.firstOpenEditorByName(activeEditorName);
if (formerlyOpenedEditor != null)
formerlyOpenedEditor.getEditor(true).setFocus();
} catch (CoreException e) {e.printStackTrace();}
//ViewChangeListener.setListenersEnabled(lockBeforeExecution);
}
/**
* Updates the model underlying model of a view by the main model
* @param project The current project
* @param file The View conf file
* @return
*/
public static String updateViewModel(IProject project, IFile file) {
String viewName = file.getName().replace(GlobalConstants.getViewConfExtension(), "");
EditView view = new EditView(project, file, viewName, false);
EditViewWizard wiz = view.getEditViewWizard();
wiz.addPages();
wiz.getPartsPage().addPackagedXmiIds();
wiz.performFinish(false);
String viewDiagramName = viewName+GlobalConstants.getDiagramExtension();
return viewDiagramName;
}
}

View File

@ -0,0 +1,13 @@
package pyUML.exceptions;
/**
* This exception is thrown when a user puhes the "cancel"
* Button in the progress monitor
*/
public class PyUMLCancelledException extends Exception{
/**
*
*/
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,18 @@
package pyUML.exceptions;
/**
*
* This exception is thrown when the parser returns an error;
* When parsing (in python only because of syntax errors),
* the user must fix the problem manually before pyUML can continue.
*
*/
public class PyUMLParseException extends Exception {
public PyUMLParseException(String message) {
super(message);
}
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,19 @@
package pyUML.exceptions;
/**
* This exception is thrown when errors occur while snychronizing code
* An error message should be given.
*/
public class PyUMLSynchronizeCodeException extends Exception{
private static final long serialVersionUID = 1L;
public PyUMLSynchronizeCodeException (String message) {
super(message);
}
public PyUMLSynchronizeCodeException () {
super("Error synchronizing code!");
}
}

View File

@ -0,0 +1,149 @@
package pyUML.listeners;
import org.eclipse.gmf.runtime.common.ui.util.IWorkbenchPartDescriptor;
import org.eclipse.gmf.runtime.common.ui.util.WorkbenchPartDescriptor;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IPropertyListener;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditor;
//import org.eclipse.uml2.diagram.clazz.part.ValidateAction;
//import org.eclipse.uml2.diagram.clazz.providers.UMLValidationDecoratorProvider;
/**
* This class is a listener that runs a live validation run,
* when the listener is called.
* Additionally, it provides static functions to run validation as a background
* process which call the Validation run every n seconds.
*/
public class LiveValidationListener implements IPropertyListener{
private static LiveValidationListener singleton;
private static boolean isStarted;
private static int intervalSeconds = 3;
private static IWorkbenchWindow workbenchWindow;
private LiveValidationListener() {
}
/**
* Gets the singleton instance of this listener
*/
public static LiveValidationListener getListenerSingleton() {
if (LiveValidationListener.singleton == null)
LiveValidationListener.singleton = new LiveValidationListener();
return LiveValidationListener.singleton;
}
/**
* Runs a live validation process once. Uses the currently open
* document for validation
*/
public static void startLiveValidation() {
LiveValidationListener.getListenerSingleton().propertyChanged(null, 0);
}
/**
* Listener method: On every change: do live validation run
*/
public void propertyChanged(Object o, int i) {
IEditorPart ed;
if (LiveValidationListener.workbenchWindow == null)
LiveValidationListener.workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (LiveValidationListener.workbenchWindow == null)
return;
try {
ed = LiveValidationListener.workbenchWindow.getActivePage().getActiveEditor();
} catch (NullPointerException e) {
return;
}
if (!(ed instanceof UMLDiagramEditor))
return;
/* TODO: UML2Tools Editor has to be changed with every Eclipse Version
for Live Validation.
So we are disabling Live Validation for now! */
// UMLDiagramEditor umlEditor = (UMLDiagramEditor) ed;
//
// IWorkbenchPartDescriptor desc = new WorkbenchPartDescriptor(umlEditor.getSite().getId(), umlEditor.getSite().getClass(), umlEditor.getSite().getPage());
// ValidateAction action = new ValidateAction(desc);
// UMLValidationDecoratorProvider.usedResource = umlEditor.getDiagram().eResource();
//
// action.run();
}
/**
* Starts a live validation Thread in background.
* The thread can be stopped with stopLiveValidationInBackground().
* Runs validation every getIntervalSeconds() seconds
*/
public static void startLiveValidationInBackground() {
LiveValidationListener.workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (isStarted)
return;
isStarted = true;
Runnable runnable = new Runnable() {
public void run() {
// do validation run and sleep for a while
// to avoid bad performance on slow systems, the time
// the run takes is measured; the 2-fold time of the
// run is added to the interval time, so that
// the overall CPU usage for validation is < 33%
while (LiveValidationListener.isStarted()) {
long timeBefore = System.currentTimeMillis();
// run validation
LiveValidationListener.startLiveValidation();
long timeAfter = System.currentTimeMillis();
long timeDiff = timeAfter-timeBefore;
long timeToSleep = LiveValidationListener.getIntervalSeconds()*1000
+ timeDiff * 2;
try {
Thread.sleep(timeToSleep);
} catch (InterruptedException e) {}
}
}
};
Thread t = new Thread(runnable);
t.start();
}
/**
* Stops the live validation in background.
*/
public static void stopLiveValidationInBackground() {
isStarted = false;
}
/**
*
* @return true, if there is a background thread doing validation
*/
public static boolean isStarted() {
return isStarted;
}
/**
* @return the update interval in seconds
*/
public static int getIntervalSeconds() {
return intervalSeconds;
}
/**
* @param intervalSeconds the new interval between beackground live
* validation runs in seconds
*/
public static void setIntervalSeconds(int intervalSeconds) {
LiveValidationListener.intervalSeconds = intervalSeconds;
}
}

View File

@ -0,0 +1,32 @@
package pyUML.listeners;
import org.eclipse.core.resources.IProject;
import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor;
import org.eclipse.ui.IPropertyListener;
import pyUML.backend.UMLToolsHelperMethods;
/**
* This class is to update all pyUML.views (model and diagram)
* On every model change
*/
public class ModelChangeListener implements IPropertyListener {
private IProject project;
public ModelChangeListener(IProject project) {
super();
this.project = project;
}
public void propertyChanged(Object source, int propId) {
// on model save, update all pyUML.views
if (source instanceof DiagramEditor) {
DiagramEditor umlEditor = (DiagramEditor) source;
if (! umlEditor.isDirty()) {
UMLToolsHelperMethods.updateModelAndViewPages(this.project);
}
}
}
}

View File

@ -0,0 +1,74 @@
package pyUML.listeners;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IPropertyListener;
import org.eclipse.ui.PlatformUI;
import pyUML.backend.EclipseHelperMethods;
import pyUML.backend.GlobalConstants;
import pyUML.backend.UMLToolsHelperMethods;
import pyUML.views.SynchronizeModelByView;
/**
* This listener synchronizes the global model and
* all other pyUML.views whenever a view is saved
*/
public class ViewChangeListener implements IPropertyListener {
private IProject project;
public ViewChangeListener(IProject project) {
super();
this.project = project;
}
public void propertyChanged(Object source, int propId) {
if (source instanceof DiagramEditor) {
DiagramEditor umlEditor = (DiagramEditor) source;
if (! umlEditor.isDirty()) {
// editor was just saved, otherwise it would be dirty.
// -> synchronize model every time the view is saved
String openEditorName=umlEditor.getTitle();
String viewPath = this.project.getLocation()
.append(GlobalConstants.getPyUmlDir())
.append(openEditorName.replace(GlobalConstants.getDiagramExtension(), "")
+ GlobalConstants.getViewUmlExtension()).toOSString();
SynchronizeModelByView.synchronizeGlobalModel(viewPath, this.project);
IFile globalModelDiagramFile = this.project.getWorkspace()
.getRoot().getFile(this.project.getFullPath()
.append(GlobalConstants.getPyUmlDir())
.append(project.getName()+GlobalConstants
.getDiagramExtension()));
// close all sub-package pyUML.views of global model diagram
for ( org.eclipse.ui.IEditorReference editor :
EclipseHelperMethods.lookForOpenEditorByName(project.getName()+"::.*")) {
PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getActivePage().closeEditor(editor.getEditor(true), true);
}
// after creating model, be sure the diagram view is reloaded
boolean diagramOpened = null != EclipseHelperMethods
.lookForOpenEditorByName(project.getName()+GlobalConstants.getDiagramExtension());
if (diagramOpened) {
// set focus to updated diagram only if no diagram is currently active
boolean keepFocus = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getActivePage().getActiveEditor().getTitle()
.matches(".*"+GlobalConstants.getDiagramExtension());
IEditorPart modelDiagram = UMLToolsHelperMethods.refreshDiagramEditor(project, globalModelDiagramFile, keepFocus);
modelDiagram.addPropertyListener(new ModelChangeListener(project));
}
}
}
}
}

View File

@ -0,0 +1,50 @@
package pyUML.plugin;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
/**
* The activator class controls the plug-in life cycle
*/
public class Activator extends AbstractUIPlugin {
// The plug-in ID
public static final String PLUGIN_ID = "pyUML.plugin";
// The shared instance
private static Activator plugin;
/**
* The constructor
*/
public Activator() {
}
/*
* (non-Javadoc)
* @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
*/
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
}
/*
* (non-Javadoc)
* @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext context) throws Exception {
plugin = null;
super.stop(context);
}
/**
* Returns the shared instance
*
* @return the shared instance
*/
public static Activator getDefault() {
return plugin;
}
}

View File

@ -0,0 +1,193 @@
package pyUML.pythonTree;
import java.util.List;
import java.util.Vector;
import org.eclipse.uml2.uml.Comment;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.VisibilityKind;
import org.python.pydev.parser.jython.ast.Assign;
import org.python.pydev.parser.jython.ast.Attribute;
import org.python.pydev.parser.jython.ast.Call;
import org.python.pydev.parser.jython.ast.Name;
import org.python.pydev.parser.jython.ast.NameTok;
import org.python.pydev.parser.jython.ast.exprType;
import pyUML.backend.GlobalConstants;
import pyUML.backend.ParseHelpers;
/**
* This PythonTree member represents a python attribute.
* It can represent static attributes (defined outside any method)
* or object attributes (defined with "self." inside __init__()
*/
public class PythonTreeAttribute extends PythonTreeNode {
private Assign astNode;
private boolean valid;
private boolean staticAtt;
private String value;
private String fullValue;
private int line;
private int col;
private int nextLine;
/**
* @param parent the parent in the PythonTree
* @param astNode the corresponding Python AST node
* @param staticAtt true, if this is an attribute outside a
* function definition
* @param nextLine the line of the next Python statement. This
* is needed to extract multi-line-attributes
*/
public PythonTreeAttribute(PythonTreeNode parent, Assign astNode, boolean staticAtt, int nextLine) {
super(parent);
this.astNode = astNode;
this.staticAtt = staticAtt;
this.nextLine = nextLine;
this.valid = this.initAttribute();
}
/**
* @return false, if this is no valid attribute
*/
private boolean initAttribute(){
exprType left = this.astNode.targets[0];
exprType right = this.astNode.value;
// analyze the left side of the assign and see
// if this might be a valid attribute
try {
if (staticAtt) { //static: attr without "self"
this.name = ((Name)left).id;
this.line = ((Name)left).beginLine;
this.col = ((Name)left).beginColumn;
}
else{ // object attr: begins with "self."
Attribute leftAtt = (Attribute)left;
if (! ((Name)leftAtt.value).id.equals("self"))
return false;
this.name =((NameTok)(leftAtt).attr).id;
this.line = ((NameTok)(leftAtt).attr).beginLine;
this.col = ((NameTok)(leftAtt).attr).beginColumn;
}
}
catch (ClassCastException e) {
// if anything is not like expected, this is not a
// att=value
// or self.att=value
// attribute -> this is not considered a valid attribute!
return false;
}
// now, look at the right side
if (right instanceof Call)
return false;
this.value = ParseHelpers.getStringOfExpr(right, this.getParent().getInFile(), true, true, this.nextLine);
// if the value was abbreviated, save full value, also.
if (this.value.endsWith("(...)")) {
this.fullValue = ParseHelpers.getStringOfExpr(right, this.getParent().getInFile(), true, false, this.nextLine);
}
// if everything went right, this is considered a valid attribute!
return true;
}
/**
* A PythonTreeAttribute is created always when an Assign
* is found in the class body or the constructor.
* Sometimes an assign does not declare an attribute; then,
* this object should not be added to the PythonTreeClass
* attributes and be left for the garbage collector.
*
* @return if this astNode really represents a python
* static/object attribute and shall be saved
*/
public boolean isValid() {
return this.valid;
}
public boolean isStatic() {
return staticAtt;
}
/**
* @return this attribute's (default) value
*/
public String getValue() {
return value;
}
public boolean synchronizeModel(NamedElement modelElement) {
Property modelProperty = (Property) modelElement;
// set this attribute private in model, if its name starts with "__"
// use protected, if class starts with "_" (this is only python convention)
if (this.getName().startsWith("__")) {
modelProperty.setVisibility(VisibilityKind.PRIVATE_LITERAL);
} else if (this.getName().startsWith("_")) {
modelProperty.setVisibility(VisibilityKind.PROTECTED_LITERAL);
}
String defVal = this.getValue();
if (! "None".equals(defVal))
modelProperty.setDefault(this.getValue());
// if default value was abbreviated ->
// save full default value as comment,
// beginning with a PyUML Marker
if (this.fullValue != null) {
Comment fullValueComment = null;
for (Comment comment : modelProperty.getOwnedComments()) {
if (comment.getBody().startsWith(GlobalConstants.getFullDefault())) {
fullValueComment=comment;
break;
}
}
if (fullValueComment == null)
fullValueComment = modelProperty.createOwnedComment();
fullValueComment.setBody(GlobalConstants.getFullDefault()
+ this.fullValue);
} else {
// there is no "full" value -> delete all comments
// that save a full value
List<Comment> commentList = new Vector<Comment>();
commentList.addAll(modelProperty.getOwnedComments());
for (Comment comment : commentList) {
if (comment.getBody().startsWith(GlobalConstants.getFullDefault())) {
comment.destroy();
}
}
}
modelProperty.setIsStatic(this.isStatic());
return true;
}
public int getLine() {
return line;
}
public int getCol() {
return col;
}
public PythonTreeClass getParent() {
return (PythonTreeClass) super.getParent();
}
/**
* @return the un-abbreviated attribute (default) value
* for this attribute
*/
public String getFullValue() {
return fullValue;
}
public int getNextLine() {
return nextLine;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,166 @@
package pyUML.pythonTree;
import java.io.File;
import java.util.List;
import java.util.Vector;
import org.eclipse.core.runtime.IPath;
import org.python.pydev.parser.jython.SimpleNode;
import org.python.pydev.parser.jython.ast.ClassDef;
import org.python.pydev.parser.jython.ast.Module;
import org.python.pydev.parser.jython.ast.stmtType;
import org.python.pydev.refactoring.ast.visitors.VisitorFactory;
import pyUML.backend.EclipseHelperMethods;
import pyUML.backend.ParseHelpers;
import pyUML.exceptions.PyUMLCancelledException;
import pyUML.exceptions.PyUMLParseException;
/**
* This class represents a Python file in the Python
* Package structure.
* It must have a parent package and contains a
* pydev Abstract Syntax Tree (AST)
*
*/
public class PythonTreeFile extends PythonTreeNode{
private IPath filePath;
private PythonTreePackage parent;
private SimpleNode ast;
private List<PythonTreeClass> classesInFile;
private String fileContent;
private String[] splittedFileContent = null;
public PythonTreeFile(IPath filePath, PythonTreePackage parent) throws PyUMLParseException, PyUMLCancelledException{
super(parent);
this.filePath = filePath;
this.parent = parent;
this.name = filePath.lastSegment();
this.classesInFile = new Vector<PythonTreeClass>();
this.initAst();
this.initClassesWithAST();
}
/**
* Parses the given Python file and saves the ast
*/
private void initAst() throws PyUMLParseException{
// init AST so that it will never be null
this.ast=new SimpleNode();
// try to get content of python file
this.fileContent = ParseHelpers.fileToString(
new File(filePath.toOSString()), this.getProject());
if (this.fileContent==null) {
return;
}
// get AST of file
try{
this.ast = VisitorFactory.getRootNodeFromString(this.fileContent);
} catch (Throwable t) {
String message = t.getClass().getName()+ " while parsing file "
+ this.filePath.toOSString() +"\n\n" +t.getMessage();
throw new PyUMLParseException(message);
}
}
/**
* extracts all the top level clases (no inner classes)
* out of the AST
*/
private void initClassesWithAST() throws PyUMLParseException, PyUMLCancelledException{
if (this.ast instanceof Module) {
Module pyModule = (Module) this.ast;
stmtType[] statements = pyModule.body;
for (int i = 0; i < statements.length; i++) {
if (statements[i] instanceof ClassDef) {
// get end line of class -> look for following statement
int followingLine = 0;
if (i +1 < statements.length) {
stmtType followingStmt = statements[i+1];
followingLine = followingStmt.beginLine;
}
ClassDef pyClass = (ClassDef) statements[i];
PythonTreeClass cl = new PythonTreeClass(this.parent, this, pyClass, followingLine-1);
this.classesInFile.add(cl);
}
}
}
}
public void updateFileInEclipse() {
EclipseHelperMethods.updateFile(this.getFilePath().toOSString(), this.getProject());
}
/**
* re-inits a file -> re-parses the content
* and adds new classes, if needed.
* @throws PyUMLParseException
*/
public void reInitFile() throws PyUMLParseException, PyUMLCancelledException {
for (PythonTreeClass cl : this.getClassesInFile()) {
this.getRoot().getClassDict().remove(cl.getPackageStructure()+cl.getName());
this.getRoot().getClassNameDict().remove(cl.getPackageStructure()+cl.getName());
this.getParent().getChildClasses().remove(cl);
}
this.splittedFileContent=null;
this.classesInFile = new Vector<PythonTreeClass>();
this.initAst();
this.initClassesWithAST();
this.getParent().getChildClasses().addAll(this.getClassesInFile());
this.getRoot().getChildClasses().addAll(this.getParent().getChildClasses());
}
/**
* Splits the file content by "\n", which results in an array of lines.
* The result is cached for performance reasons.
* @return an Array containing the lines of the file content
*/
public String[] getSplittedFileContent() {
if (splittedFileContent == null)
splittedFileContent = fileContent.split("\n");
return splittedFileContent;
}
public IPath getFilePath() {
return filePath;
}
public SimpleNode getAst() {
return ast;
}
public PythonTreePackage getParent() {
return parent;
}
public List<PythonTreeClass> getClassesInFile() {
return classesInFile;
}
/**
* @return the content of the whole file as a String
*/
public String getFileContent() {
return fileContent;
}
/**
* Set this objects "file content" string. This does *not*
* update any real file!
* @param fileContent the file content as a String
*/
public void setFileContent(String fileContent) {
this.fileContent = fileContent;
this.splittedFileContent=null;
}
public void setFilePath(IPath filePath) {
this.filePath = filePath;
}
}

View File

@ -0,0 +1,627 @@
package pyUML.pythonTree;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Comment;
import org.eclipse.uml2.uml.Interface;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Operation;
import org.eclipse.uml2.uml.Parameter;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.VisibilityKind;
import org.python.pydev.parser.jython.ast.Expr;
import org.python.pydev.parser.jython.ast.FunctionDef;
import org.python.pydev.parser.jython.ast.Name;
import org.python.pydev.parser.jython.ast.NameTok;
import org.python.pydev.parser.jython.ast.Str;
import org.python.pydev.parser.jython.ast.exprType;
import org.python.pydev.parser.jython.ast.stmtType;
import pyUML.backend.GlobalConstants;
import pyUML.backend.ParseHelpers;
import pyUML.exceptions.PyUMLParseException;
import pyUML.exceptions.PyUMLSynchronizeCodeException;
import pyUML.refactoring.BicycleRefactoring;
import pyUML.refactoring.FileRefactoring;
/**
* This class represents a Method definition inside a Python Class
*/
public class PythonTreeMethod extends PythonTreeNode {
private FunctionDef astNode;
private boolean staticMethod;
private List<String> arguments;
private String docString;
private int docStringLine;
private int docStringCol;
private int lastLine;
private String indent = " ";
private Dictionary<String, String> argumentDefaultDict;
private Dictionary<String, Integer> argumentLineDict;
private Dictionary<String, Integer> argumentColumnDict;
public PythonTreeMethod(PythonTreeClass parent, FunctionDef astNode, int nextLine) throws PyUMLParseException{
super(parent);
this.astNode = astNode;
this.lastLine = nextLine - 1;
// set last non-empty line as last line of this method
while (this.lastLine>=0 && parent.inFile.getSplittedFileContent()[lastLine-1].matches("[\\s]*")) {
this.lastLine--;
}
this.arguments = new Vector<String>();
this.argumentDefaultDict = new Hashtable<String, String>();
this.argumentLineDict = new Hashtable<String, Integer>();
this.argumentColumnDict = new Hashtable<String, Integer>();
this.initMethod();
}
public void initMethod() throws PyUMLParseException{
this.name = ((NameTok) this.astNode.name).id;
if (this.name.matches(".*__init__.*") && this.getParent().getName().matches(".*CMCEntryBrows.*")) {
}
exprType[] argList = this.astNode.args.args;
exprType[] defaultList = this.astNode.args.defaults;
// ### Get Arguments ### //
// get offset of first argument with default value
int argCount = argList.length;
int defaultCount = defaultList.length;
int defaultOffset = argCount - defaultCount;
// get arguments with corresponding default values
int argNo = 0;
for (exprType arg : argList) {
// fix indent, if needed
String line = this.getParent().getInFile().getSplittedFileContent()[arg.beginLine ];
int indentLength=0;
if (line.length() > 0)
for (; line.charAt(indentLength) == ' ' && line.length() > indentLength +1 ; indentLength++) ;
if (this.indent.length() != indentLength && ! line.matches("^[\\s]*\\\"\\\"\\\".*$")) {
this.indent = "";
for (int i=0; i< indentLength; i++)
this.indent += " ";
}
// argument name
String argName = ((Name) arg).id;
if (this.arguments.contains(argName)) {
String message = "Argument inconsistency detected!\n"+
"The python method '"+this.name+ "' in the class '" +
this.getParent().getName() +
"'\nhas an argument inconsistency with the argument '" +
argName + "'.\n\n" +
"The argument exists mor than once!\n\n" +
"Please correct this error!";
throw new PyUMLParseException(message);
}
this.arguments.add(argName);
this.argumentLineDict.put(argName, arg.beginLine);
this.argumentColumnDict.put(argName, arg.beginColumn);
// argument default value
if (defaultCount> 0 && argNo >= defaultOffset && (! argName.equals("self"))) {
exprType defaultVal = defaultList[argNo - defaultOffset];
exprType defaultValBefore = null;
// test if parameter without default follows parameter with default
// -> this is not allowed but not caught by pyDev
if (argNo - defaultOffset >= 1)
defaultValBefore = defaultList[argNo - defaultOffset-1];
String defValString = ParseHelpers.getStringOfExpr(defaultVal, this.getParent().getInFile(), false, false, 0);
if (defaultVal == null && defaultValBefore!= null) {
String message = "Argument inconsistency detected!\n"+
"The python method '"+this.name+ "' in the class '" +
this.getParent().getName() +
"'\nhas an argument inconsistency with the argument '" +
argName + "'.\n\n" +
"There are arguments without default values" +
"\nfollowing arguments with default values.\n\n" +
"Please correct this error!";
throw new PyUMLParseException(message);
} else if (defaultVal != null){
this.argumentDefaultDict.put(argName, defValString);
}
}
argNo++;
}
// set static attribute */
if (argList.length == 0 || (! this.arguments.get(0).equals("self")))
this.staticMethod = true;
stmtType[] methodBody = this.astNode.body;
// extract DocString, if it exists
if (methodBody.length > 0 && methodBody[0] instanceof Expr) {
Expr exp = (Expr) methodBody[0];
if (exp.value instanceof Str) {
Str stringExp = (Str) exp.value;
if (stringExp.type == Str.TripleDouble ||
stringExp.type == Str.TripleSingle) {
this.docString=stringExp.s;
this.docStringLine = stringExp.beginLine;
this.docStringCol = stringExp.beginColumn;
}
}
}
}
public boolean synchronizeModel(NamedElement modelElement) {
super.synchronizeModel(modelElement);
Operation modelMethod = (Operation) modelElement;
// set this method private in model, if its name starts with "__"
// use protected, if class starts with "_" (this is only python convention)
if (this.getName().startsWith("__")) {
modelMethod.setVisibility(VisibilityKind.PRIVATE_LITERAL);
} else if (this.getName().startsWith("_")) {
modelMethod.setVisibility(VisibilityKind.PROTECTED_LITERAL);
}
// set/remove static flag
if (this.staticMethod != modelMethod.isStatic())
modelMethod.setIsStatic(this.staticMethod);
List<Parameter> parameterList = modelMethod.getOwnedParameters();
// for all parameters in code -> check if model parameters are the same;
/// if not, add them
for (int i=0; i< this.getArguments().size(); i++) {
String pyArg = this.getArguments().get(i);
if (parameterList.size() > i) {
Parameter modelParam = parameterList.get(i);
// check if parameter name and default value are the same
String defautlValue = (this.getArgumentDefaultDict().get(pyArg));
if (defautlValue == null)
defautlValue = "";
if ((! pyArg.equals(modelParam.getName())) ||
( ! defautlValue.equals(modelParam.getDefault()))) {
// this parameter is not the same!
// remove all parameters from here and create following parameters!
for (int j=i; j< parameterList.size(); j++)
parameterList.remove(j);
// restart loop at the current position (again)
i--;
}
} else {
// Parameter at this position does not exist
// Append new parameter
Parameter newParam = modelMethod.createOwnedParameter(pyArg, null);
newParam.setDefault(this.getArgumentDefaultDict().get(pyArg));
}
}
// test, if there are additional model parameters -> remove them!
if (parameterList.size() > this.getArguments().size()) {
for (int i=this.getArguments().size(); i < parameterList.size(); i++) {
parameterList.get(i).destroy();
}
}
return true;
}
public boolean synchronizeCode(Operation modelOp) throws PyUMLSynchronizeCodeException{
if (this.name.matches("search.*") && this.getParent().getName().startsWith("Group")) {
}
List<String> modelParameters = new Vector<String>();
int line = this.astNode.name.beginLine;
boolean parametersNeedRewrite = false;
boolean modelIsStatic = true;
methodChildLoop:
for (Parameter modelParameter : modelOp.getOwnedParameters()) {
// get all relevant data
String modelParName = modelParameter.getName();
modelParameters.add(modelParName);
// stop if this is not a parameter (null)
if (modelParName == null)
continue methodChildLoop;
if (modelParName.equals("self")) {
modelIsStatic = false;
}
String modelParDefault = modelParameter.getDefault();
if (this.arguments.contains(modelParName)){
//found parameter with same name!
String codeParDefault = this.getArgumentDefaultDict().get(modelParName);
if (((modelParDefault == codeParDefault)&&(codeParDefault== null))
|| (modelParDefault != null && codeParDefault != null
&& (codeParDefault.equals(modelParDefault)
|| (modelParDefault.equals(GlobalConstants.getUnknownExpression())))))
// parameter exists and has the same default value
// everything is fine!
continue methodChildLoop;
// parameter exists, but with different default!
// fix default value!
// if default value does not exist in model
if (modelParDefault == null) {
parametersNeedRewrite = true;
continue methodChildLoop;
}
else if (codeParDefault == null) { //if default value wasn't there
//add a default value
parametersNeedRewrite = true;
continue methodChildLoop;
}
else {
// default value changed
// -> change default value
parametersNeedRewrite = true;
continue methodChildLoop;
}
} else {
// parameter with this name not found!
// look if parameter was renamed (look in old model)
// this is done with bicycle repair man, so that
// all references will be renamed, too
String paramXMIId = this.getRoot().getModelXmiDict().get(modelParameter);
if (this.getRoot().getXmiModelDictOld().keySet().contains(paramXMIId)) {
// parameter found -> try to find old name in code
Parameter oldModelParam = (Parameter) this.getRoot().getXmiModelDictOld().get(paramXMIId);
String oldParamName = oldModelParam.getName();
if (this.arguments.contains(oldParamName)) {
// parameter with old name found -> rename it!
int col = this.argumentColumnDict.get(oldParamName);
BicycleRefactoring.doRenameObject(this.getParent().inFile,
modelParName, line, col, this.getRoot().getProject());
setChanged(line, modelParName);
return true;
}
}
}
//parameter does and did not exist in code
//create it!
parametersNeedRewrite = true;
continue methodChildLoop;
}
// check if parameters were deleted -> delete them in code!
for (String parameter : this.arguments) {
if (! modelParameters.contains(parameter)) {
//parameter does not exist in model -> delete it
parametersNeedRewrite = true;
break;
}
}
// if method changed its static property,
// ensure the "staticmethod" call is added/removed
if (this.fixStaticmethodCall(modelIsStatic))
return true;
if (parametersNeedRewrite) {
// write new parameters definition
String parametersDef = "";
for (Parameter modelParameter: modelOp.getOwnedParameters()) {
// get all relevant data
String modelParName = modelParameter.getName();
// stop if this is not a parameter (null)
if (modelParName == null)
continue;
String modelParDefault = modelParameter.getDefault();
if (parametersDef.length() > 0)
parametersDef += ", ";
parametersDef += modelParName;
if (modelParDefault != null)
parametersDef += "=" + modelParDefault;
}
// replace old definition with help of regex
Pattern pattern = Pattern.compile("([\\s]*def[\\s]*[^\\(]+[\\s]*\\()[^\\)]*(\\)[\\s]*:.*)");
String defLine = FileRefactoring.getLine(this.getParent().inFile, line);
Matcher matcher = pattern.matcher(defLine);
if (! matcher.find()){
return false;
}
// write the new method definition line
String newDefLine = matcher.group(1) + parametersDef + matcher.group(2);
FileRefactoring.replaceLine(this.getParent().inFile, line, newDefLine, true);
setChanged(line, newDefLine);
return true;
}
return false;
}
/**
* On synchronizing code:
* Test the presence of all attributes
* - add/rename them, if needed
* - check initial value and fix it, if needed
*
* @param modelClass the class in the model where the attributes are defined
* @return true, if something was changed; false otherwise
*/
public static boolean fixAttributeDefinitions(
Classifier modelClass, String initIndent,
Map<String, PythonTreeAttribute> presentAttrs,
PythonTreeClass pyClass, int lastLine, boolean isStatic)
throws PyUMLSynchronizeCodeException{
// if this is the __init__ method, ensure all non-static attributes are defined here!
//Map<String, PythonTreeAttribute> presentAttrs = pyClass.getChildObjectAttrDict();
List<Property> neededAttrs = null;
if (modelClass instanceof Class)
neededAttrs = ((Class) modelClass).getOwnedAttributes();
else if (modelClass instanceof Interface)
neededAttrs = ((Interface) modelClass).getOwnedAttributes();
for (Property neededAttr : neededAttrs) {
if (isStatic != neededAttr.isStatic())
continue;
String attrName = neededAttr.getName();
String initialValue = neededAttr.getDefault();
// if initial value was abbreviated before, try to get
// full value out of model
if (initialValue != null && initialValue.endsWith("(...)")) {
for (Comment comment :neededAttr.getOwnedComments()) {
if (comment.getBody().startsWith(GlobalConstants.getFullDefault())) {
initialValue = comment.getBody().substring(GlobalConstants.getFullDefault().length());
break;
}
}
}
if (! presentAttrs.containsKey(attrName)) {
// attribute is not present -> find out, if it was renamed in model
String param_xmi = pyClass.getRoot().getModelXmiDict().get(neededAttr);
if (pyClass.getRoot().getXmiModelDictOld().containsKey(param_xmi)) {
Property oldParameter = (Property) pyClass.getRoot().getXmiModelDictOld().get(param_xmi);
String oldParamName = oldParameter.getName();
if (presentAttrs.containsKey(oldParamName)) {
// attribute was renamed -> rename it in code with Bicycle Repair Man
int line = presentAttrs.get(oldParamName).getLine();
int col = presentAttrs.get(oldParamName).getCol();
boolean success = BicycleRefactoring.doRenameObject(
pyClass.inFile,
attrName, line, col, pyClass.getRoot().getProject());
return success;
}
}
// attribute is and was not present -> create it!
String attrDefLine = (isStatic ? pyClass.getIndent() : initIndent+"self.")+ attrName + " = ";
if (initialValue != null && (! initialValue.endsWith("(...)")))
attrDefLine += initialValue;
else
attrDefLine += "None";
attrDefLine += " # created by PyUML";
if (lastLine <=0 )
FileRefactoring.appendToFile(pyClass.inFile, attrDefLine);
else
FileRefactoring.insertAtLine(pyClass.inFile,
lastLine, attrDefLine + "\n");
pyClass.getRoot().setChangedFileLine(pyClass.inFile.getFilePath().toOSString()+":"+lastLine + attrDefLine + ":");
return true;
} else {
// attribute is defined, check initial value
// if initial model value ends with (...),
// this value was cut when creating the model
// -> do not change it in code
PythonTreeAttribute pyAttr = presentAttrs.get(attrName);
if (pyAttr.getValue() != null && initialValue != null) {
}
if ((!pyAttr.getValue().equals(initialValue))
&& (!(pyAttr.getValue().equals("None") && initialValue==null))
&& (! initialValue.endsWith("(...)"))
&& (! initialValue.startsWith(pyAttr.getValue().replaceAll("\\(\\.\\.\\.\\)$", ""))) ){
// default value changed!
int line = pyAttr.getLine();
Pattern pattern = Pattern.compile("([\\s]*"+(isStatic?"":"self.")+"[^=]*=[\\s]*)([^#]+)(.*)");
String defLine = FileRefactoring.getLine(pyClass.getInFile(), line);
Matcher matcher = pattern.matcher(defLine);
if (! matcher.find()){
return false;
}
String initString = initialValue;
if (initString == null)
initString = "None";
// write the new method definition line
String commentGroup = matcher.group(3);
if (commentGroup.startsWith("#"))
commentGroup = " " + commentGroup;
String newDefLine = matcher.group(1) + initString + commentGroup;
// if this was a multi-line attribute, delete
// all following lines and preserver comments
for (int i = line ; i < pyAttr.getNextLine() - 1; i++)
pyClass.getInFile().setFileContent(FileRefactoring.removeLine(pyClass.inFile, i, false, true));
// now, just replace the changed line
FileRefactoring.replaceLine(pyClass.inFile, line, newDefLine, true);
pyClass.getRoot().setChangedFileLine(pyClass.inFile.getFilePath().toOSString()+":"+line);
return true;
}
}
}
return false;
}
/**
* On synchronizing code:
* Test staticmethod call of this method and
* fix it, if needed
*
* (python static methods must have the call
* <methodname> = staticmethod(<methodname>)
* after the method definition)
*
* @param modelIsStatic true, if this method should be static
* in code and vice versa
* @return true, if something was changed
* false, otherwise
*/
public boolean fixStaticmethodCall(boolean modelIsStatic) throws PyUMLSynchronizeCodeException{
// ensure there is a staticmethod call after the method
String fileContent[] = this.getParent().inFile.getFileContent().split("\n");
String lineContent = "";
int lineNo = this.lastLine;
if (this.lastLine <= 0)
lineNo= fileContent.length -1;
// if next command is "staticmethod", it is meant to be
// part of *this* method
if (fileContent.length > lineNo + 1
&& fileContent[lineNo+1].matches("^[\\s]*[^=\\(\\s]*[\\s]*=[\\s]*staticmethod[\\s]*\\([\\s]*[^\\)\\s]*[\\s]*\\)[\\s]*.*")) {
// the next command is the line to change
lineNo++;
}
// find the last non-empty non-comment line
for (; lineNo>=0; lineNo--){
lineContent = fileContent[lineNo];
if (! (lineContent.matches("^[\\s]*$") || lineContent.matches("^[\\s]*#.*$")) )
break;
}
if (lineContent.matches("^[\\s]*[^=\\(\\s]*[\\s]*=[\\s]*staticmethod[\\s]*\\([\\s]*[^\\)\\s]*[\\s]*\\)[\\s]*.*")) {
// there is already a staticmethod call
if (!modelIsStatic) {
// staticmethod call has to be removed
FileRefactoring.removeLine(this.getParent().inFile, lineNo, true, false);
return true;
}
// ensure staticmethod call is OK
if (lineContent.matches("[\\s]*"+this.getName()+"[\\s]*=[\\s]*staticmethod[\\s]*\\([^\\)\\s]*\\)[\\s]*.*")){
// staticmethod call alright, nothing needs to be changed
return false;
} else {
// fix staticmethod call (e.g. when method was renamed)
String newContent = this.getParent().getIndent() + this.getName()+" = staticmethod("+this.getName()+")";
FileRefactoring.replaceLine(this.getParent().inFile, lineNo+1, newContent, true);
setChanged(lineNo, newContent);
return true;
}
} else {
// there is no staticmethod call at all
if (!modelIsStatic) {
// all is OK
return false;
} else {
//-> insert it after the end of the method
String newContent = this.getParent().getIndent()+this.getName()+" = staticmethod("+this.getName()+")";
lineNo = this.lastLine;
if (this.lastLine <= 0)
lineNo = fileContent.length -1;
// from the next method, find the first before line with whitespace
for (; lineNo>=0; lineNo--){
lineContent = fileContent[lineNo];
if (! (lineContent.matches("^[\\s]*$")))
break;
}
FileRefactoring.insertAtLine(this.getParent().inFile, lineNo + 2, newContent + "\n");
setChanged(lineNo, newContent);
return true;
}
}
}
/**
* tells the position of current code change to PythonTreeRoot
* so that it can decide if the same line is changed again
* and again and thus detect an unfinished loop.
*
* @param line the changed line in the file
*/
private void setChanged(int line, String pos) throws PyUMLSynchronizeCodeException{
if (pos == null)
pos = "";
else pos = ":position:"+pos;
this.getRoot().setChangedFileLine(getParent().inFile.getFilePath().toOSString()+":"+line+pos);
}
public boolean isStatic() {
return staticMethod;
}
public PythonTreeClass getParent() {
return (PythonTreeClass) super.getParent();
}
public String getDocString() {
return docString;
}
public int getDocStringLine() {
return docStringLine;
}
public int getDocStringCol() {
return docStringCol;
}
public FunctionDef getAstNode() {
return astNode;
}
public List<String> getArguments() {
return arguments;
}
public Dictionary<String, String> getArgumentDefaultDict() {
return argumentDefaultDict;
}
public int getLastLine() {
return lastLine;
}
public String getIndent() {
return indent;
}
}

View File

@ -0,0 +1,128 @@
package pyUML.pythonTree;
import org.eclipse.core.resources.IProject;
import org.eclipse.uml2.uml.NamedElement;
import pyUML.exceptions.PyUMLCancelledException;
import pyUML.exceptions.PyUMLSynchronizeCodeException;
/**
* A generic node of the Python package structure tree
* This class is used as abstract super class for all
* PythonTree Elements
*/
public abstract class PythonTreeNode {
private PythonTreeNode parent;
protected String name;
protected String xmi_id;
private NamedElement associatedModelElement;
public PythonTreeNode(PythonTreeNode parent) {
this.parent = parent;
}
/**
* returns the parent of this package.
* If this is the root, return null.
* @return
*/
public PythonTreeNode getParent() {
if (! this.isRoot())
return parent;
else
return null;
}
/**
* Synchronize the model from the given model element
* downwards.
* Create, delete and move model elements
*
* @param modelElement
* @return
*/
public boolean synchronizeModel(NamedElement modelElement) {
this.associatedModelElement = modelElement;
// test if name changed -> update model element name if name changed
if (! this.isRoot() && (!this.getName().equals(modelElement.getName()))) {
modelElement.setName(this.getName());
}
return false;
}
/**
* Opposite of synchronizeModel; Synchronizes the code
* with a given model
*
* @param umlElement
* @return true if code was changed (so that the python tree
* has to be updated), false if everything went OK
*/
public boolean synchronizeCode(NamedElement modelElement) throws PyUMLSynchronizeCodeException, PyUMLCancelledException{
return false;
}
/**
* after running synchronizeModel, this method returns the corresponding
* UML Model NamedElement of this PythonTreeNode
* @return
*/
public NamedElement getAssociatedModelElement() {
return associatedModelElement;
}
/**
* method to easily find out if this is the Root
* of the Python Package Tree
*
* @return false, if this is a package,
* the subclass PythonTreeRoot returns true
*/
public boolean isRoot() {
return false;
}
/**
* Gets the XMI-id of this node,
* or null, if no XMI-ID was defined
* @return
*/
public String getXmi_id() {
return xmi_id;
}
/**
* @return the root Element of this PythonTree
*/
public PythonTreeRoot getRoot() {
if (this.isRoot())
return (PythonTreeRoot) this;
else
return this.getParent().getRoot();
}
/**
* Get the name of this node
* @return
*/
public String getName() {
return name;
}
/**
* Get the Eclipse project that was used while creating this node
* @return
*/
public IProject getProject() {
return this.getRoot().getProject();
}
}

View File

@ -0,0 +1,541 @@
package pyUML.pythonTree;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Interface;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Package;
import pyUML.backend.EclipseHelperMethods;
import pyUML.backend.ParseHelpers;
import pyUML.exceptions.PyUMLCancelledException;
import pyUML.exceptions.PyUMLParseException;
import pyUML.exceptions.PyUMLSynchronizeCodeException;
/**
* This class represents a package directory in the python
* code structure.
* A package can contain child packages or Python files.
*/
public class PythonTreePackage extends PythonTreeNode{
IPath packageDir;
private List<PythonTreePackage> childPackages;
private List<PythonTreeClass> childClasses;
private List<PythonTreeFile> pythonFiles;
private PythonTreeFile initPy;
static int count = 0;
// this is used when a class was moved -> a complete restart is needed
// instead of re-initializing the changed class
static boolean completeNewStart = false;
public PythonTreePackage(IPath packageDir, PythonTreeNode parent) throws PyUMLParseException, PyUMLCancelledException {
super(parent);
this.packageDir = packageDir;
this.childClasses = new Vector<PythonTreeClass>();
this.childPackages = new Vector<PythonTreePackage>();
this.pythonFiles = new Vector<PythonTreeFile>();
if (packageDir != null) {
initPackage();
}
}
private void initPackage() throws PyUMLParseException, PyUMLCancelledException{
File dir = new File(packageDir.toOSString());
this.name = dir.getName();
// list dir
File[] dirList = dir.listFiles();
for (File entry:dirList) {
// if directory found: check if it is package,
// if yes, recursively add child packages
if (entry.isDirectory()){
if (checkForInitPy(entry)){
childPackages.add(new PythonTreePackage(
new Path(entry.getAbsolutePath()),this));
}
continue;
}
if (entry.getName().endsWith(".py")) {
PythonTreeFile f = new PythonTreeFile(
new Path(entry.getAbsolutePath()), this);
this.pythonFiles.add(f);
this.childClasses.addAll(f.getClassesInFile());
if (entry.getName().equals("__init__.py")) {
this.initPy = f;
}
this.getRoot().worked();
}
}
// get XMI:ID from __init__.py
if (this.initPy != null) {
this.xmi_id = ParseHelpers.extractXmiFromString(
this.initPy.getFileContent());
if (this.xmi_id != null)
this.getRoot().getXmiPackDict().put(this.xmi_id, this);
}
}
/**
* tests, if the given directory contains a file "__init__.py"
* If yes, it can be considered as package.
*
* @param dir the directory to check
* @return
*/
private boolean checkForInitPy(File dir) {
if (! dir.isDirectory())
return false;
for (File entry: dir.listFiles()) {
if (entry.getName().equals("__init__.py"))
return true;
}
return false;
}
/**
* Writes a XMI-ID as a comment to this packages's __init__.py file
* @param xmiID
*/
public void writeXmiID(String xmiID) {
String initPyContent = this.getInitPy().getFileContent();
initPyContent = initPyContent.replaceAll("# PyUML: .*\n", "");
initPyContent = "# PyUML: Do not remove this line! # XMI_ID:" + xmiID + "\n" + initPyContent;
File f = new File(this.getInitPy().getFilePath().toOSString());
ParseHelpers.stringToFile(f, initPyContent, this.getProject());
}
/**
* synchronize the model by this Package using
* the packages/classes XMI-IDs
*/
public boolean synchronizeModel(NamedElement modelElement){
super.synchronizeModel(modelElement);
Package modelPack = (Package) modelElement;
Map<String, EObject> xmiModelDict = this.getRoot().getXmiModelDict();
List<NamedElement> processedElements = new Vector<NamedElement>();
List<PythonTreeNode> childElements = new Vector<PythonTreeNode>();
childElements.addAll(this.getChildPackages());
childElements.addAll(this.getChildClasses());
for (PythonTreeNode pyChildNode : childElements) {
String xmi_id= pyChildNode.getXmi_id();
boolean createNewElement = false;
if (xmi_id != null) {
if (xmiModelDict.containsKey(xmi_id)) {
NamedElement modelChild = (NamedElement) xmiModelDict.get(xmi_id);
// if found element is also child of model,
// everything is OK, continue with packageSynchonization of children
if (modelElement.getOwnedElements().contains(modelChild)) {
pyChildNode.synchronizeModel(modelChild);
processedElements.add(modelChild);
}
else {
// element found, but at another place
// -> move model element to be child of this model element
if (modelChild instanceof Package) {
Package childPack = (Package) modelChild;
childPack.setNestingPackage(modelPack);
}
else if (modelChild instanceof Class || modelChild instanceof Interface) {
Classifier childClass = (Classifier) modelChild;
childClass.setPackage(modelPack);
}
// ## synchronize children ##
// now the package has the right place, continue recursively
if (! pyChildNode.synchronizeModel(modelChild))
return false;
processedElements.add(modelChild);
}
} else {
/* the xmi_id in the code is not present in model, but
* in the code. (Propably it was deleted in the model)
* This is not possible, because when this method is called
* the code was supposed to change, not the model.
* -> This is an inconsistency that cannot be resolved.
* -> Because a Model element with a special xmi_id cannot
* be created.
* -> Show an Error message
*/
if (! this.getRoot().isCreateNewModel()) {
boolean ignore = false;
if (this.getRoot().getXmiModelDict().size() == 0) {
ignore = MessageDialog.openQuestion(null, "Deleted Model",
"The current python code was synchronized \n" +
"with a UML model earlier.\n" +
"Now, the UML model cannot be found.\n\n" +
"Do you want to create a new UML model?");
} else {
ignore = MessageDialog.openQuestion(null, "Model Synchronization error found",
"The model is missing an element it formerly had\n" +
"and which is still present in the code.\n" +
"Obviously, the model was edited outside PyUml!\n\n" +
"Please manually resolve the situation by removing\n" +
"the XMI_ID comment in the __init__.py file of the\n" +
"package or in the DocString comment of the class.\n\n" +
"Element name: "+ pyChildNode.getName() +"\n\n"+
"Do you want to ignore this and create new model elements?");
}
if (! ignore)
return false;
else {
this.getRoot().setCreateNewModel(true);
createNewElement=true;
}
} else {
// the warning was disabled by user;
createNewElement=true;
}
}
}
if (xmi_id==null || createNewElement) {
// no xmi_id is present in the code -> this is a manually
// created package! It must be created in the model, too.
NamedElement modelNewChild = null;
if (pyChildNode instanceof PythonTreePackage) {
modelNewChild = modelPack.createNestedPackage(pyChildNode.getName());
} else if (pyChildNode instanceof PythonTreeClass) {
modelNewChild = modelPack.createOwnedClass(pyChildNode.getName(), false);
}
// ## synchronize children ##
if (modelNewChild != null) {
// now the package is created, we can recursively edit it
// by the pyPack synchronization method
if (! pyChildNode.synchronizeModel(modelNewChild))
return false;
processedElements.add(modelNewChild);
}
}
}
// test if all elements of model were processed
for (Element modelChild : modelElement.getOwnedElements()) {
if ((modelChild instanceof Class || modelChild instanceof Package)
&& (! processedElements.contains(modelChild)))
// if this model element was not touched until now,
// it obviously was deleted in code and must be deleted
// also in model
this.getRoot().getModelElementsToDestroy().add((NamedElement)modelChild);
}
return true;
}
public boolean synchronizeCode(NamedElement modelElement) throws PyUMLSynchronizeCodeException, PyUMLCancelledException {
Map<EObject, String> modelXmiDict = this.getRoot().getModelXmiDict();
Map<String, PythonTreePackage> xmiPackDict = this.getRoot().getXmiPackDict();
Map<String, PythonTreeClass> xmiClassDict = this.getRoot().getXmiClassDict();
Package modelPack = (Package) modelElement;
// if package is to be renamed
if (! modelPack.getName().equals(this.getName())) {
// rename package;
boolean success = this.renamePackage(modelPack.getName());
if (! success)
throw new PyUMLSynchronizeCodeException();
// folder has changed -> return "true" to start from beginning
return true;
}
// iterate over child elements of model
globalLoop:
for (Element modelChild:modelElement.getOwnedElements()) {
//child package found
if (modelChild instanceof Package) {
Package modelChildPack = (Package) modelChild;
// get xmi_id of model element
String xmi_id = modelXmiDict.get(modelChildPack);
if (xmiPackDict.containsKey(xmi_id)) {
// this package is present in model
// now we have to check it is also child of this package and
// recurse over child elements.
PythonTreePackage pyPack = xmiPackDict.get(xmi_id);
if (this.getChildPackages().contains(pyPack)) {
// child is Okay!
boolean startNew = pyPack.synchronizeCode(modelChildPack);
if (startNew) return true;
} else {
// move package to this package
IPath newPath = EclipseHelperMethods.createFolder(this.getPackageDir().append(pyPack.name).toOSString(), this.getProject()).getFullPath();
boolean success = pyPack.movePackage(newPath);
if (success)
// now the package is moved, start from the beginning
return true;
else
throw new PyUMLSynchronizeCodeException();
}
} else {
// xmi_id not found -> look for package with same name!
boolean packageFound = false;
for (PythonTreePackage pySubPack : this.getChildPackages()) {
if (pySubPack.getName().equals(modelChildPack.getName())){
// write xmi_id to code (only needed once)
pySubPack.writeXmiID(xmi_id);
boolean startNew = pySubPack.synchronizeCode(modelChildPack);
if (startNew) return true;
packageFound=true;
break;
}
}
// if this package was not found, create it (recursively)!
if (! packageFound) {
// create package
IPath newPackPath = getPackageDir().append(modelChildPack.getName());
File newPackDir = new File(newPackPath.toOSString());
newPackDir.mkdir();
EclipseHelperMethods.updateFolder(newPackDir.getAbsolutePath(), this.getProject());
File initPy = new File(newPackPath.append("__init__.py").toOSString());
try{
initPy.createNewFile();
EclipseHelperMethods.updateFile(initPy.getAbsolutePath(), this.getProject());
}
catch (IOException e) {
MessageDialog.openError(null, "IOException", "Error writing to file "+ initPy.getPath());
throw new PyUMLSynchronizeCodeException();
}
PythonTreePackage newPyPack=null;
try{
newPyPack = new PythonTreePackage(newPackPath, this);
}
catch (PyUMLParseException e){
e.printStackTrace();
}
newPyPack.writeXmiID(xmi_id);
this.childPackages.add(newPyPack);
boolean startNew = newPyPack.synchronizeCode(modelChildPack);
if (startNew) return true;
}
}
}
// handle child classes in model
else if (modelChild instanceof Class || modelChild instanceof Interface) {
Classifier modelChildClass = (Classifier) modelChild;
/* only classes in packages are supported. If we find a top-level-class,
* exit with warning! */
if (isRoot()) {
MessageDialog.openWarning(null, "Error: Top level class detected!",
"Please use in model and code *only* classes inside packages!\n" +
"The class was: " + modelChildClass.getName());
continue globalLoop;
}
this.getRoot().worked(this.getName() + "/" + modelChildClass.getName());
this.getRoot().setSubTaskName(this.getName() + "/" + modelChildClass.getName());
String xmi_id = modelXmiDict.get(modelChildClass);
// look for class with this xmi_id
if (xmiClassDict.containsKey(xmi_id)) {
PythonTreeClass pyClass = xmiClassDict.get(xmi_id);
// if the class is already child of this package
if (this.getChildClasses().contains(pyClass)) {
// continue with children in model+code
boolean startNew = pyClass.synchronizeCode(modelChildClass);
while (startNew) {
try {
pyClass.getInFile().reInitFile();
startNew = this.synchronizeCode(modelElement);
if (PythonTreePackage.completeNewStart) {
PythonTreePackage.completeNewStart = false;
return true;
}
} catch (PyUMLParseException e) {
String message = "After changing the code parsing the " +
"changed code failed!\n" +
"Error was:\n" +
e.getMessage();
e.printStackTrace();
throw new PyUMLSynchronizeCodeException(message);
}
}
} else {
// move class to this package;
IPath newPath = this.getPackageDir().append(pyClass.name);
boolean success = pyClass.moveClass(newPath);
if (success)
// now the class is moved, start from the beginning
return true;
else
throw new PyUMLSynchronizeCodeException("Class could not be moved.");
}
} else {
// no class with this xmi_id found!
// look for python child class with same name
// and write the right xmi_id
boolean classFound = false;
for (PythonTreeClass pySubClass : this.getChildClasses()) {
if (pySubClass.getName().equals(modelChildClass.getName())){
classFound = true;
// write xmi_id to code (only needed once)
pySubClass.writeXmiID(xmi_id);
// restart hole process
setChanged(pySubClass.astNode.beginLine);
try {
pySubClass.getInFile().reInitFile();
this.synchronizeCode(modelElement);
} catch (PyUMLParseException e) {
String message = "After changing the code parsing the " +
"changed code failed!\n" +
"Error was:\n" +
e.getMessage();
e.printStackTrace();
throw new PyUMLSynchronizeCodeException(message);
}
break;
}
}
if (! classFound) {
// if this class was not found, create it (recursively)!
boolean success = PythonTreeClass.createNewClass(modelChildClass, this);
if (success) {
File newClassFile = new File(this.getPackageDir().append(modelChildClass.getName()).toOSString() + ".py");
try {
PythonTreeFile newPyFile = new PythonTreeFile(Path.fromOSString(newClassFile.toString()), this);
this.childClasses.addAll(newPyFile.getClassesInFile());
this.synchronizeCode(modelElement);
break globalLoop;
} catch (PyUMLParseException e) {
throw new PyUMLSynchronizeCodeException(
"Error: The newly created class" + newClassFile +
"\ncannot be parsed!\n" +
"Synchronizing Code cannot continue!\n" +
"Message was:\n" +
e.getClass().getName()+"\n"+e.getMessage());
}
//OK, class was created!
} else {
throw new PyUMLSynchronizeCodeException("Error creating class: "+modelChildClass.getName());
}
}
}
}
}
return false;
}
/**
* Move this package in the python code to another package/folder
* * Rename the package directory
* * TODO: Update references
*
* @param newPath the IPath where the package is to be moved
* @return true on success, false if package already exists
*/
public boolean movePackage(IPath newPath) {
IFolder packDir = EclipseHelperMethods.createFolder(this.getPackageDir().toOSString(), this.getProject());
if (! packDir.exists()) {
MessageDialog.openError(null, "Error moving package", "Package " + this.name + " cannot " +
"be renamed\n because it does not seem to exist!");
return false;
}
try {
packDir.move(newPath, true, null);
} catch (CoreException e) {
MessageDialog.openError(null, "Error moving package", "The package " +this.name+ " cannot" +
" be moved to "+ newPath +".\n Propably a package with the new name already exists!" +
"\n\nReason:\n" +e.getMessage());
return false;
}
return true;
}
/**
* Rename this package in the python code
* * Rename the package directory
* * TODO: Update references
*
* @param newName the new name of the package in the same directory
* @return true on success, false if package already exists
*/
public boolean renamePackage(String newName) {
IFolder packDir = EclipseHelperMethods.createFolder(this.getPackageDir().toOSString(), this.getProject());
IPath newPath = packDir.getFullPath().removeLastSegments(1).append(newName);
return this.movePackage(newPath);
}
/**
* Submits the position of current code change to PythonTreeRoot
* so that it can decide if the same line is changed again
* and again and thus detect an unfinished loop.
*
* @param line the changed line in the file
*/
private void setChanged(int line) throws PyUMLSynchronizeCodeException{
this.getRoot().setChangedFileLine(this.packageDir+":"+line);
}
/**
* Puts a new Package as a child beneath this package.
* @param pack
*/
public void addChildPackage(PythonTreePackage pack) {
childPackages.add(pack);
}
/**
* returns all child Packages
*/
public List<PythonTreePackage> getChildPackages() {
return this.childPackages;
}
/**
* returns all child classes (as PythonTreeClass)
* @return
*/
public List<PythonTreeClass> getChildClasses() {
return childClasses;
}
/**
* @return __init__.py file of this package
*/
public PythonTreeFile getInitPy() {
return initPy;
}
public IPath getPackageDir() {
return packageDir;
}
/**
* gets the parent package of this package,
* null if the parent package is root
*/
public PythonTreePackage getParent() {
return (PythonTreePackage) super.getParent();
}
}

View File

@ -0,0 +1,529 @@
package pyUML.pythonTree;
import java.io.File;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Generalization;
import org.eclipse.uml2.uml.Model;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Relationship;
import pyUML.backend.EclipseHelperMethods;
import pyUML.backend.JavaHelperMethods;
import pyUML.exceptions.PyUMLCancelledException;
import pyUML.exceptions.PyUMLParseException;
import pyUML.exceptions.PyUMLSynchronizeCodeException;
/**
* This class is the root of the Python Syntax Tree
* it represents the parent directory of the uppermost
* package in the python package structure.
*
* If the Project directory is already a package
* (contains __init__.py), then this class will
* contain a Package representing the own directory
* as child.
*
* Typically, this represents the "src" directory
* of the eclipse project.
*
* The root node corresponds with the "model" node of the UML diagram.
*
*/
public class PythonTreeRoot extends PythonTreePackage{
private IProject project;
private Set<IPath> srcPaths;
private Map<String, PythonTreePackage> xmiPackDict;
private Map<String, PythonTreeClass> xmiClassDict;
private Map<String, PythonTreeClass> classDict;
private Map<String, String> classNameDict;
private List<String> renamedClasses;
// Attributes needed for model synchronization
private Map<String, EObject> xmiModelDict;
private Map<EObject, String> modelXmiDict;
private Map<String, EObject> xmiModelDictOld;
private List<NamedElement> modelElementsToDestroy;
private List<String> changedFileLines;
private boolean createNewModel = false;
private boolean showWarnings = true;
private IProgressMonitor monitor;
private List<String> progressFinishedItems;
/**
* createNewModel is true, if a user decided to create a new model,
* even though a model former existed and was obviously deleted
* or edited outside PyUML
* initially, createNewModel is false, and if a former model is detected,
* the user is asked
* @return the current value of is CreateNewModel
*/
public boolean isCreateNewModel() {
return createNewModel;
}
/**
* if a user decided to create a new model,
* even though a model former existed and was obviously deleted
* or edited outside PyUML, this decision can be saved here so that
* the user is asked only once
* @param createNewModel -> true, if the user decided to re-create the model
*/
public void setCreateNewModel(boolean createNewModel) {
this.createNewModel = createNewModel;
}
/**
* sets the last changed line on synchronizing code.
*
* Background:
* on synchronizing code, after every change the whole code is re-read
* an synchronizing started from beginning, until there are no more changes.
* The danger is that the program runs in an endless loop, e.g. if changes
* are not sufficient (this should NOT happen normally)
* To detect this situation, the line of the last change in code is saved;
* if this line does not change for many times, we detect a dead loop
* and break it with an error message
*
* @param changedFileLine a line, typically representing the changed line
* in code. It can also hold a package/file path etc.
* It must always be the same for the same operation!
*/
public void setChangedFileLine(String changedFileLine) throws PyUMLSynchronizeCodeException{
if (this.changedFileLines.size() == 0){
this.changedFileLines.add(changedFileLine);
return;
}
if (this.changedFileLines.get(this.changedFileLines.size()-1).equals(changedFileLine)) {
this.changedFileLines.add(changedFileLine);
} else {
this.changedFileLines.clear();
this.changedFileLines.add(changedFileLine);
}
if (this.changedFileLines.size() > 20) {
String message = "Error: Synchronize Code runs in an unfinished loop!\n\n" +
"The loop is in the File/Line\n" + changedFileLine;
throw new PyUMLSynchronizeCodeException(message);
}
}
/**
*
* @param project the eclipse IProject
* @param showWarnings if true, warnings (e.g. duplicate classes) are shown
* this is typically done only on the first run, if there are several runs
*/
public PythonTreeRoot(IProject project, boolean showWarnings, IProgressMonitor monitor) throws PyUMLParseException, PyUMLCancelledException{
super(null, null);
this.project = project;
this.showWarnings = showWarnings;
this.monitor = monitor;
this.srcPaths = EclipseHelperMethods.getPythonSrcDirs(project);
// first Source dir is standard dir -> all new packages will be
// created here!
this.packageDir = this.srcPaths.iterator().next();
int numPackages=JavaHelperMethods.getFileCount(this.packageDir.toFile(), "^.*.py$");
this.beginTask("Analyze Python Code", numPackages);
initRoot();
}
/**
* On object Creation, this initializes the root of the python
* code representationS
* @throws PyUMLParseException
*/
private void initRoot() throws PyUMLParseException, PyUMLCancelledException{
// initialize name and xmi_id dictionaries
this.xmiPackDict = new Hashtable<String, PythonTreePackage>();
this.xmiClassDict = new Hashtable<String, PythonTreeClass>();
this.classDict = new Hashtable<String, PythonTreeClass>();
this.classNameDict = new Hashtable<String, String>();
// set the Tree name (= project name = model name)
this.name = this.project.getName();
// iterate over all source paths: find uppermost package(s)
// and append it to this root node.
for (IPath path : this.srcPaths) {
File srcDir = new File(path.toOSString());
if (! srcDir.isDirectory())
continue;
// check if dir is already package.
// if yes, add it
// if no, check all child dirs (until packages were found)
List<File> checkPackDirs = new Vector<File>();
checkPackDirs.add(srcDir);
while(checkPackDirs.size() > 0) { //take the next subdir
File dir = checkPackDirs.get(0);
checkPackDirs.remove(dir);
// list dir
File[] dirList = dir.listFiles();
boolean isPackage=false;
List<File> childDirList =new Vector<File>();
// look for child directories or "__init__.py"
for (File entry:dirList) {
if (entry.isDirectory())
childDirList.add(entry);
else if (entry.getName().equals("__init__.py"))
isPackage=true;
}
// if this dir is a package, initialize a new PythonTreePackage
if (isPackage)
this.addChildPackage(
new PythonTreePackage(
new Path(dir.getAbsolutePath()), this));
else
checkPackDirs.addAll(childDirList);
}
}
}
/**
* For a given model (it can be empty), synchronize the Model
* with the code represented by this PythonTreeNode
* use xmi_id for identifying moved Packages
*
* @param model
* @param xmiModelDict
* @return true on success, false on Errors (Model must not be saved)
*/
public boolean synchronizeModel(Model model, Map<String, EObject> xmiModelDict) throws PyUMLCancelledException{
// set name of model (e.g. when newly created
if (! model.getName().equals(this.name))
model.setName(this.name);
this.xmiModelDict = xmiModelDict;
this.modelElementsToDestroy = new Vector<NamedElement>();
boolean success = super.synchronizeModel(model);
if (! success)
return false;
// create Generalizations
this.createModelGeneralizations(model);
// delete elements not present in model any more
for (NamedElement elementToDestroy : this.modelElementsToDestroy) {
// destroy all relationships
Vector<Relationship> rels = new Vector<Relationship>();
for (Relationship rel : elementToDestroy.getRelationships())
rels.add(rel);
for (Relationship rel : rels)
rel.destroy();
elementToDestroy.destroy();
}
return true;
}
/**
* after synchronizeModel was run, this method creates all generals
* in the model. That can be done only *after* the model synchronized,
* to ensure all classes are present in the model.
* @param model
*/
public void createModelGeneralizations(Model model) {
for (PythonTreeClass pyClass : classDict.values()) {
// get model class of this class
Classifier modelClass = (Classifier) pyClass.getAssociatedModelElement();
// get all model superclasses for this class
List<Generalization> modelGenerals = modelClass.getGeneralizations();
Map<Classifier, Generalization> modelSuperClasses =
new Hashtable<Classifier, Generalization>();
for (Generalization gen : modelGenerals) {
if (gen.getGeneral() != null)
modelSuperClasses.put(gen.getGeneral(), gen);
}
// get list of superclasses in python code
Set<PythonTreeClass> pySuperClasses = pyClass.getGeneralizationsInProject();
// ensure all python superclasses are in model
for (PythonTreeClass pySuperClass : pySuperClasses) {
if (! modelSuperClasses.containsKey((Classifier)pySuperClass.getAssociatedModelElement())) {
modelClass.createGeneralization(
(Classifier)pySuperClass.getAssociatedModelElement());
}
}
// ensure all model superclasses are present in python.
// if not, delete model superclass
List<Generalization> modelGeneralList = new Vector<Generalization>();
modelGeneralList.addAll(modelGenerals);
for (Generalization modelGen : modelGeneralList) {
Classifier modelSuperClass = modelGen.getGeneral();
if (modelSuperClass == null) {
modelGen.destroy();
continue;
}
// if no class with the Generalization exists
if (! this.getClassDict().containsKey(this.getModelPackageStructure(modelSuperClass) + modelSuperClass.getName())) {
// destroy generalization
modelGen.destroy();
} else {
PythonTreeClass pySuperClass = this.getClassDict().get(this.getModelPackageStructure(modelSuperClass) + modelSuperClass.getName());
// if Superclass exists, but is no superclass
if (! pySuperClasses.contains(pySuperClass)) {
// destroy all relationships
Vector<Relationship> rels = new Vector<Relationship>();
for (Relationship rel : modelSuperClasses.get(modelSuperClass).getRelationships())
rels.add(rel);
for (Relationship rel : rels)
rel.destroy();
// destroy superclass
modelSuperClasses.get(modelSuperClass).destroy();
}
}
//otherwise: everything is OK
}
}
}
/**
*
* @param modelElement
* @param modelXmiDict
* @param xmiModelDictOld
* @param monitor
* @param classCount the number of classes in model - optional parameter for progress bar
* @return
*/
public boolean synchronizeCode(NamedElement modelElement, Map<EObject,
String> modelXmiDict, Map<String, EObject> xmiModelDictOld,
IProgressMonitor monitor, int classCount)
throws PyUMLCancelledException{
this.monitor = monitor;
this.modelXmiDict = modelXmiDict;
this.xmiModelDictOld = xmiModelDictOld;
this.renamedClasses = new Vector<String>();
this.showWarnings = false;
this.changedFileLines = new Vector<String>();
this.progressFinishedItems = new Vector<String>();
this.beginTask("Synchronize Code by Model", classCount);
// synchronize until no more changes were found (synchronize returns false)
try {
while(super.synchronizeCode(modelElement)) {
// if synchronizeCode returned true, it just changed the code!
// -> Re-read the code and start from the beginning
this.initRoot();
this.beginTask("Synchronize Code by Model", classCount*2);
}
// finally, do a second sync run to ensure all newly
// created classes can be used in import statements
super.synchronizeCode(modelElement);
} catch (PyUMLSynchronizeCodeException e) {
e.printStackTrace();
MessageDialog.openError(null, "An Exception happened while synchronizing code",
"An Exception happened while synchronizing code.\n" +
"Message was: \n\n" + e.getMessage());
return false;
} catch (PyUMLParseException e) {
e.printStackTrace();
MessageDialog.openError(null, "An Exception happened while synchronizing code",
"Obviously, while synchronizing code a python syntax error was\n" +
"created. This should not happen!\n" +
"Please resolve the problem manually!\n\n" +
"Message was: \n" + e.getMessage());
return false;
}
return true;
}
public boolean isRoot() {
return true;
}
/**
* returns a dictionary of all class names with their corresponding
* PythonTreeClass
* @return
*/
public Map<String, PythonTreeClass> getClassDict() {
return classDict;
}
/**
* returns the XMI-ID <-> PythonTreePackage dictionary with XMI-IDs as keys
* @return
*/
public Map<String, PythonTreePackage> getXmiPackDict() {
return xmiPackDict;
}
/**
* returns the XMI-ID <-> PythonTreeClass dictionary with XMI-IDs as keys
* @return
*/
public Map<String, PythonTreeClass> getXmiClassDict() {
return xmiClassDict;
}
/**
* returns the XMI-ID <-> model dictionary with XMI-IDs as keys
* @return
*/
public Map<String, EObject> getXmiModelDict() {
return xmiModelDict;
}
/**
* returns the XMI-ID <-> model dictionary with model elements as keys
* @return
*/
public Map<EObject, String> getModelXmiDict() {
return modelXmiDict;
}
/**
* Like PythonTreeClass.getPackageStructure(), this
* generates a string with the Package structure containing
* a class, like "/supPack/subPack/"
* @param c The model class to use
* @return the parent package structure as a String
*/
public String getModelPackageStructure(Classifier c) {
Package parent = c.getPackage();
String structure = "";
do {
structure = "/"+parent.getName() + structure;
parent = parent.getNestingPackage();
} while (! (parent instanceof Model));
return structure + "/";
}
/**
* Proxy method. Runs beginTask, if there is a monitor,
* does nothing, otherwise
* @param name The name of the task to start
* @param totalWork The number of task steps to display
*/
public void beginTask(String name, int totalWork) {
if (this.monitor != null)
this.monitor.beginTask(name, totalWork);
}
/**
* Completes a sub-step in the progress monitor,
* if any.
*/
public void worked() throws PyUMLCancelledException {
if (this.monitor.isCanceled())
throw new PyUMLCancelledException();
if (this.monitor != null) {
monitor.worked(1);
}
// update UI
while (Display.getCurrent().readAndDispatch())
;
}
/**
* Sets the name of the current task in the progress monitor
* @param name
* @throws PyUMLCancelledException
*/
public void setSubTaskName(String name) throws PyUMLCancelledException{
if (this.monitor.isCanceled())
throw new PyUMLCancelledException();
if (this.monitor != null) {
monitor.subTask(name);
}
// update UI
while (Display.getCurrent().readAndDispatch())
;
}
/**
* like worked(), this additionally has the possibility to
* put an item name of the finished item, so that
* the progress bar will only be updated the first time an item is
* finished.
* This is useful for a progress bar with recursive sync calls
* @param itemName the name of the finished item
*/
public void worked(String itemName) throws PyUMLCancelledException{
if (! this.progressFinishedItems.contains(itemName)) {
this.progressFinishedItems.add(itemName);
this.worked();
}
}
public void setMonitor(IProgressMonitor monitor) {
this.monitor = monitor;
}
/**
* returns the list of model elements that are to be removed from
* the model after synchronizing.
* This has to be done as the last step of the sync process
* so that no concurrent modification is done on the model.
* @return
*/
public List<NamedElement> getModelElementsToDestroy() {
return modelElementsToDestroy;
}
/**
* Overwrites the method fromPythonTreePackage
* -> On a renaming of the model root nothing is to be done!
* @param newName
*/
public boolean renamePackage(String newName) {
return true;
}
public Map<String, EObject> getXmiModelDictOld() {
return xmiModelDictOld;
}
public IProject getProject() {
return project;
}
public List<String> getRenamedClasses() {
return renamedClasses;
}
public boolean isShowWarnings() {
return showWarnings;
}
public Map<String, String> getClassNameDict() {
return classNameDict;
}
}

View File

@ -0,0 +1,136 @@
package pyUML.refactoring;
import java.io.IOException;
import java.net.URLDecoder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.MessageDialog;
import org.python.copiedfromeclipsesrc.JDTNotAvailableException;
import org.python.pydev.core.IPythonNature;
import org.python.pydev.core.IPythonPathNature;
import org.python.pydev.core.MisconfigurationException;
import org.python.pydev.core.PythonNatureWithoutProjectException;
import org.python.pydev.core.REF;
import org.python.pydev.editor.codecompletion.shell.AbstractShell;
import org.python.pydev.editor.codecompletion.shell.PythonShell;
import org.python.pydev.editor.refactoring.AbstractPyRefactoring;
import org.python.pydev.editor.refactoring.IPyRefactoring;
import org.python.pydev.plugin.nature.PythonNature;
import org.python.pydev.plugin.nature.PythonPathNature;
import pyUML.exceptions.PyUMLSynchronizeCodeException;
import pyUML.pythonTree.PythonTreeFile;
/**
* Helper class to use the Python pyUML.refactoring functionality
* provided by "Bicycle Repair Man", written in Python
* as used by PyDev
*/
public class BicycleRefactoring {
/**
* This is the generic refactor command using bicycle pyUML.refactoring.
* Is is used by specializes pyUML.refactoring methods
*
* @param refactorCommand - the String with the pyUML.refactoring to be done
* @param conditionalMethod - the name of the pyUML.refactoring method
* @param project - the current project
* @return true on success, false on error
*/
public static boolean doGenericBikeRefactoring(String refactorCommand, String conditionalMethod, IProject project) throws PyUMLSynchronizeCodeException{
IPyRefactoring pyRefactoring = AbstractPyRefactoring.getPyRefactoring();
IPythonNature pythonNature = PythonNature.getPythonNature(project);
try {
if ((Boolean) REF.invoke(pyRefactoring, conditionalMethod, new Object[0])) {
AbstractShell pytonShell = AbstractShell.getServerShell(pythonNature, AbstractShell.OTHERS_SHELL);
String output = "";
try{
IPythonPathNature n = pythonNature.getPythonPathNature();
pytonShell.changePythonPath(pythonNature.getPythonPathNature().getCompleteProjectPythonPath(pythonNature.getProjectInterpreter(), null)); //default
pytonShell.write(refactorCommand);
output = URLDecoder.decode(pytonShell.read((IProgressMonitor)null), "UTF-8");
} catch (Exception e) {
output = "ERROR: "+e.getClass().getName()+"\n";
e.printStackTrace();
pytonShell.restartShell();
}
if (output.startsWith("ERROR:")) {
String errmsg = output.substring(0, output.indexOf('\n'));
pytonShell.restartShell();
MessageDialog.openError(null, "Error on pyUML.refactoring using Bike!" ,
"There was a pyUML.refactoring error using the Bicycle Repair Man Browser\n" +
"The command was: "+refactorCommand
+"\nThe error was: "+errmsg);
return false;
}
} else {
throw new PyUMLSynchronizeCodeException("Error on pyUML.refactoring using Bike!\n\n" +
"pyRefactoring is not available!");
}
}catch (CoreException e) {
throw new PyUMLSynchronizeCodeException("CoreException on pyUML.refactoring using Bike!\n\n" +
e.getMessage());
}catch (IOException e) {
throw new PyUMLSynchronizeCodeException("IOException on pyUML.refactoring using Bike!\n\n" +
e.getMessage());
} catch (JDTNotAvailableException e) {
throw new PyUMLSynchronizeCodeException("JDTNotAvailableException on pyUML.refactoring using Bike!\n\n" +
e.getMessage());
} catch (MisconfigurationException e) {
throw new PyUMLSynchronizeCodeException("PyUMLSynchronizeCodeException on pyUML.refactoring using Bike!\n\n" +
e.getMessage());
} catch (PythonNatureWithoutProjectException e) {
throw new PyUMLSynchronizeCodeException("PythonNatureWithoutProjectException on pyUML.refactoring using Bike!\n\n" +
e.getMessage());
}
return true;
}
/**
* DO a 'rename' Refactoring. This is for class / method renaming
*
* @param filePath the Path of the file to edit
* (other files may be affected as well)
* (use File.toOSString() to get this Path string)
* @param newName the new Name of the object
* @param line the line of the object
* @param col the column of the object
* @param project the current project
* @return true on success, false otherwise.
*/
public static boolean doRenameObject(PythonTreeFile file, String newName, int line, int col, IProject project) throws PyUMLSynchronizeCodeException{
String filePath = file.getFilePath().toOSString();
// make sure the line to change is not the last line in file
// -> then bike will fail!
if (line == file.getFileContent().split("\n").length ) {
// insert line and start again
FileRefactoring.appendToFile(file, " ");
file.getRoot().setChangedFileLine(filePath+":"+line);
return true;
}
String command = "@@BIKE";
command+= "renameByCoordinates";
command+= "|"+filePath;
command+= "|"+line;
command+= "|"+(col-1);
command+= "|"+newName;
command+= "END@@";
String conditionalMethod = "canRename";
boolean success = doGenericBikeRefactoring(command, conditionalMethod, project);
file.updateFileInEclipse();
return success;
}
}

View File

@ -0,0 +1,161 @@
package pyUML.refactoring;
import java.io.File;
import pyUML.backend.ParseHelpers;
import pyUML.pythonTree.PythonTreeFile;
/**
* Some convenience methods for modifying/writing files
*/
public class FileRefactoring {
/**
* replaces a string in a file from a given line/col
* deletes the file from that position unto
*
* @param pyFile the python file to edit
* @param startLine the line, from which the replace should begin
* @param startCol the column, from which the replace should begin
* @param newString the new String to replace the deleted with
* @param endMarker the char/string, unto the file content is replaces
* @param reInit if true, a reInit() is called on the python file after finishing
* @return
*/
public static boolean replaceFromCoordinate(PythonTreeFile pyFile, int startLine, int startCol, String newString, String endMarker, boolean reInit){
String content = pyFile.getFileContent();
int lineIndex = 0;
for (int i=1; i<startLine; i++) {
lineIndex = content.indexOf('\n' ,lineIndex)+1;
}
int startIndex = lineIndex + startCol -1;
int endIndex = content.indexOf(endMarker, startIndex);
String newContent = content.substring(0, startIndex) + newString + content.substring(endIndex);
ParseHelpers.stringToFile(new File(pyFile.getFilePath().toOSString()), newContent, pyFile.getProject());
pyFile.setFileContent(newContent);
return true;
}
/**
* inserts the given string at the beginning of the given line
*
* @param pyFile
* @param insertLine
* @param newString
* @return success
*/
public static boolean insertAtLine(PythonTreeFile pyFile, int insertLine, String newString){
String content = pyFile.getFileContent();
int lineIndex = 0;
for (int i=1; i<insertLine; i++) {
lineIndex = content.indexOf('\n' ,lineIndex)+1;
}
String newContent = content.substring(0, lineIndex) + newString + content.substring(lineIndex);
ParseHelpers.stringToFile(new File(pyFile.getFilePath().toOSString()), newContent, pyFile.getProject());
pyFile.setFileContent(newContent);
return true;
}
/**
* completely replace a given line in a python file
* @param pyFile
* @param lineNo
* @param newString
* @param writeToFile if true, the changes are directly written to the python file
* @return the String with the replaced line
*/
public static String replaceLine(PythonTreeFile pyFile, int lineNo, String newString, boolean writeToFile) {
String content = pyFile.getFileContent();
int lineIndex = 0;
for (int i=1; i<lineNo; i++) {
lineIndex = content.indexOf('\n' ,lineIndex)+1;
}
int lineIndexAfter = content.indexOf('\n' ,lineIndex);
String contentBefore = content.substring(0, lineIndex);
String newContent = contentBefore + newString;
if (lineIndexAfter > lineIndex) {
String contentAfter = content.substring(lineIndexAfter);
newContent += contentAfter;
}
if (writeToFile) {
ParseHelpers.stringToFile(new File(pyFile.getFilePath().toOSString()), newContent, pyFile.getProject());
pyFile.updateFileInEclipse();
}
pyFile.setFileContent(newContent);
return newContent;
}
/**
* completely removes a given line in a python file
* @param pyFile
* @param lineNo The lineNo to deletes
* @param writeToFile if true, the changes are directly written to the python file
* @param onlyIfNotEmpty if true, only a non-empty-line is deleted (to preserve file design)
* @return the String with the replaced line
*/
public static String removeLine(PythonTreeFile pyFile, int lineNo, boolean writeToFile, boolean onlyIfNotEmpty) {
String content = pyFile.getFileContent();
int lineIndex = 0;
for (int i=1; i<lineNo+1; i++) {
lineIndex = content.indexOf('\n' ,lineIndex)+1;
}
int lineIndexAfter = content.indexOf('\n' ,lineIndex)+1;
String contentBefore = content.substring(0, lineIndex);
String newContent = contentBefore;
if (lineIndexAfter > lineIndex) {
String contentAfter = content.substring(lineIndexAfter);
newContent += contentAfter;
}
if (onlyIfNotEmpty) {
String lineToDelete = content.substring(lineIndex+1, lineIndexAfter );
if (lineToDelete.matches("[\\s]*"))
return content;
}
if (writeToFile) {
ParseHelpers.stringToFile(new File(pyFile.getFilePath().toOSString()), newContent, pyFile.getProject());
pyFile.updateFileInEclipse();
}
pyFile.setFileContent(newContent);
return newContent;
}
/**
* Appends a String to a PythonTreeFile and saves the file on disk
* @param pyFile
* @param stringToAppend
* @return
*/
public static boolean appendToFile(PythonTreeFile pyFile, String stringToAppend) {
String content = pyFile.getFileContent();
String newContent = content + stringToAppend;
ParseHelpers.stringToFile(new File(pyFile.getFilePath().toOSString()), newContent, pyFile.getProject());
pyFile.updateFileInEclipse();
pyFile.setFileContent(newContent);
return true;
}
/**
* Returns the line with the given line number
* for this file. Line numbers start with 1, not with 0
* @param pyFile the PythonTreeFile which represents the file
* @param lineNo the lineNumber
* @return The searched line as a string, null if lineNo is
* not in index.
*/
public static String getLine(PythonTreeFile pyFile, int lineNo) {
String[] splittedFileContent = pyFile.getSplittedFileContent();
if (lineNo <= 0)
return null;
if (lineNo > splittedFileContent.length)
return null;
return splittedFileContent[lineNo - 1];
}
}

View File

@ -0,0 +1,63 @@
package pyUML.views;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.uml2.uml.Model;
import org.eclipse.uml2.uml.resource.UMLResource;
import pyUML.backend.GlobalConstants;
/**
* This edits a given view for a project.
* It loads the view configuration and calls EditViewWizard
*/
public class EditView{
private EditViewWizard editViewWizard;
public EditView(IProject project, IFile confFile, String viewName, boolean open) {
try{
String umlModelFileName=project.getLocation().
append(GlobalConstants.getPyUmlDir()).
append(project.getName()+".uml").toOSString();
EObject diagramRoot = null;
try {
Resource resource = new ResourceSetImpl().getResource(URI.createFileURI(umlModelFileName), true);
diagramRoot = (EObject) resource.getContents().get(0);
} catch (WrappedException ex) {
MessageDialog.openError(null,ex.getMessage(),"Unable to load model: " + umlModelFileName);
return;
}
UMLResource res = (UMLResource) diagramRoot.eResource();
Map<EObject, String> modelXmiDict = res.getEObjectToIDMap();
Model model = (Model) diagramRoot;
editViewWizard = new EditViewWizard(null, model, res, project, confFile, viewName, modelXmiDict);
WizardDialog dialog = new WizardDialog(null, editViewWizard);
if (open)
dialog.open();
else
dialog.create();
}catch (Throwable t) {
MessageDialog.openError(null,t.getMessage(),"Error Managing Views:"+t.getMessage());
t.printStackTrace();
}
}
public EditViewWizard getEditViewWizard() {
return editViewWizard;
}
}

View File

@ -0,0 +1,437 @@
package pyUML.views;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.wizard.IWizard;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IEditorPart;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Generalization;
import org.eclipse.uml2.uml.Model;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Relationship;
import org.eclipse.uml2.uml.Type;
import org.eclipse.uml2.uml.resource.UMLResource;
import pyUML.backend.EclipseHelperMethods;
import pyUML.backend.GlobalConstants;
import pyUML.backend.UMLToolsHelperMethods;
import pyUML.listeners.ViewChangeListener;
/**
* This wizard lets the user edit a view. Classes
* and Packages can be selected; super- or child classes
* can be used creating a view.
*/
public class EditViewWizard extends Wizard implements IWizard{
private Model model;
private UMLResource resource;
private IProject project;
private IFile confFile;
private String viewName;
private SelectViewElementsPage partsPage;
private List<String> usedXmiIds;
private boolean includeSuperClasses=false;
private boolean includeSubClasses=false;
private Map<EObject, String> modelXmiDict;
private List<Element> nodeToDeleteList;
private List<Element> usedModelElements;
public EditViewWizard(Shell parentShell, Model model, UMLResource resource, IProject project, IFile confFile, String viewName, Map<EObject, String>modelXmiDict) {
super();
this.model = model;
this.resource = resource;
this.project = project;
this.confFile = confFile;
this.viewName = viewName;
this.modelXmiDict = modelXmiDict;
this.usedModelElements = new Vector<Element>();
this.setWindowTitle("Create UML View");
this.readConfFile();
}
@Override
public void addPages() {
this.partsPage = new SelectViewElementsPage("Select Model Elements for this View",
this.model, this.usedXmiIds, this.modelXmiDict, this.viewName,
this.includeSuperClasses, this.includeSubClasses);
addPage(partsPage);
}
/**
* Reads the CONF file of this view (e.g. used classes+packages)
*/
public void readConfFile(){
this.usedXmiIds = new Vector<String>();
String[] confContent = EclipseHelperMethods.iFileToString(confFile).split("\n");
boolean xmiSectionFound=false;
for (String line:confContent) {
if(xmiSectionFound) {
this.usedXmiIds.add(line);
}
if (line.matches("CONF_INCLUDE_SUPERCLASSES:.*")) {
this.includeSuperClasses=
line.replaceAll("CONF_INCLUDE_SUPERCLASSES:", "")
.equals("TRUE");
}
if (line.matches("CONF_INCLUDE_SUBCLASSES:.*")) {
this.includeSubClasses=
line.replaceAll("CONF_INCLUDE_SUBCLASSES:", "")
.equals("TRUE");
}
if (line.matches("XMI_SECTION"))
xmiSectionFound=true;
}
}
@Override
public boolean performFinish() {
return performFinish(true);
}
/**
*
* @param openAfterFinish if true, the created view will be
* opened immediately
* @return true on success
*/
public boolean performFinish(boolean openAfterFinish) {
//generate new model as part of old one
String oldViewName = viewName;
String viewName = this.viewName;
if (this.partsPage.viewNameField != null)
viewName = this.partsPage.getViewNameField().getText();
IFile umlFile = this.project.getWorkspace().getRoot()
.getFile(this.project.getFullPath()
.append(GlobalConstants.getPyUmlDir())
.append(oldViewName+GlobalConstants.getViewUmlExtension()));
IFile diagramFile = this.project.getWorkspace().getRoot()
.getFile(this.project.getFullPath()
.append(GlobalConstants.getPyUmlDir())
.append(oldViewName+GlobalConstants.getDiagramExtension()));
boolean editorChangedNameAndWasOpen =true;
// if view name changed, move all files to new name
if (!viewName.equals(oldViewName)) {
// compute new file names with changed view name
IPath newConfFilePath = this.project.getFullPath()
.append(GlobalConstants.getPyUmlDir())
.append(viewName+GlobalConstants.getViewConfExtension());
IPath newViewUmlPath = this.project.getFullPath()
.append(GlobalConstants.getPyUmlDir())
.append(viewName+GlobalConstants.getViewUmlExtension());
IPath newDiagramFilePath = this.project.getFullPath()
.append(GlobalConstants.getPyUmlDir())
.append(viewName+GlobalConstants.getDiagramExtension());
// close editor, if it is open
EclipseHelperMethods.closeEditorByName(project, diagramFile.getName());
editorChangedNameAndWasOpen = true;
try {
// now really move view files
this.confFile.move(newConfFilePath, true, null);
if (umlFile.exists())
umlFile.move(newViewUmlPath, true, null);
if (diagramFile.exists())
diagramFile.move(newDiagramFilePath, true, null);
this.confFile = project.getFile(newConfFilePath.removeFirstSegments(1));
umlFile = project.getFile(newViewUmlPath.removeFirstSegments(1));
diagramFile = project.getFile(newDiagramFilePath.removeFirstSegments(1));
} catch (CoreException e) {
System.out.println("error moving view file to new view name!");
}
}
//model.setName(viewName);
this.nodeToDeleteList = new Vector<Element>();
if (partsPage.viewNameField != null)
this.usedXmiIds= new Vector<String>();
removeUnmarkedNodes(this.model);
List<Classifier> classList;
classList = getClassListFromModel(this.model);
// if "include superclasses" was checked:
// remove all superclasses of selected items from 'classes to remove' list
if (this.partsPage.getButtInclSuperClasses() != null)
this.includeSuperClasses = this.partsPage.getButtInclSuperClasses().getSelection();
if (this.partsPage.getButtInclSubClasses() != null)
this.includeSubClasses = this.partsPage.getButtInclSubClasses().getSelection();
if (includeSuperClasses) {
boolean superClassFound;
do {
superClassFound = false;
for (Classifier cl:classList) {
EList<Generalization> gens = cl.getGeneralizations();
for (Generalization gen : gens) {
if (nodeToDeleteList.contains(gen.getGeneral())
&& (! nodeToDeleteList.contains(cl))) {
nodeToDeleteList.remove(gen.getGeneral());
superClassFound = true;
}
}
}
}
while (superClassFound);
}
// exclude subclasses from nodeToDeleteList for every class in list
// if includeSubClasses was set in gui
if (includeSubClasses) {
boolean subClassFound;
do {
subClassFound = false;
for (Classifier cl:classList) {
for (Relationship rel : cl.getRelationships()) {
if (rel instanceof Generalization) {
Generalization gen = (Generalization) rel;
if (gen.getOwner() == cl)
continue;
if (nodeToDeleteList.contains(gen.getOwner())
&& (! nodeToDeleteList.contains(cl))) {
nodeToDeleteList.remove(gen.getOwner());
subClassFound = true;
}
}
}
}
}
while (subClassFound);
}
List<Type> elList = getPackagedElementsFromModel(this.model);
Package viewPack = model.createNestedPackage("View_"+viewName);
// make model "flat", setting parent of all classes to model root
for(Type el : elList) {
if (! this.nodeToDeleteList.contains(el))
el.setPackage(viewPack);
}
// remove elements in nodeToDeleteList
/*for (Element e:this.nodeToDeleteList) {
e.destroy();
}
*/
/*
//remove all package entries of model
List<Element> packageList = new Vector<Element>();
for (Element e: model.getOwnedElements()) {
if (e instanceof Package) {
packageList.add(e);
}
}
for (Element e: packageList) {
//e.destroy();
}*/
//save new "view"-model
try {
// if model was renamed, rename old model
String umlFileName=project.getLocation().
append(GlobalConstants.getPyUmlDir()).
append(viewName + GlobalConstants.getViewUmlExtension()).toOSString();
resource.setURI(URI.createFileURI(umlFileName));
resource.save(null);
EclipseHelperMethods.updateFile(umlFile);
System.out.println(("Saving view file "+umlFileName+" done."));
} catch (IOException ioe) {
MessageDialog.openError(null,"IOException",
"Error saving uml file: \n" + ioe.getMessage());
}
//save configuration
String confFileContents="CONF_INCLUDE_SUPERCLASSES:"
+( includeSuperClasses ? "TRUE" : "FALSE" ) + "\n";
confFileContents+="CONF_INCLUDE_SUBCLASSES:"
+( includeSubClasses ? "TRUE" : "FALSE" ) + "\n";
confFileContents += "XMI_SECTION\n";
for (String id: this.usedXmiIds) {
confFileContents += id + "\n";
}
EclipseHelperMethods.StringToIFile(confFile, confFileContents);
// create graphical diagram, if it does not already exist
// create diagram, if it does not exist; after creation, open it
// (diagram should not be opened when "edit" was pressed)
if (! diagramFile.exists() || editorChangedNameAndWasOpen) {
// create and open diagram, if it was created as new
if (! diagramFile.exists())
UMLToolsHelperMethods.createModelDiagram(viewPack, diagramFile);
else {
String oldDiagramContent = EclipseHelperMethods.iFileToString(diagramFile);
Pattern pattern = Pattern.compile("(.*<element xmi:type=\"uml:Package\" href=\"file:[^#]*#)([^\"]*)(\"/>.*)");
String viewId = resource.getID(viewPack);
// get old view package id
Matcher matcher = pattern.matcher(oldDiagramContent);
String oldViewId = null;
if (matcher.find()) {
oldViewId = matcher.group(2);
} else
return false;
// replace all old IDs to the new ID
oldDiagramContent = oldDiagramContent.replace(oldViewId, viewId);
EclipseHelperMethods.StringToIFile(diagramFile, oldDiagramContent);
}
if (openAfterFinish)
UMLToolsHelperMethods.openDiagram(project, diagramFile, umlFile.getName() ,true);
} else {
// refresh editor, if it was open
if (null != EclipseHelperMethods.lookForOpenEditorByName(diagramFile.getName())) {
IEditorPart newPage = UMLToolsHelperMethods.refreshDiagramEditor(project, diagramFile, false);
newPage.addPropertyListener(new ViewChangeListener(this.project));
}
}
EclipseHelperMethods.updateFile(diagramFile);
return true;
}
/**
* Recursive Helper method to add the nodes that were not
* selected to the nodeToDeletelist
* If a package node is selected, all children will be selected, implicitely.
* If a package node is not selected, a recursion on the children is started.
* @param node
*/
private void removeUnmarkedNodes(Element node) {
TreeItem assignedItem =this.partsPage.getNodeCheckboxDict().get(node);
if (assignedItem != null && (assignedItem.getChecked()))
this.usedXmiIds.add(this.modelXmiDict.get(node));
if (node instanceof Relationship) {
return;
}
if (node instanceof org.eclipse.uml2.uml.Classifier) {
assignedItem =this.partsPage.getNodeCheckboxDict().get(node);
if (assignedItem == null) {
if (this.usedXmiIds.contains(modelXmiDict.get(node))) {
this.usedModelElements.add(node);
} else {
this.nodeToDeleteList.add(node);
}
}else if (! assignedItem.getChecked()) {
// add node to remove list if it is not marked.
this.nodeToDeleteList.add(node);
return;
} else {
this.usedModelElements.add(node);
this.usedXmiIds.add(this.modelXmiDict.get(node));
}
}
else if (node instanceof Package) {
for (Element childNode : node.getOwnedElements()) {
assignedItem =this.partsPage.getNodeCheckboxDict().get(node);
if (assignedItem == null) {
}
else if (assignedItem.getChecked())
this.usedXmiIds.add(this.modelXmiDict.get(node));
removeUnmarkedNodes(childNode);
}
}
}
/**
* return all classes in model
* @param node
*/
private Vector<Classifier> getClassListFromModel(Element node) {
Vector<Classifier> classList = new Vector<Classifier>();
if (node instanceof Classifier) {
Classifier cl = (Classifier) node;
classList.add(cl);
} else {
EList<Element> children = node.getOwnedElements();
for (Element child : children) {
classList.addAll(getClassListFromModel(child));
}
}
return classList;
}
/**
* get all child elements of a package
* that are Types (direct successors of packages)
*
* @param node The node where the search is to be started
* @return the list of Types
*/
private Vector<Type> getPackagedElementsFromModel(Element node) {
Vector<Type> elList = new Vector<Type>();
if (node instanceof Classifier) {
Classifier cl = (Classifier) node;
elList.add(cl);
elList.addAll(cl.getAssociations());
} else {
EList<Element> children = node.getOwnedElements();
for (Element child : children) {
elList.addAll(getPackagedElementsFromModel(child));
}
}
return elList;
}
public SelectViewElementsPage getPartsPage() {
return partsPage;
}
}

View File

@ -0,0 +1,307 @@
package pyUML.views;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorPart;
import org.eclipse.uml2.uml.Model;
import pyUML.actions.ManageViewsAction;
import pyUML.backend.GlobalConstants;
import pyUML.backend.JavaHelperMethods;
import pyUML.backend.UMLToolsHelperMethods;
import pyUML.listeners.ViewChangeListener;
/**
* This is the dialog for managing pyUML.views.
* Views can be selected, deleted, edited and created.
* A listener is implemented with this class, so here
* is defined what happens when you press buttons in the dialog.
*/
public class ManageViewsPage extends Dialog implements SelectionListener{
Composite composite = null;
Group viewsBoxGroup = null;
List viewsBox = null;
Button openButton = null;
Button editButton = null;
Button deleteButton = null;
Button createNewButton = null;
Model model;
IProject project;
Shell shell=null;
public ManageViewsPage(Shell parent, Model model, IProject project){
super(parent);
this.model= model;
this.project=project;
}
protected Control createDialogArea(Composite parent) {
this.composite = (Composite) super.createDialogArea(parent);
setShellStyle(SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MAX);
createControls(composite);
initializeDialog();
//add controls to composite as necessary
return composite;
}
public void createControls (Composite composite) {
// create graphical components
shell = composite.getShell();
shell.setText("Manage UML Views");
viewsBoxGroup = new Group(composite, SWT.None);
viewsBoxGroup.setText("Available Views");
viewsBoxGroup.setLayoutData(new GridData(GridData.FILL_BOTH));
viewsBoxGroup.setLayout(new GridLayout(1, true));
viewsBox = new List( viewsBoxGroup, SWT.BORDER|SWT.SINGLE|SWT.V_SCROLL|SWT.H_SCROLL );
viewsBox.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
Composite buttonGroup = new Composite(viewsBoxGroup, SWT.NONE);
buttonGroup.setLayoutData(new GridData(GridData.FILL_BOTH));
buttonGroup.setLayout(new GridLayout(3, true));
viewsBox.setSize(300,300);
openButton = new Button(buttonGroup, SWT.PUSH);
openButton.setText("Open View");
openButton.addSelectionListener(this);
editButton = new Button(buttonGroup, SWT.PUSH);
editButton.setText("Edit View");
editButton.addSelectionListener(this);
deleteButton = new Button(buttonGroup, SWT.PUSH);
deleteButton.setText("Delete View");
deleteButton.addSelectionListener(this);
buttonGroup.pack();
viewsBoxGroup.pack();
setElementEnabled(false, viewsBoxGroup);
createNewButton = new Button(composite, SWT.PUSH);
createNewButton.setText("Create New View");
createNewButton.setLayoutData(new GridData(GridData.FILL_BOTH));
createNewButton.addSelectionListener(this);
composite.pack();
}
/**
* Sets a composite element and all children enabled/disabled
* @param enabled
* @param element
*/
public static void setElementEnabled(boolean enabled, Control element) {
element.setEnabled(enabled);
if (element instanceof Composite) {
Composite comp = (Composite) element;
for (Control child : comp.getChildren()) {
setElementEnabled(enabled, child);
}
}
}
public void widgetDefaultSelected(SelectionEvent e) {
// Auto-generated method stub
}
/**
* Handles pressed-button events and runs appropriate pyUML.actions
*/
public void widgetSelected(SelectionEvent e) {
// "CREATE NEW" BUTTON
if (e.getSource() == this.createNewButton) {
this.createDialog();
// re-open View management window
this.cancelPressed();
}
//DELETE BUTTON
else if (e.getSource() == this.deleteButton) {
// return if nothing was selected
if (this.viewsBox.getSelection().length <= 0)
return;
// warn before deletion
if (MessageDialog.openConfirm(null, "Confirm deletion of view",
"Do you really want to delete this view?") == false)
return;
// delete view configuration, UML model and diagram
String selectedElement = this.viewsBox.getSelection()[0];
IPath conFilePath = project.getFullPath().append(GlobalConstants.getPyUmlDir())
.append(selectedElement+GlobalConstants.getViewConfExtension());
IFile confFile = this.project.getWorkspace().getRoot().getFile(conFilePath);
IPath umlFilePath = project.getFullPath().append(GlobalConstants.getPyUmlDir())
.append(selectedElement+GlobalConstants.getViewUmlExtension());
IFile umlFile = this.project.getWorkspace().getRoot().getFile(umlFilePath);
IPath diagramFilePath = project.getFullPath().append(GlobalConstants.getPyUmlDir())
.append(selectedElement+GlobalConstants.getDiagramExtension());
IFile diagramFile = this.project.getWorkspace().getRoot().getFile(diagramFilePath);
try {
if (confFile.exists())
confFile.delete(false, null);
if (umlFile.exists())
umlFile.delete(false, null);
if (diagramFile.exists())
diagramFile.delete(false, null);
} catch (CoreException err) {
MessageDialog.openError(null, "Error deleting element",
"Could not delete view. Reason:\n"+err.getMessage());
}
this.cancelPressed();
ManageViewsAction.run(project);
// OPEN BUTTON
} else if (e.getSource() == this.openButton) {
if (this.viewsBox.getSelection().length <= 0)
return;
String ViewUmlFileName = this.viewsBox.getSelection()[0]+GlobalConstants.getViewUmlExtension();
String ViewConfFileName = this.viewsBox.getSelection()[0]+GlobalConstants.getViewConfExtension();
String selectedElement = this.viewsBox.getSelection()[0]+GlobalConstants.getDiagramExtension();
IFile viewDiagramFile = this.project.getWorkspace().getRoot().
getFile(project.getFullPath().append(GlobalConstants.getPyUmlDir()).
append(selectedElement));
IFile viewConfFile = this.project.getWorkspace().getRoot().
getFile(project.getFullPath().append(GlobalConstants.getPyUmlDir()).
append(ViewConfFileName));
if (! viewDiagramFile.exists()) {
MessageDialog.openError(null, "Error opening view", "The selected view could not be opened;\n" +
"The UML diagram does not seem to exist!");
} else {
UMLToolsHelperMethods.updateViewModel(project, viewConfFile);
IEditorPart newPage = null;
try {
newPage = UMLToolsHelperMethods.refreshDiagramEditor(this.project, viewDiagramFile, false);
} catch (Throwable t) {
t.printStackTrace();
}
if (newPage == null)
newPage = UMLToolsHelperMethods.openDiagram(this.project, viewDiagramFile, ViewUmlFileName, true);
if ( newPage == null) {
MessageDialog.openError(null, "Error opening view", "The selected view could not be opened!");
}
else {
newPage.addPropertyListener(new ViewChangeListener(this.project));
this.close();
}
}
} // EDIT BUTTON
else if (e.getSource() == this.editButton) {
String selectedViewName = this.viewsBox.getSelection()[0];
IFile confFile = this.project.getWorkspace().getRoot().getFile(project.getFullPath().append(GlobalConstants.getPyUmlDir()).append(selectedViewName + GlobalConstants.getViewConfExtension()));
IFile viewDiagramFile = this.project.getWorkspace().getRoot().getFile(project.getFullPath().append(GlobalConstants.getPyUmlDir()).append(selectedViewName + GlobalConstants.getDiagramExtension()));
// open view editor
new EditView(this.project, confFile, selectedViewName, true);
// reload View, if it is already opened
UMLToolsHelperMethods.refreshDiagramEditor(project, viewDiagramFile, true);
// re-open View management window
this.cancelPressed();
ManageViewsAction.run(project);
}
}
/**
* creates a "new View" dialog
* creates an empty view config file and runs "edit" on this file
*/
public void createDialog() {
String viewName = "newView";
String newViewName = viewName;
IPath filePath=this.project.getLocation().append(GlobalConstants.getPyUmlDir());
// find initial filename that is not already used
int i=0;
java.io.File f;
do {
newViewName = viewName+(i==0?"":i);
String fileName=filePath.append(newViewName +GlobalConstants.getViewConfExtension()).toOSString();
f= new java.io.File(fileName);
i++;
} while (f.exists());
// create initial config file
try{
IFile confFile = this.project.getWorkspace().getRoot().getFile(project.getFullPath().append(GlobalConstants.getPyUmlDir()).append(newViewName + GlobalConstants.getViewConfExtension()));
confFile.create(JavaHelperMethods.stringToStream(""), false, null);
//open "edit view" editor
new EditView(this.project, confFile, newViewName, true);
this.close();
} catch (CoreException err) {
MessageDialog.openError(null, "Cannot create View", "View could not be created.\n" +
"Reason:\n"+err.getMessage());
return;
}
}
/**
* re-reads available pyUML.views from hard disk
*/
protected void initializeDialog() {
boolean viewFound = false;
String pyUmlDir = project.getLocation().append(GlobalConstants.getPyUmlDir()).toOSString();
java.io.File umlDir = new java.io.File(pyUmlDir);
if (umlDir.list() == null) {
MessageDialog.openError(null, "Error Managing Views",
"No UML Model was found.\n" +
"Please create a Model before creating a View!");
this.close();
return;
}
for (String file : umlDir.list()) {
if (file.matches(".*.pyUmlView.uml$")) {
viewFound=true;
this.viewsBox.add(file.replace(".pyUmlView.uml", ""));
this.viewsBox.add("a");
this.viewsBox.remove(this.viewsBox.getItemCount()-1);
}
}
if (viewFound)
setElementEnabled(true, viewsBoxGroup);
else
setElementEnabled(false, viewsBoxGroup);
}
}

View File

@ -0,0 +1,235 @@
package pyUML.views;
import java.util.Arrays;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Interface;
import org.eclipse.uml2.uml.Model;
/**
* This Wizard page contains a tree view where
* the user can select packages/classes used in the view.
*/
public class SelectViewElementsPage extends WizardPage implements SelectionListener{
private Model model;
private List<String> usedXmiIds;
protected Dictionary<Element, TreeItem> nodeCheckboxDict;
protected Text viewNameField;
protected Button buttInclSuperClasses;
protected Button buttInclSubClasses;
private Map<EObject, String> modelXmiDict;
private boolean initialIncludeSuperclasses;
private boolean initialIncludeSubclasses;
private String initialViewName;
public Text getViewNameField() {
return viewNameField;
}
protected SelectViewElementsPage(String pageName, Model model, List<String> usedXmiIds,
Map<EObject, String> modelXmiDict, String initialViewName,
boolean initialIncludSuperclasses, boolean initialIncludSubclasses) {
super(pageName);
this.setTitle(pageName);
this.model=model;
this.nodeCheckboxDict = new Hashtable<Element, TreeItem>();
this.usedXmiIds = usedXmiIds;
this.modelXmiDict = modelXmiDict;
this.initialIncludeSuperclasses = initialIncludSuperclasses;
this.initialIncludeSubclasses = initialIncludSubclasses;
this.initialViewName = initialViewName;
}
public void createControl(Composite parent) {
// create the composite to hold the widgets
GridData gd;
Composite composite = new Composite(parent, SWT.NULL);
// create the desired layout for this wizard page
GridLayout gl = new GridLayout();
int ncol = 1;
gl.numColumns = ncol;
gl.makeColumnsEqualWidth=true;
composite.setLayout(gl);
Composite viewNameComp= new Composite(composite, composite.getStyle());
GridLayout ViewNameLayout = new GridLayout();
ViewNameLayout.numColumns=2;
ViewNameLayout.makeColumnsEqualWidth=false;
viewNameComp.setLayout(ViewNameLayout);
Label viewNameLabel = new Label(viewNameComp, SWT.HORIZONTAL);
viewNameLabel.setText("View name: ");
viewNameField = new Text(viewNameComp, SWT.SINGLE);
viewNameField.setText(this.initialViewName);
viewNameField.setSize(200, 25);
Tree tree = new Tree(composite, SWT.CHECK);
gd = new GridData(GridData.FILL_BOTH);
tree.setLayoutData(gd);
TreeItem item = new TreeItem(tree, tree.getStyle());
item.setText(this.model.getName());
nodeCheckboxDict.put(model, item);
if (usedXmiIds.contains(modelXmiDict.get(model)))
item.setChecked(true);
for (Element child : model.getOwnedElements()) {
recurseModelElements(child, item);
}
if (usedXmiIds.contains(modelXmiDict.get(model)))
item.setChecked(true);
this.buttInclSuperClasses = new Button(composite, SWT.CHECK);
this.buttInclSuperClasses.setText("Include superclasses of selected classes");
this.buttInclSuperClasses.setSelection(this.initialIncludeSuperclasses);
this.buttInclSubClasses = new Button(composite, SWT.CHECK);
this.buttInclSubClasses.setText("Include child classes of selected classes");
this.buttInclSubClasses.setSelection(this.initialIncludeSubclasses);
// set the composite as the control for this page
setControl(composite);
tree.addSelectionListener(this);
}
/**
* This adds all sub-elements of checked packages
* to the list of used XMI-IDs. This is needed for a non-interactive
* View update to ensure all newly created sub-classes/-packages
* are added to a checked package.
*/
public void addPackagedXmiIds() {
this.recurseModelElements(this.model, null);
}
/**
* Initialize the TreeView by iterationg the Model
* -> Package and class nodes are created in the tree
* @param node
* @param parentItem if null, the XMI-ID will be added to used IDs
* insead of checking the box (used non-interactive mode)
*/
protected void recurseModelElements(Element node, TreeItem parentItem) {
if (node instanceof org.eclipse.uml2.uml.Package) {
org.eclipse.uml2.uml.Package pack = (org.eclipse.uml2.uml.Package) node;
if (parentItem == null) {
if (this.usedXmiIds.contains(this.modelXmiDict.get(pack)))
for (Element childNode : pack.getOwnedElements()) {
this.usedXmiIds.add(this.modelXmiDict.get(childNode));
recurseModelElements(childNode, null);
}
} else {
TreeItem item = new TreeItem(parentItem, parentItem.getStyle());
item.setText("Package " + pack.getName());
nodeCheckboxDict.put(pack, item);
for (Element childNode : pack.getOwnedElements())
recurseModelElements(childNode, item);
if(this.usedXmiIds.contains(this.modelXmiDict.get(pack)))
setWidgetChecked(item, true);
}
return;
}
if (node instanceof Classifier && parentItem != null) {
Classifier cl = (Classifier) node;
TreeItem item = new TreeItem(parentItem, parentItem.getStyle());
if (cl instanceof org.eclipse.uml2.uml.Class)
item.setText("Class " + cl.getName());
else if (cl instanceof Interface)
item.setText("Interface " + cl.getName());
else
item.setText("Element " + cl.getName());
nodeCheckboxDict.put(cl, item);
if(this.usedXmiIds.contains(this.modelXmiDict.get(cl)))
item.setChecked(true);
for (Element childNode : cl.getOwnedElements())
recurseModelElements(childNode, item);
return;
}
}
public void widgetDefaultSelected(SelectionEvent e) {
}
/**
* Check/uncheck a Class/Package in the Tree View
* and *all* subpackages/classes of a view
* This can be called by the listener or
* automatically when updating a view
* -> all new Child-Elements of a selected package
* should be automatically added to a view.
* @param item
* @param checked
*/
public void setWidgetChecked(TreeItem item, boolean checked) {
item.setChecked(checked);
List<TreeItem> children = new Vector<TreeItem>();
children.addAll(Arrays.asList(item.getItems()));
while(! children.isEmpty()) {
TreeItem child = children.get(0);
children.remove(child);
children.addAll(Arrays.asList(child.getItems()));
child.setChecked(checked);
}
}
public void widgetSelected(SelectionEvent e) {
// mark or unmark all children check boxes
// of a marked/unmarked box
if (e.item instanceof TreeItem) {
TreeItem item = (TreeItem) e.item;
boolean checked = item.getChecked();
this.setWidgetChecked(item, checked);
}
}
public Dictionary<Element, TreeItem> getNodeCheckboxDict() {
return nodeCheckboxDict;
}
public Button getButtInclSuperClasses() {
return buttInclSuperClasses;
}
public boolean isInitialIncludeSuperclasses() {
return initialIncludeSuperclasses;
}
public void setInitialIncludeSuperclasses(boolean initialIncludeSuperclasses) {
this.initialIncludeSuperclasses = initialIncludeSuperclasses;
}
public Button getButtInclSubClasses() {
return buttInclSubClasses;
}
}

View File

@ -0,0 +1,512 @@
package pyUML.views;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.impl.EClassImpl;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.uml2.uml.Association;
import org.eclipse.uml2.uml.BehavioredClassifier;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Generalization;
import org.eclipse.uml2.uml.Interface;
import org.eclipse.uml2.uml.Model;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.PackageableElement;
import org.eclipse.uml2.uml.ParameterableElement;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Realization;
import org.eclipse.uml2.uml.Relationship;
import org.eclipse.uml2.uml.TemplateParameter;
import org.eclipse.uml2.uml.Type;
import org.eclipse.uml2.uml.resource.UMLResource;
import pyUML.backend.GlobalConstants;
import pyUML.backend.UMLToolsHelperMethods;
/**
* This is an action class where the global UML model
* is to be updated by a view.
* Classes cannot be copied, because this would destroy all
* model relationships of the class.
* New classes in a view are ignored, because it is not known where
* they are to be inserted in the model.
*
* At the moment, class attributes and methods are *not* synchronized
* with the mail model.
*
*/
public class SynchronizeModelByView implements IObjectActionDelegate{
private String pathToModel;;
private String pathToView;
private Model model;
private Model viewModel;
private Resource[] viewResource = {null};
private Map<String, EObject> xmiModelDict;
private Map<EObject, String> modelXmiDict;
private Map<String, EObject> xmiViewDict;
private Map<EObject, String> viewXmiDict;
private IProject project;
public static void synchronizeGlobalModel(String pathToView, IProject project) {
SynchronizeModelByView sv = new SynchronizeModelByView();
sv.project = project;
sv.synchronizeGlobalModel(pathToView);
}
/**
* Updates the global model by changes made by the given view.
* Class deletions are removed from the view, not from the model.
*
* New classes/packages are ignored, because it is not known
* where they should be inserted.
*
* Other changes are updated in the global model.
*
* @param pathToModel
* @param pathToView
* @return
*/
public boolean synchronizeGlobalModel(String pathToView) {
String pathToModel = this.project.getLocation()
.append(GlobalConstants.getPyUmlDir())
.append(this.project.getName()+".uml").toOSString();
//init models
this.pathToModel = pathToModel;
this.pathToView = pathToView;
initModels();
String viewName = new Path(pathToView).lastSegment().replaceAll(GlobalConstants.getViewUmlExtension(), "");
Package viewPackage = null;
viewPackage = this.viewModel.getNestedPackage("View_"+viewName);
if (viewPackage == null) {
MessageDialog.openError(null, "Error synchronizing View",
"The Model could not be synchronized by the view, because\n" +
"The View package View_"+viewName+" could not\n" +
"be found.");
return false;
}
List<PackageableElement> elList = new Vector<PackageableElement>();
elList.addAll(viewPackage.getPackagedElements());
for (PackageableElement el : elList) {
// find parent package in model
if (el instanceof Type) {
Type packagedType = (Type) el;
Type includingType = packagedType;
if (packagedType instanceof Association) {
Association as = (Association) packagedType;
includingType = as.getEndTypes().get(0);
}
String xmi_id = this.viewXmiDict.get(includingType);
if (xmi_id == null || (! this.xmiModelDict.containsKey(xmi_id)))
continue;
Type modelType = (Type) this.xmiModelDict.get(xmi_id);
Package parentPackage = modelType.getPackage();
String modelPackageXmiId= this.modelXmiDict.get(parentPackage);
if (modelPackageXmiId == null)
continue;
Package newViewPackage = (Package) this.xmiViewDict.get(modelPackageXmiId);
if (newViewPackage == null)
continue;
packagedType.setPackage(newViewPackage);
} else if (el instanceof ParameterableElement) {
ParameterableElement parEl = (ParameterableElement) el;
String xmi_id = this.viewXmiDict.get(el);
ParameterableElement modelParEl = (ParameterableElement) this.xmiModelDict.get(xmi_id);
Realization r;
TemplateParameter parentParEl = modelParEl.getOwningTemplateParameter();
String modelParElXmiId=this.modelXmiDict.get(parentParEl);
if (modelParElXmiId == null)
continue;
TemplateParameter newViewParEl = (TemplateParameter) this.xmiViewDict.get(modelParElXmiId);
if (newViewParEl == null)
continue;
parEl.setOwningTemplateParameter(newViewParEl);
}
}
viewPackage.destroy();
/*
// synchronize by all child classes
try{
List<Element> elementCopy = new Vector<Element>();
elementCopy.addAll(this.viewModel.getOwnedElements());
for (Element child : elementCopy) {
if (child instanceof Class)
synchronizeClass((Class)child);
}
} catch (Throwable t) {
t.printStackTrace();
}
*/
// save model
this.viewResource[0].setURI(URI.createFileURI(project.getLocation().append(GlobalConstants.getPyUmlDir()).append(project.getName()+".uml").toOSString()));
try {
this.viewResource[0].save(null);
}catch (IOException e) {
e.printStackTrace();
}
return true;
//return saveModel();
}
/**
* initializes the Model of the view and the main model
*/
private void initModels() {
// save all open editors
IWorkbenchPage page =
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
page.saveAllEditors(false);
// initialize XMI dictionaries as empty -> they are filled, if a
// model already exists
this.modelXmiDict = new HashMap<EObject, String>();
this.xmiModelDict = new HashMap<String, EObject>();
this.viewXmiDict = new HashMap<EObject, String>();
this.xmiViewDict = new HashMap<String, EObject>();
// load view and model
// this.model =
this.model= initModel(this.pathToModel, this.xmiModelDict, this.modelXmiDict, null);
if (this.model == null)
return;
this.viewModel = initModel(this.pathToView, this.xmiViewDict, this.viewXmiDict, this.viewResource);
if (this.viewModel == null)
return;
}
/**
* loads a .uml model (main model or view)
* and fills the given dictionaries
* @param pathToModel
* @param xmiModelDict
* @param modelXmiDict
* @param modelResource
* @return
*/
private Model initModel(String pathToModel, Map<String, EObject> xmiModelDict,
Map<EObject, String> modelXmiDict, Resource[] modelResource) {
// look for model file
Model model;
Resource resource;
File modelFile = new File(pathToModel);
if (! modelFile.exists()) {
MessageDialog.openError(null, "Error synchronizing Model by View",
"Model can not be found: "+pathToModel);
return null;
}
// read Model
EObject diagramRoot = UMLToolsHelperMethods.loadUMLDiagram(pathToModel);
model = (Model) diagramRoot;
resource = model.eResource();
// get model -> xmi-id dictionary
UMLResource r = (UMLResource) resource;
modelXmiDict.putAll(r.getEObjectToIDMap());
// create reverse dict, so that xmi_id can be the key
for (EObject modelObject : modelXmiDict.keySet()) {
String xmi_id = modelXmiDict.get(modelObject);
xmiModelDict.put(xmi_id, modelObject);
}
if (modelResource != null)
modelResource[0] = resource;
return model;
}
/**
* Synchronizes a model class by a view class
* @param viewClass
*/
private void synchronizeClass(Class viewClass) {
String classXmiId = this.viewXmiDict.get(viewClass);
if (! xmiModelDict.containsKey(classXmiId)) {
MessageDialog.openWarning(null, "Error saving View",
"You created a new class \""+ viewClass.getName() +
"\" in the view.\n" +
"This is not supported, because it is not " +
"known \nwhere to put the class in the original " +
"model.\n" +
"The inserted class will be ignored.");
return;
}
Class modelClass = (Class) xmiModelDict.get(classXmiId);
Package parentPackage = (Package) modelClass.getOwner();
// destroy all generalizations and associations in model,
// if both ends are present in view and association is no more
// present in view
for (Relationship rel : modelClass.getRelationships()) {
if (rel instanceof Association) {
String modelRelationXmiID = this.modelXmiDict.get(rel);
if (modelRelationXmiID != null && ! this.xmiViewDict.containsKey(modelRelationXmiID)) {
rel.destroy();
}
}
}
// now, copy all changes from
// View to Model.
// Also, we have to make sure to delete Attributes/methods in
// the model if they were deleted in the code.
List<Relationship> relList = new Vector<Relationship>();
relList.addAll(viewClass.getRelationships());
System.out.println(viewClass.getRelationships());
System.out.println(viewClass.getSourceDirectedRelationships());
for (Relationship rel : relList) {
if (rel instanceof Association) {
Association assoc = (Association) rel;
EList<Element> elList = rel.getRelatedElements();
Type connectedElement = (Type) elList.get(0);
Property end1 = (Property) rel.getOwnedElements().get(0);
Property end2 = (Property) (rel.getOwnedElements().size() > 1 ? rel.getOwnedElements().get(1) : end1);
Type secondElement = (Type) connectedElement;
if (elList.size() > 1) {
secondElement = (Type) elList.get(1);
}
// if source (first) element is not current class,
// switch first and second element
// to be sure element to be connected by this class is second.
if (! (connectedElement == viewClass)) {
Type tmpElement = secondElement;
secondElement = connectedElement;
connectedElement = tmpElement;
Property tmpProp = end1;
end1=end2;
end2=tmpProp;
}
String secondElXmiID = this.viewXmiDict.get(secondElement);
// continue if connected element is not present in model
// -> this relationship can not be handled!
if (! this.xmiModelDict.containsKey(secondElXmiID)) {
continue;
}
Type connectedElementInModel = (Type) this.xmiModelDict.get(secondElXmiID);
if (rel.getOwnedElements().size() == 0) {
continue;
}
// get old association, if possible
Relationship modelRelationship = null;
if (this.xmiModelDict.containsKey(this.viewXmiDict.get(rel))) {
modelRelationship = (Relationship) this.xmiModelDict.get(this.viewXmiDict.get(rel));
}
boolean changed = true;
if (modelRelationship != null) {
changed = false;
Property modelEnd2 = (Property) modelRelationship.getOwnedElements().get(0);
Property modelEnd1 = (Property) (modelRelationship.getOwnedElements().size() > 1 ? modelRelationship.getOwnedElements().get(1) : modelEnd2);
// update classes that take part in this association
modelEnd1.setType(modelClass);
modelEnd2.setType(connectedElementInModel);
// look if anything changed in association; if yes, move view association
// to model
if ( modelEnd1.isNavigable() != end1.isNavigable()
|| modelEnd1.isNavigable() != end1.isNavigable()
|| modelEnd2.isNavigable() != end2.isNavigable()
|| ! modelEnd1.getAggregation().equals(end1.getAggregation())
|| ! modelEnd2.getAggregation().equals(end2.getAggregation())
|| ! modelEnd1.getName().equals(end1.getName())
|| ! modelEnd2.getName().equals(end2.getName())
|| modelEnd1.getLower() != end1.getLower()
|| modelEnd2.getLower() != end2.getLower()
|| modelEnd1.getUpper() != end1.getUpper()
|| modelEnd2.getUpper() != end2.getUpper()
|| ! this.modelXmiDict.get(modelEnd1.getType()).equals(this.viewXmiDict.get(end1.getType()))
|| ! this.modelXmiDict.get(modelEnd2.getType()).equals(this.viewXmiDict.get(end2.getType())))
changed = true;
}
if (changed) {
assoc.setPackage(parentPackage);
end1.setType(modelClass);
end2.setType(connectedElementInModel);
//modelClass.createAssociation(end1.isNavigable(), end1.getAggregation(), end1.getName(), end1.getLower(), end1.getUpper(), connectedElementInModel, end2.isNavigable(), end2.getAggregation(), end2.getName(), end2.getLower(), end2.getUpper());
if (modelRelationship != null)
modelRelationship.destroy();
}
}
}
// Directed Associations are hidden in attributes
propertyLoop:
for (Property att : viewClass.getAllAttributes()) {
if (att.getAssociation() != null) {
Association as = att.getAssociation();
String asXmiId = this.viewXmiDict.get(as);
Type modelType = null;
String typeXmiId = this.viewXmiDict.get(att.getType());
if (this.xmiModelDict.containsKey(typeXmiId))
modelType = (Type) this.xmiModelDict.get(typeXmiId);
else
continue propertyLoop;
Property modelProp = null;
// try to find model property -> property with same association
for (Property prop : modelClass.getAllAttributes()) {
if (prop.getAssociation()!= null &&
this.xmiModelDict.get(prop.getAssociation()).equals(asXmiId))
modelProp = prop;
}
if (modelProp != null){
// Property is present, check if everything is correct;
modelProp = (Property) this.xmiModelDict.get(asXmiId);
modelProp.setName(att.getName());
} else {
//create this Property
modelProp = modelClass.createOwnedAttribute(att.getName(), modelType);
}
as.setPackage(parentPackage);
//for (Element e : as.getOwnedElements();
modelProp.setOwningAssociation(as);
modelProp.setType(modelType);
modelProp.setLower(att.getLower());
modelProp.setUpper(att.getUpper());
}
}
// delete all generalizations in model not present in view
List<Generalization> tmpGens= new Vector<Generalization>();
tmpGens.addAll(modelClass.getGeneralizations());
for (Generalization general: tmpGens) {
String modelSupXmiID = this.modelXmiDict.get(general.getGeneral());
Classifier viewSuperClass = (Classifier) this.xmiViewDict.get(modelSupXmiID);
boolean generalIsPresentInView = false;
for (Generalization viewSuper : viewClass.getGeneralizations()) {
if (viewSuper.getGeneral() == viewSuperClass) {
generalIsPresentInView = true;
break;
}
}
if (! generalIsPresentInView) {
general.destroy();
}
}
// copy all generalizations of classes
for (Generalization general: viewClass.getGeneralizations()) {
String superClassXmiID = viewXmiDict.get(general.getGeneral());
Classifier modelSuperClass = (Classifier) xmiModelDict.get(superClassXmiID);
boolean generalIsPresentInModel = false;
for (Generalization modelSuper : modelClass.getGeneralizations()) {
if (modelSuper.getGeneral() == modelSuperClass) {
generalIsPresentInModel = true;
break;
}
}
if (! xmiViewDict.containsKey(superClassXmiID))
continue;
if (! generalIsPresentInModel) {
modelClass.createGeneralization(modelSuperClass);
}
}
}
/**
* Saves the edited model .uml file
* @return
*/
private boolean saveModel() {
/*try {
this.modelResource[0].save(null);
EclipseHelperMethods.updateFile(pathToModel, project);
return true;
} catch (IOException e) {
MessageDialog.openError(null, "Error saving model",
"The model cannot be saved. Reason:\n" + e.getMessage());
return false;
}*/
return true;
}
public void setActivePart(IAction action, IWorkbenchPart targetPart) {
// Auto-generated method stub
}
public void run(IAction action) {
this.synchronizeGlobalModel(this.pathToView);
}
public void selectionChanged(IAction action, ISelection selection) {
// save selected uml view
if (selection instanceof TreeSelection) {
TreeSelection ts = (TreeSelection) selection;
if (ts.getFirstElement() instanceof org.eclipse.core.internal.resources.File) {
org.eclipse.core.internal.resources.File selectedFile = (org.eclipse.core.internal.resources.File) ts.getFirstElement();
this.pathToView = selectedFile.getLocation().toOSString();
this.project = selectedFile.getProject();
}
}
}
}

View File

@ -0,0 +1,384 @@
package pyUML.views;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import org.eclipse.core.resources.IProject;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.uml2.uml.Association;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Generalization;
import org.eclipse.uml2.uml.Model;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.ParameterableElement;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Relationship;
import org.eclipse.uml2.uml.Type;
import org.eclipse.uml2.uml.resource.UMLResource;
import pyUML.backend.EclipseHelperMethods;
import pyUML.backend.GlobalConstants;
import pyUML.backend.UMLToolsHelperMethods;
/**
* This is an action class where the global UML model
* is to be updated by a view.
* Classes cannot be copied, because this would destroy all
* model relationships of the class.
* New classes in a view are ignored, because it is not known where
* they are to be inserted in the model.
*
* At the moment, class attributes and methods are *not* synchronized
* with the mail model.
*
*/
public class SynchronizeViews implements IObjectActionDelegate{
private String pathToModel;;
private String pathToView;
//private Model model;
private Model viewModel;
private Resource[] modelResource = {null};
private Map<String, EObject> xmiModelDict;
private Map<EObject, String> modelXmiDict;
private Map<String, EObject> xmiViewDict;
private Map<EObject, String> viewXmiDict;
private IProject project;
public static void synchronizeGlobalModel(String pathToView, IProject project) {
SynchronizeViews sv = new SynchronizeViews();
sv.project = project;
sv.synchronizeGlobalModel(pathToView);
}
/**
* Updates the global model by changes made by the given view.
* Class deletions are removed from the view, not from the model.
*
* New classes/packages are ignored, because it is not known
* where they should be inserted.
*
* Other changes are updated in the global model.
*
* @param pathToModel
* @param pathToView
* @return
*/
public boolean synchronizeGlobalModel(String pathToView) {
String pathToModel = this.project.getLocation()
.append(GlobalConstants.getPyUmlDir())
.append(this.project.getName()+".uml").toOSString();
//init models
this.pathToModel = pathToModel;
this.pathToView = pathToView;
initModels();
// synchronize by all child classes
try{
List<Element> elementCopy = new Vector<Element>();
elementCopy.addAll(this.viewModel.getOwnedElements());
for (Element child : elementCopy) {
if (child instanceof Class)
synchronizeClass((Class)child);
}
} catch (Throwable t) {
t.printStackTrace();
}
// save model
return saveModel();
}
/**
* initializes the Model of the view and the main model
*/
private void initModels() {
// save all open editors
IWorkbenchPage page =
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
page.saveAllEditors(false);
// initialize XMI dictionaries as empty -> they are filled, if a
// model already exists
this.modelXmiDict = new HashMap<EObject, String>();
this.xmiModelDict = new HashMap<String, EObject>();
this.viewXmiDict = new HashMap<EObject, String>();
this.xmiViewDict = new HashMap<String, EObject>();
// load view and model
// this.model =
initModel(this.pathToModel, this.xmiModelDict, this.modelXmiDict, this.modelResource);
this.viewModel = initModel(this.pathToView, this.xmiViewDict, this.viewXmiDict, null);
}
/**
* loads a .uml model (main model or view)
* and fills the given dictionaries
* @param pathToModel
* @param xmiModelDict
* @param modelXmiDict
* @param modelResource
* @return
*/
private Model initModel(String pathToModel, Map<String, EObject> xmiModelDict,
Map<EObject, String> modelXmiDict, Resource[] modelResource) {
// look for model file
Model model;
Resource resource;
File modelFile = new File(pathToModel);
if (! modelFile.exists()) {
MessageDialog.openError(null, "Error synchronizing Model by View",
"Model can not be found: "+pathToModel);
return null;
}
// read Model
EObject diagramRoot = UMLToolsHelperMethods.loadUMLDiagram(pathToModel);
model = (Model) diagramRoot;
resource = model.eResource();
// get model -> xmi-id dictionary
UMLResource r = (UMLResource) resource;
modelXmiDict.putAll(r.getEObjectToIDMap());
// create reverse dict, so that xmi_id can be the key
for (EObject modelObject : modelXmiDict.keySet()) {
String xmi_id = modelXmiDict.get(modelObject);
xmiModelDict.put(xmi_id, modelObject);
}
if (modelResource != null)
modelResource[0] = resource;
return model;
}
/**
* Synchronizes a model class by a view class
* @param viewClass
*/
private void synchronizeClass(Class viewClass) {
String classXmiId = this.viewXmiDict.get(viewClass);
if (! xmiModelDict.containsKey(classXmiId)) {
MessageDialog.openWarning(null, "Error saving View",
"You created a new class \""+ viewClass.getName() +
"\" in the view.\n" +
"This is not supported, because it is not " +
"known \nwhere to put the class in the original " +
"model.\n" +
"The inserted class will be ignored.");
return;
}
Class modelClass = (Class) xmiModelDict.get(classXmiId);
Package parentPackage = (Package) modelClass.getOwner();
// destroy all generalizations and associations in model,
// if both ends are present in view and association is no more
// present in view
for (Relationship rel : modelClass.getRelationships()) {
if (rel instanceof Association) {
String modelRelationXmiID = this.modelXmiDict.get(rel);
if (modelRelationXmiID != null && ! this.xmiViewDict.containsKey(modelRelationXmiID)) {
rel.destroy();
}
}
}
// now, copy all associations / attributes/methods from
// View to Model.
// We cannot just copy the whole class, because this would
// destroy the associations/generalizations etc.
// Also, we have to make sure to delete Attributes/methods in
// the model if they were deleted in the code.
for (Relationship rel : viewClass.getRelationships()) {
if (rel instanceof Association) {
Association assoc = (Association) rel;
EList<Element> elList = rel.getRelatedElements();
Type connectedElement = (Type) elList.get(0);
Property end1 = (Property) rel.getOwnedElements().get(0);
Property end2 = (Property) (rel.getOwnedElements().size() > 1 ? rel.getOwnedElements().get(1) : end1);
Type secondElement = (Type) connectedElement;
if (elList.size() > 1) {
secondElement = (Type) elList.get(1);
}
// if source (first) element is not current class,
// switch first and second element
// to be sure element to be connected by this class is second.
if (! (connectedElement == viewClass)) {
Type tmpElement = secondElement;
secondElement = connectedElement;
connectedElement = tmpElement;
Property tmpProp = end1;
end1=end2;
end2=tmpProp;
}
String secondElXmiID = this.viewXmiDict.get(secondElement);
// continue if connected element is not present in model
// -> this relationship can not be handled!
if (! this.xmiModelDict.containsKey(secondElXmiID)) {
continue;
}
Type connectedElementInModel = (Type) this.xmiModelDict.get(secondElXmiID);
if (rel.getOwnedElements().size() == 0) {
continue;
}
// get old association, if possible
Relationship modelRelationship = null;
if (this.xmiModelDict.containsKey(this.viewXmiDict.get(rel))) {
modelRelationship = (Relationship) this.xmiModelDict.get(this.viewXmiDict.get(rel));
}
boolean changed = true;
if (modelRelationship != null) {
changed = false;
Property modelEnd2 = (Property) modelRelationship.getOwnedElements().get(0);
Property modelEnd1 = (Property) (modelRelationship.getOwnedElements().size() > 1 ? modelRelationship.getOwnedElements().get(1) : modelEnd2);
// update classes that take part in this association
modelEnd1.setType(modelClass);
modelEnd2.setType(connectedElementInModel);
// look if anything changed in association; if yes, move view association
// to model
if ( modelEnd1.isNavigable() != end1.isNavigable()
|| modelEnd1.isNavigable() != end1.isNavigable()
|| modelEnd2.isNavigable() != end2.isNavigable()
|| ! modelEnd1.getAggregation().equals(end1.getAggregation())
|| ! modelEnd2.getAggregation().equals(end2.getAggregation())
|| ! modelEnd1.getName().equals(end1.getName())
|| ! modelEnd2.getName().equals(end2.getName())
|| modelEnd1.getLower() != end1.getLower()
|| modelEnd2.getLower() != end2.getLower()
|| modelEnd1.getUpper() != end1.getUpper()
|| modelEnd2.getUpper() != end2.getUpper()
|| ! this.modelXmiDict.get(modelEnd1.getType()).equals(this.viewXmiDict.get(end1.getType()))
|| ! this.modelXmiDict.get(modelEnd2.getType()).equals(this.viewXmiDict.get(end2.getType())))
changed = true;
}
if (changed) {
assoc.setPackage(parentPackage);
end1.setType(modelClass);
end2.setType(connectedElementInModel);
//modelClass.createAssociation(end1.isNavigable(), end1.getAggregation(), end1.getName(), end1.getLower(), end1.getUpper(), connectedElementInModel, end2.isNavigable(), end2.getAggregation(), end2.getName(), end2.getLower(), end2.getUpper());
if (modelRelationship != null)
modelRelationship.destroy();
}
}
}
// delete all generalizations in model not present in view
List<Generalization> tmpGens= new Vector<Generalization>();
tmpGens.addAll(modelClass.getGeneralizations());
for (Generalization general: tmpGens) {
String modelSupXmiID = this.modelXmiDict.get(general.getGeneral());
Classifier viewSuperClass = (Classifier) this.xmiViewDict.get(modelSupXmiID);
boolean generalIsPresentInView = false;
for (Generalization viewSuper : viewClass.getGeneralizations()) {
if (viewSuper.getGeneral() == viewSuperClass) {
generalIsPresentInView = true;
break;
}
}
if (! generalIsPresentInView) {
general.destroy();
}
}
// copy all generalizations of classes
for (Generalization general: viewClass.getGeneralizations()) {
String superClassXmiID = viewXmiDict.get(general.getGeneral());
Classifier modelSuperClass = (Classifier) xmiModelDict.get(superClassXmiID);
boolean generalIsPresentInModel = false;
for (Generalization modelSuper : modelClass.getGeneralizations()) {
if (modelSuper.getGeneral() == modelSuperClass) {
generalIsPresentInModel = true;
break;
}
}
if (! xmiViewDict.containsKey(superClassXmiID))
continue;
if (! generalIsPresentInModel) {
modelClass.createGeneralization(modelSuperClass);
}
}
}
/**
* Saves the edited model .uml file
* @return
*/
private boolean saveModel() {
try {
this.modelResource[0].save(null);
EclipseHelperMethods.updateFile(pathToModel, project);
return true;
} catch (IOException e) {
MessageDialog.openError(null, "Error saving model",
"The model cannot be saved. Reason:\n" + e.getMessage());
return false;
}
}
public void setActivePart(IAction action, IWorkbenchPart targetPart) {
// Auto-generated method stub
}
public void run(IAction action) {
this.synchronizeGlobalModel(this.pathToView);
}
public void selectionChanged(IAction action, ISelection selection) {
// save selected uml view
if (selection instanceof TreeSelection) {
TreeSelection ts = (TreeSelection) selection;
if (ts.getFirstElement() instanceof org.eclipse.core.internal.resources.File) {
org.eclipse.core.internal.resources.File selectedFile = (org.eclipse.core.internal.resources.File) ts.getFirstElement();
this.pathToView = selectedFile.getLocation().toOSString();
this.project = selectedFile.getProject();
}
}
}
}

View File

@ -0,0 +1,133 @@
package parser;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import org.eclipse.core.runtime.IPath;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Package;
import parser.pythonTree.PythonTreeClass;
import parser.pythonTree.PythonTreeNode;
import parser.pythonTree.PythonTreePackage;
public class CodeFromModelCreator {
/**
* synchronizes the code with the model.
* if any python file is changed, false is returned
* to rebuild the tree and start from beginning
*
* @param pythonNode
* @param umlElement
* @param xmiModelDict
* @return
*/
public static boolean synchronizeCodeFromModel(PythonTreeNode pythonNode, Element umlElement, Map<EObject, String> xmiModelDict) {
for (Element modelElement:umlElement.getOwnedElements()) {
if (modelElement instanceof Package) {
Package modelPack = (Package) modelElement;
PythonTreePackage pyPack = (PythonTreePackage) pythonNode;
if (xmiModelDict.containsKey(modelPack)) {
String xmi_id = xmiModelDict.get(modelPack);
if (pythonNode.getRoot().getXmiPackDict().containsKey(xmi_id)) {
PythonTreeNode node = pythonNode.getRoot().getXmiPackDict().get(xmi_id);
if (pyPack.getChildPackages().contains(node)) {
boolean startNew = synchronizeCodeFromModel(node, modelElement, xmiModelDict);
if (startNew) return true;
PythonTreePackage subPack = (PythonTreePackage) node;
// TODO: umhaengen des Pakets an die richtige Stelle
// im FS und im Python Tree
}
} else {
// look for python node with same name
boolean packageFound = false;
for (PythonTreePackage pySubPack : pyPack.getChildPackages()) {
if (pySubPack.getName().equals(modelPack.getName())){
// write xmi_id to code (only needed once)
pySubPack.writeXmiID(xmi_id);
packageFound=true;
break;
}
}
// if this package was not found, create it (recursively)!
if (! packageFound) {
// create package
IPath newPackPath = pyPack.getPackageDir().append(modelPack.getName());
File newPackDir = new File(newPackPath.toOSString());
newPackDir.mkdir();
File initPy = new File(newPackPath.append("__init__.py").toOSString());
try{
initPy.createNewFile();
}
catch (IOException e) {
MessageDialog.openError(null, "IOException", "Error writing to file "+ initPy.getPath());
}
PythonTreePackage newPyPack = new PythonTreePackage(newPackPath, pyPack);
newPyPack.writeXmiID(xmi_id);
boolean startNew = synchronizeCodeFromModel(newPyPack, modelPack, xmiModelDict);
if (startNew) return true;
}
}
} else {
MessageDialog.openError(null,"Error synchronizing","There was an inconsistency in the Python Package Tree");
return true;
}
}
else if (modelElement instanceof Class) {
Class modelClass = (Class) modelElement;
PythonTreePackage pyPack = (PythonTreePackage) pythonNode;
if (xmiModelDict.containsKey(modelClass)) {
String xmi_id = xmiModelDict.get(modelClass);
if (pythonNode.getRoot().getXmiClassDict().containsKey(xmi_id)) {
PythonTreeNode node = pythonNode.getRoot().getXmiClassDict().get(xmi_id);
if (pyPack.getChildClasses().contains(node)) {
boolean startNew = synchronizeCodeFromModel(node, modelElement, xmiModelDict);
if (startNew) return true;
PythonTreeClass subPack = (PythonTreeClass) node;
// TODO: umhaengen der Klasse an die richtige Stelle
}
} else {
// look for python child class with same name
// and write the right xmi_id
boolean classFound = false;
for (PythonTreeClass pySubClass : pyPack.getChildClasses()) {
if (pySubClass.getName().equals(modelClass.getName())){
// write xmi_id to code (only needed once)
pySubClass.writeXmiID(xmi_id);
classFound=true;
return false;
}
}
// if this class was not found, create it (recursively)!
/* if (! classFound) {
// create package
IPath newPackPath = treePack.getPackageDir().append(modelPack.getName());
File newPackDir = new File(newPackPath.toOSString());
newPackDir.mkdir();
File initPy = new File(newPackPath.append("__init__.py").toOSString());
try{
initPy.createNewFile();
}
catch (IOException e) {
MessageDialog.openError(null, "IOException", "Error writing to file "+ initPy.getPath());
}
PythonTreePackage newPyPack = new PythonTreePackage(newPackPath, treePack);
newPyPack.writeXmiID(xmi_id);
generateCodeFromModel(newPyPack, modelPack, xmiModelDict);
}
*/
}
}else {
MessageDialog.openError(null,"Error synchronizing","There was an inconsistency in the Python Package Tree");
return true;
}
}
}
return false;
}
}

211
pyUml/trash/Py2UMLCreator.java Executable file
View File

@ -0,0 +1,211 @@
package synchronize;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;
import java.util.Vector;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Generalization;
import org.eclipse.uml2.uml.Operation;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Type;
import org.python.pydev.parser.jython.SimpleNode;
import org.python.pydev.parser.jython.ast.Assign;
import org.python.pydev.parser.jython.ast.Attribute;
import org.python.pydev.parser.jython.ast.Call;
import org.python.pydev.parser.jython.ast.ClassDef;
import org.python.pydev.parser.jython.ast.FunctionDef;
import org.python.pydev.parser.jython.ast.Import;
import org.python.pydev.parser.jython.ast.ImportFrom;
import org.python.pydev.parser.jython.ast.Module;
import org.python.pydev.parser.jython.ast.Name;
import org.python.pydev.parser.jython.ast.NameTok;
import org.python.pydev.parser.jython.ast.Num;
import org.python.pydev.parser.jython.ast.Str;
import org.python.pydev.parser.jython.ast.exprType;
import org.python.pydev.parser.jython.ast.stmtType;
import parser.ParseHelpers;
public class Py2UMLCreator {
// dictionary of all created classes for later access
private Dictionary<String, Class> classDict;
// list of generalizations to add to model
// after adding all classes
private List<Tuple<Class, String>> generalizations;
public Py2UMLCreator() {
this.classDict = new Hashtable<String, Class>();
this.generalizations = new Vector<Tuple<Class, String>>();
}
public void createModelFromAST(SimpleNode root, Package rootPack) {
parsePackage(root, rootPack);
}
private void parsePackage(SimpleNode node, Package pack) {
if (node instanceof Module) {
Module pyModule = (Module) node;
stmtType[] statements = pyModule.body;
for (int i = 0; i < statements.length; i++) {
parsePackage(statements[i], pack);
if (statements[i] instanceof ClassDef) {
ClassDef pyClass = (ClassDef) statements[i];
parseClass(pyClass, pack);
}
if (statements[i] instanceof ImportFrom) {
ImportFrom importFrom = (ImportFrom) statements[i];
//System.out.println("---import---");
//System.out.println(((NameTok)importFrom.names[0].name).id);
}
if (statements[i] instanceof Import) {
Import importFrom = (Import) statements[i];
//System.out.println("---import---");
//System.out.println(((NameTok)importFrom.names[0].name).id);
}
}
}
}
/**
* Add generalizations to model
*/
public void createGeneralizations() {
System.out.println("creating Gens");
System.out.println(this.generalizations);
for (Tuple<Class, String> tup : this.generalizations) {
Class subClass = tup.a;
String superClassStr = tup.b;
System.out.println("create gen for " + subClass.getName());
System.out.println(superClassStr);
if ((classDict.get(superClassStr)) == null) {
System.out.println("...failed");
continue;
}
Class superclass = classDict.get(superClassStr);
Generalization gen = subClass.createGeneralization(superclass);
}
}
// get basic class information
private void parseClass(ClassDef pyClass, Package pack) {
String className=((NameTok) pyClass.name).id;
Class cl = pack.createOwnedClass(className, false);
if (classDict.get(className) != null)
MessageDialog.openError(null, "Duplicate Class detected",
"The class '"+className+ "' exists more than 1 time!");
this.classDict.put(className, cl);
System.out.println("class "+className);
exprType[] baseClasses=pyClass.bases;
for (exprType baseClass : baseClasses) {
if (baseClass instanceof Name) {
String baseName = ((Name)baseClass).id;
System.out.println("found base class " + baseName);
// add generalization
generalizations.add(new Tuple<Class,String>(cl, baseName));
}else if (baseClass instanceof Attribute){
Attribute att = (Attribute) baseClass;
String baseName=att.attr.toString();
System.out.println("found base class " + baseName);
// add generalization
generalizations.add(new Tuple<Class,String>(cl, baseName));
}
}
// parse class body
stmtType[] statements = pyClass.body;
parseBody: for (int i = 0; i < statements.length; i++) {
System.out.println("stmt at line " + statements[i].beginLine);
System.out.println(statements[i].getClass().getName());
// look for static attributes (=assertions inside class body)
if (statements[i] instanceof Assign) {
Assign assign = (Assign) statements[i];
exprType left = assign.targets[0];
exprType right = assign.value;
String assignTo = ((Name)left).id;
String assignVal = "";
assignVal = ParseHelpers.getStringOfExpr(right);
System.out.println("attrs:");
System.out.println(right.getClass().getName());
System.out.println(assignVal);
if (right instanceof Call) {
Call call = (Call) right;
String callName =(((Name)call.func).id);
if (callName.equals("staticmethod"))
continue parseBody;
}
Property classAttr = cl.createOwnedAttribute(assignTo, null);
classAttr.setIsStatic(true);
classAttr.setDefault(assignVal);
}
// get method definitions
if (statements[i] instanceof FunctionDef) {
FunctionDef func = (FunctionDef) statements[i];
String funcName=((NameTok)func.name).id;
exprType[] argList = func.args.args;
EList<String> paramNameList = new BasicEList<String>();
EList<Type> paramTypeList = new BasicEList<Type>();
// get arguments
for (exprType arg : argList) {
Name n = (Name) arg;
paramNameList.add(n.id);
paramTypeList.add(null);
System.out.println(n.id);
}
// create model element
Operation op = cl.createOwnedOperation(funcName, paramNameList, null);
// set static method (if so)
if (argList.length == 0 || (! ((Name) argList[0]).id.equals("self")))
op.setIsStatic(true);
// get object variables, if this is the __init__ method
if (funcName.equals("__init__")){
stmtType[] initStmts = func.body;
for (stmtType initStmt: initStmts) {
if (initStmt instanceof Assign) {
Assign assign = (Assign) initStmt;
exprType left = assign.targets[0];
exprType right = assign.value;
if (left instanceof Attribute) {
Attribute attrLeft = (Attribute) left;
String attrName = ((NameTok)attrLeft.attr).id;
String attrVal = ParseHelpers.getStringOfExpr(right);
Property att = cl.createOwnedAttribute(attrName, null);
att.setDefault(attrVal);
}
}
}
}
}
}
}
class Tuple<A,B>{
A a;
B b;
public Tuple(A a, B b) {
this.a=a;
this.b=b;
}
public String toString() {
return "(<"+this.a+">,<"+this.b+">)";
}
}
}

View File

@ -0,0 +1,134 @@
package pyUML.listeners;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IPropertyListener;
import org.eclipse.ui.PlatformUI;
import pyUML.backend.EclipseHelperMethods;
import pyUML.backend.GlobalConstants;
import pyUML.backend.UMLToolsHelperMethods;
import pyUML.views.SynchronizeModelByView;
/**
* This listener synchronizes the global model and
* all other pyUML.views whenever a view is saved
*/
public abstract class ViewChangeListener2 implements IPropertyListener {
private IProject project;
private static boolean listenerEnabled = true;
public ViewChangeListener2(IProject project) {
super();
this.project = project;
}
/**
* Enables or disables all Listeners; this can be
* useful to avoid circular listener calls
* (model, view...) on a document change
* @param enabled
*/
public static void setListenersEnabled(boolean enabled) {
listenerEnabled = enabled;
}
/**
@return true, if the View listeners are currently enabled, false otehrwise.
*/
public static boolean getListenersEnabled() {
return listenerEnabled;
}
public void propertyChanged(Object source, int propId) {
if (! ViewChangeListener2.listenerEnabled)
return;
if (source instanceof DiagramEditor) {
// Wait until the Model is saved in file system
try {
Thread.sleep(1000);
}catch (Exception e) {}
DiagramEditor umlEditor = (DiagramEditor) source;
if (! umlEditor.isDirty()) {
try {
umlEditor.getDiagram().eResource().save(null);
} catch (Exception e){e.printStackTrace();}
ViewChangeListener2.listenerEnabled = false;
ModelChangeListener.setEnabled(false);
// editor was just saved, otherwise it would be dirty.
// -> synchronize model every time the view is saved
String openEditorName=umlEditor.getTitle();
String viewPath = this.project.getLocation()
.append(GlobalConstants.getPyUmlDir())
.append(openEditorName.replace(GlobalConstants.getDiagramExtension(), "")
+ GlobalConstants.getViewUmlExtension()).toOSString();
SynchronizeModelByView.synchronizeGlobalModel(viewPath, this.project);
IFile globalModelDiagramFile = this.project.getWorkspace()
.getRoot().getFile(this.project.getFullPath()
.append(GlobalConstants.getPyUmlDir())
.append(project.getName()+GlobalConstants
.getDiagramExtension()));
// close all sub-package pyUML.views of global model diagram
for ( org.eclipse.ui.IEditorReference editor :
EclipseHelperMethods.lookForOpenEditorByName(project.getName()+"::.*")) {
PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getActivePage().closeEditor(editor.getEditor(true), true);
}
// after creating model, be sure the diagram view is reloaded
/*boolean diagramOpened = null != EclipseHelperMethods
.lookForOpenEditorByName(project.getName()+GlobalConstants.getDiagramExtension());
if (diagramOpened) {
// set focus to updated diagram only if no diagram is currently active
boolean keepFocus = false;
try {
keepFocus = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getActivePage().getActiveEditor().getTitle()
.matches(".*"+GlobalConstants.getDiagramExtension());
} catch (Exception e) {
e.printStackTrace();
}
IEditorPart newPage = UMLToolsHelperMethods.refreshDiagramEditor(project, globalModelDiagramFile, keepFocus);
if (newPage != null)
newPage.addPropertyListener(new ViewChangeListener2(this.project));
}*/
UMLToolsHelperMethods.updateModelAndViewPages(this.project, openEditorName.replace(GlobalConstants.getDiagramExtension(), ""), false);
// enable Listeners only after 4 seconds, when all diagrams are reloaded
Thread t = new Thread(
new Runnable() {
public void run() {
try {
Thread.sleep(4000);
System.out.println("finish");
} catch (InterruptedException e) {
e.printStackTrace();
}
ViewChangeListener2.listenerEnabled = true;
ModelChangeListener.setEnabled(true);
System.out.println(ViewChangeListener2.listenerEnabled);
}
});
t.start();
}
}
}
}

15558
pyUml/usedDocuments/UML.ecore Executable file

File diff suppressed because it is too large Load Diff

1947
pyUml/usedDocuments/UML.uml Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,96 @@
package org.eclipse.uml2.diagram.clazz.providers;
import java.util.Arrays;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.EditPart;
import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor;
import org.eclipse.gmf.runtime.emf.ui.providers.marker.AbstractModelMarkerNavigationProvider;
import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditorPlugin;
import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditorUtil;
/**
* @generated
*/
public class UMLMarkerNavigationProvider extends
AbstractModelMarkerNavigationProvider {
/**
* @generated
*/
public static final String MARKER_TYPE = UMLDiagramEditorPlugin.ID
+ ".diagnostic"; //$NON-NLS-1$
/**
* @generated
*/
protected void doGotoMarker(IMarker marker) {
String elementId = marker
.getAttribute(
org.eclipse.gmf.runtime.common.core.resources.IMarker.ELEMENT_ID,
null);
if (elementId == null || !(getEditor() instanceof DiagramEditor)) {
return;
}
DiagramEditor editor = (DiagramEditor) getEditor();
Map editPartRegistry = editor.getDiagramGraphicalViewer()
.getEditPartRegistry();
EObject targetView = editor.getDiagram().eResource().getEObject(
elementId);
if (targetView == null) {
return;
}
EditPart targetEditPart = (EditPart) editPartRegistry.get(targetView);
if (targetEditPart != null) {
UMLDiagramEditorUtil.selectElementsInDiagram(editor, Arrays
.asList(new EditPart[] { targetEditPart }));
}
}
/**
* @generated
*/
public static void deleteMarkers(IResource resource) {
try {
resource.deleteMarkers(MARKER_TYPE, true, IResource.DEPTH_ZERO);
} catch (CoreException e) {
UMLDiagramEditorPlugin.getInstance().logError(
"Failed to delete validation markers", e); //$NON-NLS-1$
}
}
/**
* @generated
*/
public static IMarker addMarker(IFile file, String elementId,
String location, String message, int statusSeverity) {
IMarker marker = null;
try {
marker = file.createMarker(MARKER_TYPE);
marker.setAttribute(IMarker.MESSAGE, message);
marker.setAttribute(IMarker.LOCATION, location);
marker
.setAttribute(
org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID,
elementId);
int markerSeverity = IMarker.SEVERITY_INFO;
if (statusSeverity == IStatus.WARNING) {
markerSeverity = IMarker.SEVERITY_WARNING;
} else if (statusSeverity == IStatus.ERROR
|| statusSeverity == IStatus.CANCEL) {
markerSeverity = IMarker.SEVERITY_ERROR;
}
marker.setAttribute(IMarker.SEVERITY, markerSeverity);
} catch (CoreException e) {
UMLDiagramEditorPlugin.getInstance().logError(
"Failed to create validation marker", e); //$NON-NLS-1$
}
return marker;
}
}

View File

@ -0,0 +1,463 @@
package org.eclipse.uml2.diagram.clazz.providers;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.draw2d.FlowLayout;
import org.eclipse.draw2d.Label;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
import org.eclipse.gef.EditDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.editparts.AbstractConnectionEditPart;
import org.eclipse.gmf.runtime.common.core.service.AbstractProvider;
import org.eclipse.gmf.runtime.common.core.service.IOperation;
import org.eclipse.gmf.runtime.common.ui.resources.FileChangeManager;
import org.eclipse.gmf.runtime.common.ui.resources.IFileObserver;
import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil;
import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditDomain;
import org.eclipse.gmf.runtime.diagram.ui.services.decorator.AbstractDecorator;
import org.eclipse.gmf.runtime.diagram.ui.services.decorator.CreateDecoratorsOperation;
import org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecorator;
import org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorProvider;
import org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorTarget;
import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.gmf.runtime.notation.Edge;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.uml2.diagram.clazz.edit.parts.PackageEditPart;
import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditor;
import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditorPlugin;
import org.eclipse.uml2.diagram.clazz.part.UMLVisualIDRegistry;
/**
* @generated
*/
public class UMLValidationDecoratorProvider extends AbstractProvider implements
IDecoratorProvider {
public static Resource usedResource = null;
/**
* @generated
*/
private static final String KEY = "validationStatus"; //$NON-NLS-1$
/**
* @generated
*/
private static final String MARKER_TYPE = UMLDiagramEditorPlugin.ID
+ ".diagnostic"; //$NON-NLS-1$
/**
* @generated
*/
private static MarkerObserver fileObserver;
/**
* @generated
*/
private static Map/*<String, List<IDecorator>>*/allDecorators = new HashMap();
/**
* @generated
*/
public void createDecorators(IDecoratorTarget decoratorTarget) {
EditPart editPart = (EditPart) decoratorTarget
.getAdapter(EditPart.class);
if (editPart instanceof GraphicalEditPart
|| editPart instanceof AbstractConnectionEditPart) {
Object model = editPart.getModel();
if ((model instanceof View)) {
View view = (View) model;
if (!(view instanceof Edge) && !view.isSetElement()) {
return;
}
}
EditDomain ed = editPart.getViewer().getEditDomain();
if (!(ed instanceof DiagramEditDomain)) {
return;
}
if (((DiagramEditDomain) ed).getEditorPart() instanceof UMLDiagramEditor) {
decoratorTarget.installDecorator(KEY, new StatusDecorator(
decoratorTarget));
}
}
}
/**
* @generated
*/
public boolean provides(IOperation operation) {
if (!(operation instanceof CreateDecoratorsOperation)) {
return false;
}
IDecoratorTarget decoratorTarget = ((CreateDecoratorsOperation) operation)
.getDecoratorTarget();
View view = (View) decoratorTarget.getAdapter(View.class);
return view != null
&& PackageEditPart.MODEL_ID.equals(UMLVisualIDRegistry
.getModelID(view));
}
/**
* @generated
*/
public static void refreshDecorators(View view) {
refreshDecorators(ViewUtil.getIdStr(view), view.getDiagram());
}
/**
* @generated
*/
private static void refreshDecorators(String viewId, Diagram diagram) {
final List decorators = viewId != null ? (List) allDecorators
.get(viewId) : null;
if (decorators == null || decorators.isEmpty() || diagram == null) {
return;
}
final Diagram fdiagram = diagram;
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
public void run() {
try {
if (UMLValidationDecoratorProvider.usedResource == null)
UMLValidationDecoratorProvider.usedResource = fdiagram.eResource();
if (UMLValidationDecoratorProvider.usedResource == null)
return;
TransactionalEditingDomain domain =
TransactionalEditingDomain.Factory.INSTANCE.getEditingDomain(
UMLValidationDecoratorProvider.usedResource.getResourceSet());
domain.runExclusive(
new Runnable() {
public void run() {
for (Iterator it = decorators.iterator(); it
.hasNext();) {
IDecorator decorator = (IDecorator) it
.next();
decorator.refresh();
}
}
});
} catch (Exception e) {
UMLDiagramEditorPlugin.getInstance().logError(
"Decorator refresh failure", e); //$NON-NLS-1$
}
}
});
}
/**
* @generated
*/
public static class StatusDecorator extends AbstractDecorator {
/**
* @generated
*/
private String viewId;
/**
* @generated
*/
public StatusDecorator(IDecoratorTarget decoratorTarget) {
super(decoratorTarget);
try {
final View view = (View) getDecoratorTarget().getAdapter(
View.class);
TransactionUtil.getEditingDomain(view).runExclusive(
new Runnable() {
public void run() {
StatusDecorator.this.viewId = view != null ? ViewUtil
.getIdStr(view)
: null;
}
});
} catch (Exception e) {
UMLDiagramEditorPlugin.getInstance().logError(
"ViewID access failure", e); //$NON-NLS-1$
}
}
/**
* @generated
*/
public void refresh() {
removeDecoration();
View view = (View) getDecoratorTarget().getAdapter(View.class);
if (view == null || view.eResource() == null) {
return;
}
EditPart editPart = (EditPart) getDecoratorTarget().getAdapter(
EditPart.class);
if (editPart == null || editPart.getViewer() == null) {
return;
}
// query for all the validation markers of the current resource
String elementId = ViewUtil.getIdStr(view);
if (elementId == null) {
return;
}
int severity = IMarker.SEVERITY_INFO;
IMarker foundMarker = null;
IResource resource = WorkspaceSynchronizer
.getFile(view.eResource());
if (resource == null || !resource.exists()) {
return;
}
IMarker[] markers = null;
try {
markers = resource.findMarkers(MARKER_TYPE, true,
IResource.DEPTH_INFINITE);
} catch (CoreException e) {
UMLDiagramEditorPlugin.getInstance().logError(
"Validation markers refresh failure", e); //$NON-NLS-1$
}
if (markers == null || markers.length == 0) {
return;
}
Label toolTip = null;
for (int i = 0; i < markers.length; i++) {
IMarker marker = markers[i];
String attribute = marker
.getAttribute(
org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID,
""); //$NON-NLS-1$
if (attribute.equals(elementId)) {
int nextSeverity = marker.getAttribute(IMarker.SEVERITY,
IMarker.SEVERITY_INFO);
Image nextImage = getImage(nextSeverity);
if (foundMarker == null) {
foundMarker = marker;
toolTip = new Label(marker.getAttribute(
IMarker.MESSAGE, ""), //$NON-NLS-1$
nextImage);
} else {
if (toolTip.getChildren().isEmpty()) {
Label comositeLabel = new Label();
FlowLayout fl = new FlowLayout(false);
fl.setMinorSpacing(0);
comositeLabel.setLayoutManager(fl);
comositeLabel.add(toolTip);
toolTip = comositeLabel;
}
toolTip.add(new Label(marker.getAttribute(
IMarker.MESSAGE, ""), //$NON-NLS-1$
nextImage));
}
severity = (nextSeverity > severity) ? nextSeverity
: severity;
}
}
if (foundMarker == null) {
return;
}
// add decoration
if (editPart instanceof org.eclipse.gef.GraphicalEditPart) {
if (view instanceof Edge) {
setDecoration(getDecoratorTarget().addConnectionDecoration(
getImage(severity), 50, true));
} else {
int margin = -1;
if (editPart instanceof org.eclipse.gef.GraphicalEditPart) {
margin = MapModeUtil.getMapMode(
((org.eclipse.gef.GraphicalEditPart) editPart)
.getFigure()).DPtoLP(margin);
}
setDecoration(getDecoratorTarget()
.addShapeDecoration(getImage(severity),
IDecoratorTarget.Direction.NORTH_EAST,
margin, true));
}
getDecoration().setToolTip(toolTip);
}
}
/**
* @generated
*/
private Image getImage(int severity) {
String imageName = ISharedImages.IMG_OBJS_ERROR_TSK;
switch (severity) {
case IMarker.SEVERITY_ERROR:
imageName = ISharedImages.IMG_OBJS_ERROR_TSK;
break;
case IMarker.SEVERITY_WARNING:
imageName = ISharedImages.IMG_OBJS_WARN_TSK;
break;
default:
imageName = ISharedImages.IMG_OBJS_INFO_TSK;
}
return PlatformUI.getWorkbench().getSharedImages().getImage(
imageName);
}
/**
* @generated
*/
public void activate() {
if (viewId == null) {
return;
}
// add self to global decorators registry
List list = (List) allDecorators.get(viewId);
if (list == null) {
list = new ArrayList(2);
list.add(this);
allDecorators.put(viewId, list);
} else if (!list.contains(this)) {
list.add(this);
}
// start listening to changes in resources
View view = (View) getDecoratorTarget().getAdapter(View.class);
if (view == null) {
return;
}
Diagram diagramView = view.getDiagram();
if (diagramView == null) {
return;
}
if (fileObserver == null) {
FileChangeManager.getInstance().addFileObserver(
fileObserver = new MarkerObserver(diagramView));
}
}
/**
* @generated
*/
public void deactivate() {
if (viewId == null) {
return;
}
// remove self from global decorators registry
List list = (List) allDecorators.get(viewId);
if (list != null) {
list.remove(this);
if (list.isEmpty()) {
allDecorators.remove(viewId);
}
}
// stop listening to changes in resources if there are no more decorators
if (fileObserver != null && allDecorators.isEmpty()) {
FileChangeManager.getInstance()
.removeFileObserver(fileObserver);
fileObserver = null;
}
super.deactivate();
}
}
/**
* @generated
*/
static class MarkerObserver implements IFileObserver {
/**
* @generated
*/
private Diagram diagram;
/**
* @generated
*/
private MarkerObserver(Diagram diagram) {
this.diagram = diagram;
}
/**
* @generated
*/
public void handleFileRenamed(IFile oldFile, IFile file) {
}
/**
* @generated
*/
public void handleFileMoved(IFile oldFile, IFile file) {
}
/**
* @generated
*/
public void handleFileDeleted(IFile file) {
}
/**
* @generated
*/
public void handleFileChanged(IFile file) {
}
/**
* @generated
*/
public void handleMarkerAdded(IMarker marker) {
if (marker
.getAttribute(
org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID,
null) != null) {
handleMarkerChanged(marker);
}
}
/**
* @generated
*/
public void handleMarkerDeleted(IMarker marker, Map attributes) {
String viewId = (String) attributes
.get(org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID);
refreshDecorators(viewId, diagram);
}
/**
* @generated
*/
public void handleMarkerChanged(IMarker marker) {
if (!MARKER_TYPE.equals(getType(marker))) {
return;
}
String viewId = marker
.getAttribute(
org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID,
""); //$NON-NLS-1$
refreshDecorators(viewId, diagram);
}
/**
* @generated
*/
private String getType(IMarker marker) {
try {
return marker.getType();
} catch (CoreException e) {
UMLDiagramEditorPlugin.getInstance().logError(
"Validation marker refresh failure", e); //$NON-NLS-1$
return ""; //$NON-NLS-1$
}
}
}
}

View File

@ -0,0 +1,367 @@
package org.eclipse.uml2.diagram.clazz.providers;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.emf.validation.model.IClientSelector;
import org.eclipse.emf.validation.service.IBatchValidator;
import org.eclipse.emf.validation.service.ITraversalStrategy;
import org.eclipse.gmf.runtime.common.ui.services.action.contributionitem.AbstractContributionItemProvider;
import org.eclipse.gmf.runtime.common.ui.util.IWorkbenchPartDescriptor;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.jface.action.IAction;
import org.eclipse.uml2.diagram.clazz.edit.parts.PackageEditPart;
import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditorPlugin;
import org.eclipse.uml2.diagram.clazz.part.UMLVisualIDRegistry;
import org.eclipse.uml2.diagram.clazz.part.ValidateAction;
/**
* @generated
*/
public class UMLValidationProvider extends AbstractContributionItemProvider {
/**
* @generated
*/
private static boolean constraintsActive = false;
/**
* @generated
*/
public static boolean shouldConstraintsBePrivate() {
return false;
}
/**
* @generated
*/
protected IAction createAction(String actionId,
IWorkbenchPartDescriptor partDescriptor) {
if (ValidateAction.VALIDATE_ACTION_KEY.equals(actionId)) {
return new ValidateAction(partDescriptor);
}
return super.createAction(actionId, partDescriptor);
}
/**
* @generated
*/
public static void runWithConstraints(View view, Runnable op) {
final Runnable fop = op;
Runnable task = new Runnable() {
public void run() {
try {
constraintsActive = true;
fop.run();
} finally {
constraintsActive = false;
}
}
};
TransactionalEditingDomain txDomain = TransactionUtil
.getEditingDomain(view);
if (txDomain != null) {
try {
txDomain.runExclusive(task);
} catch (Exception e) {
UMLDiagramEditorPlugin.getInstance().logError(
"Validation action failed", e); //$NON-NLS-1$
}
} else {
task.run();
}
}
/**
* @generated
*/
static boolean isInDefaultEditorContext(Object object) {
if (shouldConstraintsBePrivate() && !constraintsActive) {
return false;
}
if (object instanceof View) {
return constraintsActive
&& PackageEditPart.MODEL_ID.equals(UMLVisualIDRegistry
.getModelID((View) object));
}
return true;
}
/**
* @generated
*/
static final Map semanticCtxIdMap = new HashMap();
/**
* @generated
*/
public static class DefaultCtx1 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static class DefaultCtx2 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static class DefaultCtx3 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static class DefaultCtx4 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static class DefaultCtx5 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static class DefaultCtx6 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static class DefaultCtx7 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static class DefaultCtx8 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static class DefaultCtx9 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static class DefaultCtx10 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static class DefaultCtx11 implements IClientSelector {
/**
* @generated
*/
public boolean selects(Object object) {
return isInDefaultEditorContext(object);
}
}
/**
* @generated
*/
public static ITraversalStrategy getNotationTraversalStrategy(
IBatchValidator validator) {
return new CtxSwitchStrategy(validator);
}
/**
* @generated
*/
private static class CtxSwitchStrategy implements ITraversalStrategy {
/**
* @generated
*/
private ITraversalStrategy defaultStrategy;
/**
* @generated
*/
private String currentSemanticCtxId;
/**
* @generated
*/
private boolean ctxChanged = true;
/**
* @generated
*/
private EObject currentTarget;
/**
* @generated
*/
private EObject preFetchedNextTarget;
/**
* @generated
*/
CtxSwitchStrategy(IBatchValidator validator) {
this.defaultStrategy = validator.getDefaultTraversalStrategy();
}
/**
* @generated
*/
public void elementValidated(EObject element, IStatus status) {
defaultStrategy.elementValidated(element, status);
}
/**
* @generated
*/
public boolean hasNext() {
return defaultStrategy.hasNext();
}
/**
* @generated
*/
public boolean isClientContextChanged() {
if (preFetchedNextTarget == null) {
preFetchedNextTarget = next();
prepareNextClientContext(preFetchedNextTarget);
}
return ctxChanged;
}
/**
* @generated
*/
public EObject next() {
EObject nextTarget = preFetchedNextTarget;
if (nextTarget == null) {
nextTarget = defaultStrategy.next();
}
this.preFetchedNextTarget = null;
return this.currentTarget = nextTarget;
}
/**
* @generated
*/
public void startTraversal(Collection traversalRoots,
IProgressMonitor monitor) {
defaultStrategy.startTraversal(traversalRoots, monitor);
}
/**
* @generated
*/
private void prepareNextClientContext(EObject nextTarget) {
if (nextTarget != null && currentTarget != null) {
if (nextTarget instanceof View) {
String id = ((View) nextTarget).getType();
String nextSemanticId = id != null
&& semanticCtxIdMap.containsKey(id) ? id : null;
if ((currentSemanticCtxId != null && !currentSemanticCtxId
.equals(nextSemanticId))
|| (nextSemanticId != null && !nextSemanticId
.equals(currentSemanticCtxId))) {
this.ctxChanged = true;
}
currentSemanticCtxId = nextSemanticId;
} else {
// context of domain model
this.ctxChanged = currentSemanticCtxId != null;
currentSemanticCtxId = null;
}
} else {
this.ctxChanged = false;
}
}
}
/**
* @generated
*/
static class JavaAudits {
}
}

View File

@ -0,0 +1,297 @@
package org.eclipse.uml2.diagram.clazz.part;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.emf.validation.model.EvaluationMode;
import org.eclipse.emf.validation.model.IConstraintStatus;
import org.eclipse.emf.validation.service.IBatchValidator;
import org.eclipse.emf.validation.service.ModelValidationService;
import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gmf.runtime.common.ui.util.IWorkbenchPartDescriptor;
import org.eclipse.gmf.runtime.diagram.ui.OffscreenEditPartFactory;
import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart;
import org.eclipse.gmf.runtime.emf.core.util.EMFCoreUtil;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.WorkspaceModifyDelegatingOperation;
import org.eclipse.uml2.diagram.clazz.providers.UMLMarkerNavigationProvider;
import org.eclipse.uml2.diagram.clazz.providers.UMLValidationProvider;
/**
* @generated
*/
public class ValidateAction extends Action {
/**
* @generated
*/
public static final String VALIDATE_ACTION_KEY = "validateAction"; //$NON-NLS-1$
/**
* @generated
*/
private IWorkbenchPartDescriptor workbenchPartDescriptor;
/**
* @generated
*/
public ValidateAction(IWorkbenchPartDescriptor workbenchPartDescriptor) {
setId(VALIDATE_ACTION_KEY);
setText(Messages.ValidateActionMessage);
this.workbenchPartDescriptor = workbenchPartDescriptor;
}
/**
* @generated
*/
public void run() {
IWorkbenchPart workbenchPart = workbenchPartDescriptor.getPartPage()
.getActivePart();
if (workbenchPart instanceof IDiagramWorkbenchPart) {
final IDiagramWorkbenchPart part = (IDiagramWorkbenchPart) workbenchPart;
try {
new WorkspaceModifyDelegatingOperation(
new IRunnableWithProgress() {
public void run(IProgressMonitor monitor)
throws InterruptedException,
InvocationTargetException {
runValidation(part.getDiagramEditPart(), part
.getDiagram());
}
}).run(new NullProgressMonitor());
} catch (Exception e) {
UMLDiagramEditorPlugin.getInstance().logError(
"Validation action failed", e); //$NON-NLS-1$
}
}
}
/**
* @generated
*/
public static void runValidation(View view) {
try {
if (UMLDiagramEditorUtil.openDiagram(view.eResource())) {
IEditorPart editorPart = PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getActivePage()
.getActiveEditor();
if (editorPart instanceof IDiagramWorkbenchPart) {
runValidation(((IDiagramWorkbenchPart) editorPart)
.getDiagramEditPart(), view);
} else {
runNonUIValidation(view);
}
}
} catch (Exception e) {
UMLDiagramEditorPlugin.getInstance().logError(
"Validation action failed", e); //$NON-NLS-1$
}
}
/**
* @generated
*/
public static void runNonUIValidation(View view) {
DiagramEditPart diagramEditPart = OffscreenEditPartFactory
.getInstance().createDiagramEditPart(view.getDiagram());
runValidation(diagramEditPart, view);
}
/**
* @generated
*/
public static void runValidation(DiagramEditPart diagramEditPart, View view) {
final DiagramEditPart fpart = diagramEditPart;
final View fview = view;
UMLValidationProvider.runWithConstraints(view, new Runnable() {
public void run() {
validate(fpart, fview);
}
});
}
/**
* @generated
*/
private static Diagnostic runEMFValidator(View target) {
if (target.isSetElement() && target.getElement() != null) {
return new Diagnostician() {
public String getObjectLabel(EObject eObject) {
return EMFCoreUtil.getQualifiedName(eObject, true);
}
}.validate(target.getElement());
}
return Diagnostic.OK_INSTANCE;
}
/**
* @generated
*/
private static void validate(DiagramEditPart diagramEditPart, View view) {
IFile target = view.eResource() != null ? WorkspaceSynchronizer
.getFile(view.eResource()) : null;
if (target != null) {
UMLMarkerNavigationProvider.deleteMarkers(target);
}
Diagnostic diagnostic = runEMFValidator(view);
createMarkers(target, diagnostic, diagramEditPart);
IBatchValidator validator = (IBatchValidator) ModelValidationService
.getInstance().newValidator(EvaluationMode.BATCH);
validator.setIncludeLiveConstraints(true);
if (view.isSetElement() && view.getElement() != null) {
IStatus status = validator.validate(view.getElement());
createMarkers(target, status, diagramEditPart);
}
}
/**
* @generated
*/
private static void createMarkers(IFile target, IStatus validationStatus,
DiagramEditPart diagramEditPart) {
if (validationStatus.isOK()) {
return;
}
final IStatus rootStatus = validationStatus;
List allStatuses = new ArrayList();
UMLDiagramEditorUtil.LazyElement2ViewMap element2ViewMap = new UMLDiagramEditorUtil.LazyElement2ViewMap(
diagramEditPart.getDiagramView(), collectTargetElements(
rootStatus, new HashSet(), allStatuses));
for (Iterator it = allStatuses.iterator(); it.hasNext();) {
IConstraintStatus nextStatus = (IConstraintStatus) it.next();
View view = UMLDiagramEditorUtil.findView(diagramEditPart,
nextStatus.getTarget(), element2ViewMap);
addMarker(diagramEditPart.getViewer(), target, view.eResource()
.getURIFragment(view), EMFCoreUtil.getQualifiedName(
nextStatus.getTarget(), true), nextStatus.getMessage(),
nextStatus.getSeverity());
}
}
/**
* @generated
*/
private static void createMarkers(IFile target,
Diagnostic emfValidationStatus, DiagramEditPart diagramEditPart) {
if (emfValidationStatus.getSeverity() == Diagnostic.OK) {
return;
}
final Diagnostic rootStatus = emfValidationStatus;
List allDiagnostics = new ArrayList();
UMLDiagramEditorUtil.LazyElement2ViewMap element2ViewMap = new UMLDiagramEditorUtil.LazyElement2ViewMap(
diagramEditPart.getDiagramView(), collectTargetElements(
rootStatus, new HashSet(), allDiagnostics));
for (Iterator it = emfValidationStatus.getChildren().iterator(); it
.hasNext();) {
Diagnostic nextDiagnostic = (Diagnostic) it.next();
List data = nextDiagnostic.getData();
if (data != null && !data.isEmpty()
&& data.get(0) instanceof EObject) {
EObject element = (EObject) data.get(0);
View view = UMLDiagramEditorUtil.findView(diagramEditPart,
element, element2ViewMap);
addMarker(
diagramEditPart.getViewer(),
target,
view.eResource().getURIFragment(view),
EMFCoreUtil.getQualifiedName(element, true),
nextDiagnostic.getMessage(),
diagnosticToStatusSeverity(nextDiagnostic.getSeverity()));
}
}
}
/**
* @generated
*/
private static void addMarker(EditPartViewer viewer, IFile target,
String elementId, String location, String message,
int statusSeverity) {
if (target == null) {
return;
}
UMLMarkerNavigationProvider.addMarker(target, elementId, location,
message, statusSeverity);
}
/**
* @generated
*/
private static int diagnosticToStatusSeverity(int diagnosticSeverity) {
if (diagnosticSeverity == Diagnostic.OK) {
return IStatus.OK;
} else if (diagnosticSeverity == Diagnostic.INFO) {
return IStatus.INFO;
} else if (diagnosticSeverity == Diagnostic.WARNING) {
return IStatus.WARNING;
} else if (diagnosticSeverity == Diagnostic.ERROR
|| diagnosticSeverity == Diagnostic.CANCEL) {
return IStatus.ERROR;
}
return IStatus.INFO;
}
/**
* @generated
*/
private static Set collectTargetElements(IStatus status,
Set targetElementCollector, List allConstraintStatuses) {
if (status instanceof IConstraintStatus) {
targetElementCollector
.add(((IConstraintStatus) status).getTarget());
allConstraintStatuses.add(status);
}
if (status.isMultiStatus()) {
IStatus[] children = status.getChildren();
for (int i = 0; i < children.length; i++) {
collectTargetElements(children[i], targetElementCollector,
allConstraintStatuses);
}
}
return targetElementCollector;
}
/**
* @generated
*/
private static Set collectTargetElements(Diagnostic diagnostic,
Set targetElementCollector, List allDiagnostics) {
List data = diagnostic.getData();
EObject target = null;
if (data != null && !data.isEmpty() && data.get(0) instanceof EObject) {
target = (EObject) data.get(0);
targetElementCollector.add(target);
allDiagnostics.add(diagnostic);
}
if (diagnostic.getChildren() != null
&& !diagnostic.getChildren().isEmpty()) {
for (Iterator it = diagnostic.getChildren().iterator(); it
.hasNext();) {
collectTargetElements((Diagnostic) it.next(),
targetElementCollector, allDiagnostics);
}
}
return targetElementCollector;
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

19
pyUml_updatesite/.project Executable file
View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>pyUml_updatesite</name>
<comment></comment>
<projects>
<project>pyUml</project>
<project>pyUML_feature</project>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.pde.UpdateSiteBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.UpdateSiteNature</nature>
</natures>
</projectDescription>

105
pyUml_updatesite/artifacts.xml Executable file
View File

@ -0,0 +1,105 @@
<?xml version='1.0' encoding='UTF-8'?>
<?artifactRepository class='org.eclipse.equinox.internal.p2.artifact.repository.simple.SimpleArtifactRepository' version='1.0.0'?>
<repository name='file:/home/didi/workspace/pyUml_updatesite/ - artifacts' type='org.eclipse.equinox.p2.artifact.repository.simpleRepository' version='1.0.0'>
<properties size='2'>
<property name='p2.compressed' value='false'/>
<property name='p2.timestamp' value='1244722879655'/>
</properties>
<mappings size='3'>
<rule filter='(&amp; (classifier=osgi.bundle))' output='${repoUrl}/plugins/${id}_${version}.jar'/>
<rule filter='(&amp; (classifier=binary))' output='${repoUrl}/binary/${id}_${version}'/>
<rule filter='(&amp; (classifier=org.eclipse.update.feature))' output='${repoUrl}/features/${id}_${version}.jar'/>
</mappings>
<artifacts size='14'>
<artifact classifier='org.eclipse.update.feature' id='pyUML' version='1.2.1'>
<properties size='2'>
<property name='artifact.size' value='4963'/>
<property name='download.size' value='4963'/>
</properties>
</artifact>
<artifact classifier='osgi.bundle' id='pyUml' version='1.2.0'>
<properties size='3'>
<property name='artifact.size' value='551466'/>
<property name='download.size' value='551466'/>
<property name='download.contentType' value='application/zip'/>
</properties>
</artifact>
<artifact classifier='org.eclipse.update.feature' id='pyUML-experimental' version='1.2.2'>
<properties size='2'>
<property name='artifact.size' value='4976'/>
<property name='download.size' value='4976'/>
</properties>
</artifact>
<artifact classifier='osgi.bundle' id='pyUml-experimental' version='1.2.2'>
<properties size='3'>
<property name='artifact.size' value='556653'/>
<property name='download.size' value='556653'/>
<property name='download.contentType' value='application/zip'/>
</properties>
</artifact>
<artifact classifier='org.eclipse.update.feature' id='pyUML' version='1.2.1'>
<properties size='2'>
<property name='artifact.size' value='4980'/>
<property name='download.size' value='4980'/>
</properties>
</artifact>
<artifact classifier='org.eclipse.update.feature' id='pyUML-experimental' version='1.2.2'>
<properties size='2'>
<property name='artifact.size' value='4980'/>
<property name='download.size' value='4980'/>
</properties>
</artifact>
<artifact classifier='osgi.bundle' id='pyUml-experimental' version='1.2.2'>
<properties size='3'>
<property name='artifact.size' value='556646'/>
<property name='download.size' value='556646'/>
<property name='download.contentType' value='application/zip'/>
</properties>
</artifact>
<artifact classifier='osgi.bundle' id='pyUml' version='1.2.0'>
<properties size='3'>
<property name='artifact.size' value='554276'/>
<property name='download.size' value='554276'/>
<property name='download.contentType' value='application/zip'/>
</properties>
</artifact>
<artifact classifier='org.eclipse.update.feature' id='pyUML' version='1.2.1'>
<properties size='2'>
<property name='artifact.size' value='900'/>
<property name='download.size' value='900'/>
</properties>
</artifact>
<artifact classifier='org.eclipse.update.feature' id='pyUML' version='1.2.2'>
<properties size='2'>
<property name='artifact.size' value='4974'/>
<property name='download.size' value='4974'/>
</properties>
</artifact>
<artifact classifier='org.eclipse.update.feature' id='pyUML' version='1.2.0'>
<properties size='2'>
<property name='artifact.size' value='725'/>
<property name='download.size' value='725'/>
</properties>
</artifact>
<artifact classifier='osgi.bundle' id='pyUml' version='1.2.1'>
<properties size='3'>
<property name='artifact.size' value='554945'/>
<property name='download.size' value='554945'/>
<property name='download.contentType' value='application/zip'/>
</properties>
</artifact>
<artifact classifier='org.eclipse.update.feature' id='pyUML' version='1.2.2'>
<properties size='2'>
<property name='artifact.size' value='4980'/>
<property name='download.size' value='4980'/>
</properties>
</artifact>
<artifact classifier='osgi.bundle' id='pyUml' version='1.2.2'>
<properties size='3'>
<property name='artifact.size' value='555052'/>
<property name='download.size' value='555052'/>
<property name='download.contentType' value='application/zip'/>
</properties>
</artifact>
</artifacts>
</repository>

388
pyUml_updatesite/content.xml Executable file

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

10
pyUml_updatesite/site.xml Executable file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<site>
<description url="http://eclipse-pyuml.sourceforge.net/update_site_experimental">
Eclipse PyUML Update Site
</description>
<feature url="features/pyUML-experimental_1.2.2.jar" id="pyUML-experimental" version="1.2.2">
<category name="Eclipse PyUML Experimental"/>
</feature>
<category-def name="Eclipse PyUML Experimental" label="Eclipse PyUML Experimental"/>
</site>