diff --git a/MS SQL sqljdbc_auth.dll/x64/mssql-jdbc_auth-8.2.2.x64.dll b/MS SQL sqljdbc_auth.dll/x64/mssql-jdbc_auth-8.2.2.x64.dll
new file mode 100644
index 00000000..a1717a01
Binary files /dev/null and b/MS SQL sqljdbc_auth.dll/x64/mssql-jdbc_auth-8.2.2.x64.dll differ
diff --git a/MS SQL sqljdbc_auth.dll/x86/mssql-jdbc_auth-8.2.2.x86.dll b/MS SQL sqljdbc_auth.dll/x86/mssql-jdbc_auth-8.2.2.x86.dll
new file mode 100644
index 00000000..43c43fda
Binary files /dev/null and b/MS SQL sqljdbc_auth.dll/x86/mssql-jdbc_auth-8.2.2.x86.dll differ
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..6670a8ac
--- /dev/null
+++ b/README.md
@@ -0,0 +1,9 @@
+### Archimate Tool Database-Plugin
+Database export/import plugin that store models in a central repository.
+
+### The plugin adds the following functionalities to Archi
+* Export and import models to a relational database (PostGreSQL, MySQL, MS SQL Server, Oracle or SQLite)
+* Export elements and relationships to a graph database (Neo4J)
+* Version the models and all their components (keep an history and allow to retrieve a former version)
+* Share elements, relationships and views between models
+
diff --git a/license.txt b/license.txt
new file mode 100644
index 00000000..ab64a207
--- /dev/null
+++ b/license.txt
@@ -0,0 +1,63 @@
+THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
+
+BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
+
+1. Definitions
+
+"Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License.
+"Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(g) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License.
+"Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership.
+"License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, Noncommercial, ShareAlike.
+"Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License.
+"Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast.
+"Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work.
+"You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.
+"Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images.
+"Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium.
+2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws.
+
+3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below:
+
+to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections;
+to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified.";
+to Distribute and Publicly Perform the Work including as incorporated in Collections; and,
+to Distribute and Publicly Perform Adaptations.
+The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved, including but not limited to the rights described in Section 4(e).
+
+4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:
+
+You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(d), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(d), as requested.
+You may Distribute or Publicly Perform an Adaptation only under: (i) the terms of this License; (ii) a later version of this License with the same License Elements as this License; (iii) a Creative Commons jurisdiction license (either this or a later license version) that contains the same License Elements as this License (e.g., Attribution-NonCommercial-ShareAlike 3.0 US) ("Applicable License"). You must include a copy of, or the URI, for Applicable License with every copy of each Adaptation You Distribute or Publicly Perform. You may not offer or impose any terms on the Adaptation that restrict the terms of the Applicable License or the ability of the recipient of the Adaptation to exercise the rights granted to that recipient under the terms of the Applicable License. You must keep intact all notices that refer to the Applicable License and to the disclaimer of warranties with every copy of the Work as included in the Adaptation You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Adaptation, You may not impose any effective technological measures on the Adaptation that restrict the ability of a recipient of the Adaptation from You to exercise the rights granted to that recipient under the terms of the Applicable License. This Section 4(b) applies to the Adaptation as incorporated in a Collection, but this does not require the Collection apart from the Adaptation itself to be made subject to the terms of the Applicable License.
+You may not exercise any of the rights granted to You in Section 3 above in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation. The exchange of the Work for other copyrighted works by means of digital file-sharing or otherwise shall not be considered to be intended for or directed toward commercial advantage or private monetary compensation, provided there is no payment of any monetary compensation in con-nection with the exchange of copyrighted works.
+If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and, (iv) consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4(d) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties.
+For the avoidance of doubt:
+
+Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License;
+Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License if Your exercise of such rights is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(c) and otherwise waives the right to collect royalties through any statutory or compulsory licensing scheme; and,
+Voluntary License Schemes. The Licensor reserves the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License that is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(c).
+Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise.
+5. Representations, Warranties and Disclaimer
+
+UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING AND TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO THIS EXCLUSION MAY NOT APPLY TO YOU.
+
+6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. Termination
+
+This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.
+Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.
+8. Miscellaneous
+
+Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.
+Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License.
+If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
+No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.
+This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.
+The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law.
+Creative Commons Notice
+
+Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor.
+
+Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, Creative Commons does not authorize the use by either party of the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of this License.
+
+Creative Commons may be contacted at https://creativecommons.org/.
\ No newline at end of file
diff --git a/sources/.classpath b/sources/.classpath
new file mode 100644
index 00000000..d8e36fff
--- /dev/null
+++ b/sources/.classpath
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sources/.gitignore b/sources/.gitignore
new file mode 100644
index 00000000..ae3c1726
--- /dev/null
+++ b/sources/.gitignore
@@ -0,0 +1 @@
+/bin/
diff --git a/sources/.project b/sources/.project
new file mode 100644
index 00000000..a3364718
--- /dev/null
+++ b/sources/.project
@@ -0,0 +1,17 @@
+
+
+ org.archicontribs.database
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/sources/.settings/org.eclipse.jdt.core.prefs b/sources/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..6993c07b
--- /dev/null
+++ b/sources/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,142 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.builder.cleanOutputFolder=clean
+org.eclipse.jdt.core.builder.duplicateResourceTask=error
+org.eclipse.jdt.core.builder.invalidClasspath=abort
+org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore
+org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch
+org.eclipse.jdt.core.circularClasspath=error
+org.eclipse.jdt.core.classpath.exclusionPatterns=enabled
+org.eclipse.jdt.core.classpath.mainOnlyProjectHasTestOnlyDependency=error
+org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled
+org.eclipse.jdt.core.classpath.outputOverlappingAnotherSource=error
+org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=enabled
+org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
+org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnull.secondary=
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary=
+org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=11
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.doc.comment.support=enabled
+org.eclipse.jdt.core.compiler.maxProblemPerUnit=100
+org.eclipse.jdt.core.compiler.problem.APILeak=error
+org.eclipse.jdt.core.compiler.problem.annotatedTypeArgumentToUnannotated=info
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=error
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=error
+org.eclipse.jdt.core.compiler.problem.deadCode=error
+org.eclipse.jdt.core.compiler.problem.deprecation=error
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=enabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=error
+org.eclipse.jdt.core.compiler.problem.emptyStatement=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=error
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=error
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=error
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=error
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=error
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=error
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=enabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=error
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=error
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=error
+org.eclipse.jdt.core.compiler.problem.invalidJavadoc=ignore
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=private
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=error
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error
+org.eclipse.jdt.core.compiler.problem.missingDefaultCase=error
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=error
+org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=enabled
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=error
+org.eclipse.jdt.core.compiler.problem.missingJavadocComments=warning
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=all_standard_tags
+org.eclipse.jdt.core.compiler.problem.missingJavadocTags=warning
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsMethodTypeParameters=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=private
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=error
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=error
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=error
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=error
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=error
+org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=error
+org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
+org.eclipse.jdt.core.compiler.problem.nullReference=error
+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=error
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=error
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=error
+org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=error
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=error
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=error
+org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=warning
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=error
+org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=error
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=error
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=error
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=error
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=error
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=enabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=error
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=enabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.suppressWarningsNotFullyAnalysed=info
+org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=error
+org.eclipse.jdt.core.compiler.problem.terminalDeprecation=error
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=error
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=ignore
+org.eclipse.jdt.core.compiler.problem.unclosedCloseable=error
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=error
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=error
+org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=error
+org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=enabled
+org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=error
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=error
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=error
+org.eclipse.jdt.core.compiler.problem.unstableAutoModuleName=error
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=error
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=error
+org.eclipse.jdt.core.compiler.problem.unusedImport=error
+org.eclipse.jdt.core.compiler.problem.unusedLabel=error
+org.eclipse.jdt.core.compiler.problem.unusedLocal=error
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=error
+org.eclipse.jdt.core.compiler.problem.unusedParameter=error
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error
+org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=error
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=error
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=11
+org.eclipse.jdt.core.incompatibleJDKLevel=info
+org.eclipse.jdt.core.incompleteClasspath=error
diff --git a/sources/.settings/org.eclipse.jdt.launching.prefs b/sources/.settings/org.eclipse.jdt.launching.prefs
new file mode 100644
index 00000000..66b8d5c5
--- /dev/null
+++ b/sources/.settings/org.eclipse.jdt.launching.prefs
@@ -0,0 +1,3 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.launching.PREF_COMPILER_COMPLIANCE_DOES_NOT_MATCH_JRE=error
+org.eclipse.jdt.launching.PREF_STRICTLY_COMPATIBLE_JRE_NOT_AVAILABLE=error
diff --git a/sources/META-INF/MANIFEST.MF b/sources/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..a2648d0d
--- /dev/null
+++ b/sources/META-INF/MANIFEST.MF
@@ -0,0 +1,32 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Database export / import plugin for Archimate Tool
+Bundle-SymbolicName: org.archicontribs.database;singleton:=true
+Bundle-Version: 4.9.0.alpha
+Bundle-Vendor: Herve Jouin
+Bundle-Localization: plugin
+Bundle-RequiredExecutionEnvironment: JavaSE-11
+Bundle-ClassPath: .,
+ lib/json-simple-1.1.1.jar,
+ lib/log4j-1.2.17.jar,
+ lib/lombok.jar,
+ lib/neo4j-jdbc-driver-4.0.0.jar,
+ lib/ojdbc10.jar,
+ lib/postgresql-42.2.12.jar,
+ lib/sqlite-jdbc-3.30.1.jar,
+ lib/mssql-jdbc-8.2.2.jre11.jar,
+ lib/mysql-connector-java-5.1.48.jar,
+ lib/orai18n.jar
+Bundle-ActivationPolicy: lazy
+Bundle-Activator: org.archicontribs.database.DBPlugin
+Require-Bundle: org.eclipse.core.runtime,
+ com.archimatetool.editor,
+ com.archimatetool.canvas,
+ com.archimatetool.help,
+ org.eclipse.swt,
+ com.archimatetool.model,
+ org.eclipse.emf.ecore,
+ org.eclipse.help,
+ com.archimatetool.commandline
+Export-Package: org.archicontribs.database
+Import-Package: org.eclipse.nebula.widgets.gallery
diff --git a/sources/build.properties b/sources/build.properties
new file mode 100644
index 00000000..c60e2cf0
--- /dev/null
+++ b/sources/build.properties
@@ -0,0 +1,13 @@
+source.. = src/
+output.. = bin/
+jars.compile.order = .
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ help/,\
+ img/,\
+ lib/,\
+ build.properties,\
+ help_contexts.xml,\
+ bin/
+src.includes = src/
diff --git a/sources/help/help.xml b/sources/help/help.xml
new file mode 100644
index 00000000..13556215
--- /dev/null
+++ b/sources/help/help.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sources/help/html/componentsHistory.html b/sources/help/html/componentsHistory.html
new file mode 100644
index 00000000..cc1bfb79
--- /dev/null
+++ b/sources/help/html/componentsHistory.html
@@ -0,0 +1,23 @@
+
+
+
+
+
+ Preference page
+
+
+
+
+Components history
+It is possible to gather any component's history in the database by selecting the get history option in the context menu (right click).
+
+
+
+It is possible to get the history from any database declared in the preference page:
+
+ Selecting a specific version will compare this version to the one in the current Archi model. All the differences will be highlighted in red.
+ If the current version is different from the latest version in the database, then it will be possible to export the current version to the database using the Export to the database button.
+ If the selected database version is different from the current version, it will be possible to replace the current version by the selected version in Archi using the Import database version button.
+
+
+
\ No newline at end of file
diff --git a/sources/help/html/configurePlugin.html b/sources/help/html/configurePlugin.html
new file mode 100644
index 00000000..1046863a
--- /dev/null
+++ b/sources/help/html/configurePlugin.html
@@ -0,0 +1,170 @@
+
+
+
+
+
+ Configure plugin
+
+
+
+
+Configure the plugin
+
+The plugin can be configured through a preference page that can be accessed using Archi's menu: Edit / Preference / Database plugin.
+
+This preference page provides two tabs:
+
+
+Behaviour
+This tab allows to change the plugin behaviour.
+
+
+Version
+This box shows up the actual plugin's version.
+The check for update button allows to check if a new version is available on GitHub and automatically download it.
+The Automatically check for update at startup allows to automate this check when Archi is started.
+
+Should Archi be behind a corporate proxy, one may define the following entries in the Archi.ini file:
+
+
+
+
+Databases
+This box shows an array with all the databases that have been defined to to plugin.
+
+Databases must be defined with the following information:
+
+ Name : Name of the database entry in the array. This is just a label and may contain spaces but it must be unique.
+ Driver : Driver used to connect to the database. This supported drivers are:
+ ms-sql for Microsoft SQL Server databases
+ mysql for MySQL and MariaDB databases
+ neo4j for Neo4J graph databases
+ oracle for Oracle databases
+ postgresql for PostGreSql databases
+ sqlite for SQLite databases
+
+
+
+Client/server relational databases
+
+
+In addition, the following information is required for MS-SQL, MySQL, Oracle and PostGreSql databases:
+
+ Server or IP : DNS name or IP address of the server where the database stands
+ Port : TCP port on which the server listens
+ Database name : Name of the database (lease empty to connect to the default database)
+ Schema : Name of the schema (leave empty to connect to the default schema)
+ Username and Password : Credentials used to connect to the database
+ Export view snapshots : Choose if the plugin should export a snapshot on the views in the database (PNG format). In this case, you must choose the:
+ Border width in pixels (between 0 and 50)
+ Scale factor in percentage (between 10% and 500%)
+
+
+
+SQLite databases
+
+
+In addition, the following information is required for SQLite databases:
+
+ File : Path of the database file. On Windows, the file may be hosted on a network drive. The Browse button allows to browse the desktop disks to choose the database file.
+ Export view snapshots : Choose if the plugin should export a snapshot on the views in the database (PNG format). In this case, you must choose the:
+ Border width in pixels (between 0 and 50)
+ Scale factor in percentage (between 10% and 500%)
+
+
+
+Neo4j databases
+
+
+In addition, the following information is required for Neo4j databases:
+
+ Server or IP : DNS name or IP address of the server where the database stands
+ Port : TCP port on which the server listens. Please note that the plugin uses the bolt protocol. Therefore, the default port is 7878 , not 7474.
+ Username and Password : Credentials used to connect to the database
+ Empty database: : Choose what the plugin should do before exporting the model:
+ Empty database before every export : the plugin deletes all the existing graphs, thus leaving the database with a single graph with the model content
+ Leave database content : the plugin leaves the existing graphs, and creates a new one with the model content. As all the model components are versionned, exporting the same model several times will leads to one graph per export.
+
+ Relationships type : Choose what type of relationship the export plugin should create in the graph:
+ Use unique relationships type : One single relationship type called "relationships" will be created. The "class" property will be set to distinguish the different Archi relationships types.
+ Use typed relationships : The plugin will create one relationship type per Archi relationship (FlowRelationship, AccessRelationship, InfluenceRelationship...).
+
+
+
+Miscellaneous
+You may change the behaviour of the database plugin by selecting or un-selecting the following options:
+
+ Automatically start to export to the default database
+ The plugin shows up the export window but automatically starts the export to the first database declared in the database list (one may use the up and down arrows to order your databases in the list).
+ The plugin shows up the export window and waits for the user to click on the "Export" button.
+
+ Automatically close import and export windows on success
+ When the import/export is successful, the import window /export window is automatically closed
+ Even if the import/export is successful, the user needs to click on the "close" button in order to close the window.
+
+ Show zero values on import and export windows
+ A zero in shown in cases when no component is imported/exported.
+ Cases are left emptywhen no component is imported/exported.
+
+ Check max memory available at startup
+ As the plugin requires memory to work, it can check that Archi is ran with enough memory when it is initialized (at least 1 GB).
+ The plugin won't check for the available memory during its initialization.
+
+ Remove model's dirty flag after successful export
+ After a successful export, the model's dirty flag is removed so the model will be considered as saved by Archi (Archi will not ask to save the model to an Archimate file when it is closed).
+ The model's dirty flag is not removed, even after a successful export, so a popup will be displayed when Archi is closed, asking to save the model to an Archimate file.
+ Compare model to the database before export
+ The plugin compares the model components to the database content and shows up the result in the export window . This slows down a bit the export process but the user knows what the export process will do in the database.
+ The plugin does not compare the model to the database until the user clicks on the "Export". This quicks up a bit the export process, but the user does not know in advance what the plugin will do in the database before he clicks on the "Export" button.
+
+ Keep partially imported model in case of error
+ In case of an error during the import of a model, the plugin keeps the partially imported model. Please note that this option is for debugging purpose, you must never export back a partially imported model, else you will corrupt your model in the database. Use this option at your own risks.
+ The plugin does not keep in memory any partially imported model (highly recommended).
+
+ Show debugging information in context menu
+ Adds a context menu entry that leads to debugging information (ID, version, checksum, database status, ...).
+ The debug context menu entry will be hidden.
+
+ Append suffix when import component in copy mode
+ It is possible to change the suffix that is added to components' name when the are imported in copy mode from the database.
+
+
+
+Online help
+All the database plugin windows have got a button that shows up these help pages.
+
+
+Logger
+The logger tab allows to specify a log file and the level of information to store in this log file.
+Disabled
+When disabled, the logger does not generate any log nor error message.
+
+Simple mode
+
+In simple mode, one should only specify the level of information and a filename (on Windows, it is not necessary to double the backslashes).
+
+Please note that enabling debug or, even more, trace level has got an impact on the plugin performances. You may activate it only if required.
+
+Expert mode
+
+In expert mode, you are provided with a simple text editor and you may configure the Log4j logger manually (on Windows, it is necessary to double the backslashes).
+
+This mode is very powerful, as you may specify several log files, with different level of information. You may also change the lines format.
+
+This option must be reserved to people who have knowledge about Log4j as a bad configuration can stop the plugin from working correctly. In all cases, it is always possible to restore a safe and working configuration using the "Restore defaults" button.
+
+
\ No newline at end of file
diff --git a/sources/help/html/databaseStructure.html b/sources/help/html/databaseStructure.html
new file mode 100644
index 00000000..713d7a2d
--- /dev/null
+++ b/sources/help/html/databaseStructure.html
@@ -0,0 +1,1345 @@
+
+
+
+
+
+ Database structure
+
+
+
+
+Database structure
+
+This page describes the structure of the tables needed by the database plugin in relational databases.
+
+
+Tables
+database_version
+This table allows the plugin to quickly check that the database has got the requested tables without checking all of them one by one.
+It contains one line per plugin that has got tables in this database (this will allow several plugins to share the same database in the future):
+
+
+
+
+
+
+
+
+ archi-plugin
+ varchar
+ x
+ The name of the plugin ("DatabasePlugin" for instance).
+
+
+ version
+ int
+ x
+ The version of the database model (for this plugin release, must be set to 209 ).
+
+
+
+Each time the plugin connects to a database, it checks the existence and the content of this table.
+
+ if the table does not exist, then it considers that all the other tables are missing and propose to create them,
+ if the table does exist but the plugin name is not listed, then the plugin refuses to work with the database,
+ if the plugin name is listed but the version is an old version, then the plugin updates the database to the newer version,
+ if the version is unknown, then the plugin refuses to work with the database.
+
+
+models
+This table contains the models metadata that are stored in the database. There is one line per model and per version:
+
+
+
+
+
+
+
+
+ id
+ varchar
+ x
+ The id of the model.
+
+
+ version
+ int
+ x
+ The version of the model (starting from 1).
+
+
+ name
+ varchar
+ x
+ The name of the model. Please note that the model name may change between one version to another, so one must not rely on the name to distinguish models but on the id instead.
+
+
+ note
+ clob
+
+ The release note associated to the version of the model.
+
+
+ purpose
+ clob
+
+ The purpose of the version of the model.
+
+
+ created_by
+ varchar
+ x
+ The name of the user who exported the version of the model to the database.
+
+
+ created_on
+ timestamp
+ x
+ The date and time when the version of the model has been exported to the database.
+
+
+ checkedin_by
+ varchar
+
+ Not used yet.
+
+
+ checkedin_on
+ timestamp
+
+ Not used yet
+
+
+ deleted_by
+ varchar
+
+ Not used yet.
+
+
+ deleted_on
+ timestamp
+
+ Not used yet.
+
+
+ checksum
+ varchar
+ x
+ A md5 checksum calculated at export time to allow versions comparison.
+
+
+
+Models may have properties .
+
+folders
+This table contains the folders that are stored in the database. Please note that this table does not link the folders to any model (c.f. folders_in_model ). There is one row per folder and per version:
+
+
+
+
+
+
+
+
+ id
+ varchar
+ x
+ The id of the folder.
+
+
+ version
+ int
+ x
+ The version of the folder (starting from 1).
+
+
+ type
+ int
+ x
+ The type of the folder (as specified by Archi):
+ 1 = strategy
+ 2 = business
+ 3 = application
+ 4 = technology
+ 5 = relations
+ 6 = other
+ 7 = diagrams
+ 8 = motivation
+ 9 = implementation and migration
+ 0 = created by user
+
+
+
+ root_type
+ int
+ x
+ The folder type of the root folder (used when the folder is created by user, i.e. when type = 0).
+
+
+ name
+ varchar
+ x
+ The name of the folder. Please note that the folder may be renamed from one version to another, so one must not rely on the name to distinguish folders but rely on the id instead.
+
+
+ documentation
+ clob
+
+ The documentation of the folder.
+
+
+ created_by
+ varchar
+ x
+ The name of the user who exported the version of the folder to the database.
+
+
+ created_on
+ timestamp
+ x
+ The date and time when the version of the folder has been exported to the database.
+
+
+ checkedin_by
+ varchar
+
+ Not used yet.
+
+
+ checkedin_on
+ timestamp
+
+ Not used yet
+
+
+ deleted_by
+ varchar
+
+ Not used yet.
+
+
+ deleted_on
+ timestamp
+
+ Not used yet.
+
+
+ checksum
+ varchar
+ x
+ A md5 checksum calculated at export time to allow versions comparison.
+
+
+
+Folders may have properties .
+
+folders_in_model
+This is a relation table that permits to know which folders is included in which model (a folder may be shared between several models). There is one row per folder and per model:
+
+
+
+
+
+
+
+
+ fim_id
+ int
+ x
+ Internal id of the row that guarantees uniqueness.
+
+
+ folder_id
+ varchar
+ x
+ The id of the folder.
+
+
+ folder_version
+ int
+ x
+ The version of the folder.
+
+
+ parent_folder_id
+ varchar
+
+ The id of the folder's parent folder in the model (a folder can be moved in the folder tree between model versions). Null if the folder is a root folder.
+
+
+ model_id
+ varchar
+ x
+ The id of the model that contains the folder.
+
+
+ model_version
+ int
+ x
+ The version of the model that contains the folder.
+
+
+ rank
+ int
+ x
+ Numerical increment that allows to import the folders in the same order they've been exported.
+
+
+
+elements
+This table contains the elements that are stored in the database. Please note that this table does not link the elements to any model (c.f. elements_in_model ). There is one row per element and per version:
+
+
+
+
+
+
+
+
+ id
+ varchar
+ x
+ The id of the element.
+
+
+ version
+ int
+ x
+ The version of the element (starting from 1).
+
+
+ class
+ varchar
+ x
+ The class of the element as stated by Archi (Node, BusinessActor, ApplicationInterface, ...).
+
+
+ name
+ varchar
+
+ The name of the element. Please note that an element can be renamed from one version to another, so one should not rely on the name to distinguish elements but rely on its id instead.
+
+
+ documentation
+ clob
+
+ The documentation of the element.
+
+
+ type
+ varchar
+
+ The type of the element (relevant when the class is Junction, null for an and junction, "or" for an or junction).
+
+
+ created_by
+ varchar
+ x
+ The name of the user who exported the version of the element to the database.
+
+
+ created_on
+ timestamp
+ x
+ The date and time when the version of the element has been exported to the database.
+
+
+ checkedin_by
+ varchar
+
+ Not used yet.
+
+
+ checkedin_on
+ timestamp
+
+ Not used yet
+
+
+ deleted_by
+ varchar
+
+ Not used yet.
+
+
+ deleted_on
+ timestamp
+
+ Not used yet.
+
+
+ checksum
+ varchar
+ x
+ A md5 checksum calculated at export time to allow versions comparison.
+
+
+
+Elements may have properties .
+
+elements_in_model
+This is a relation table that permits to know which elements is included in which model (an element may be shared between several models). There is one row per element and per model:
+
+
+
+
+
+
+
+
+ eim_id
+ int
+ x
+ Internal id of the row that guarantees uniqueness.
+
+
+ element_id
+ varchar
+ x
+ The id of the element.
+
+
+ element_version
+ int
+ x
+ The version of the element.
+
+
+ parent_folder_id
+ varchar
+ x
+ The id of the element's parent folder in the model (an element can be moved in the folder tree between model versions).
+
+
+ model_id
+ varchar
+ x
+ The id of the model that contains the element.
+
+
+ model_version
+ int
+ x
+ The version of the model that contains the element.
+
+
+ rank
+ int
+ x
+ Numerical increment that allows to import the elements in the same order they've been exported.
+
+
+
+relationships
+This table contains the relationships that are stored in the database. Please note that this table does not link the relationships to any model (c.f. relationships_in_model ). There is one row per relationship and per version:
+
+
+
+
+
+
+
+
+ id
+ varchar
+ x
+ The id of the relationship.
+
+
+ version
+ int
+ x
+ The version of the relationship.
+
+
+ class
+ varchar
+ x
+ The class of the relationship as stated by Archi (CompositionRelationship, ServingRelationship, ...).
+
+
+ name
+ varchar
+
+ The name if the relationship. Please note that the relationship may be renamed from one version to another, so you must not rely on the name to distinguish relationships but rely on the id instead.
+
+
+ documentation
+ clob
+
+ The documentation of the relationship.
+
+
+ source_id
+ varchar
+
+ The id of the element or relationship that this relationship sources.
+
+
+ target_id
+ varchar
+ x
+ The id of the the element or the relationship that this relationship targets.
+
+
+ strength
+ varchar
+
+ The strength of the relationship (relevant when the class is InfluenceRelationship).
+
+
+ access_type
+ varchar
+
+ The access type of the relationship (relevant when the class is AccessRelationship).
+
+
+ created_by
+ varchar
+ x
+ The name of the user who exported the version of the relationship to the database.
+
+
+ created_on
+ timestamp
+ x
+ The date and time when the version of the relationship has been exported to the database.
+
+
+ checkedin_by
+ varchar
+
+ Not used yet.
+
+
+ checkedin_on
+ timestamp
+
+ Not used yet
+
+
+ deleted_by
+ varchar
+
+ Not used yet.
+
+
+ deleted_on
+ timestamp
+
+ Not used yet.
+
+
+ checksum
+ varchar
+ x
+ A md5 checksum calculated at export time to allow versions comparison.
+
+
+
+Relationships may have properties .
+
+relationships_in_model
+This is a relation table that permits to know which relationships is included in which model (a relationship may be shared between several models). There is one row per relationship and per model:
+
+
+
+
+
+
+
+
+ rim_id
+ int
+ x
+ Internal id of the row that guarantees uniqueness.
+
+
+ relationship_id
+ varchar
+ x
+ The id of the relationship.
+
+
+ relationship_version
+ int
+ x
+ The version of the relationship.
+
+
+ parent_folder_id
+ varchar
+ x
+ The id of the relationship's parent folder in the model (a relationship can be moved in the folder tree between model versions).
+
+
+ model_id
+ varchar
+ x
+ The id of the model that contains the relationship.
+
+
+ model_version
+ int
+ x
+ The version of the model that contains the relationship.
+
+
+ rank
+ int
+ x
+ Numerical increment that allows to import the relationships in the same order they've been exported.
+
+
+
+views
+This table contains the views (diagrams, canvas and sketchs) that are stored in the database. Please note that this table does not link the views to any model (c.f. views_in_model ). There is one row per view and per version:
+
+
+
+
+
+
+
+
+ id
+ varchar
+ x
+ The id of the view.
+
+
+ version
+ int
+ x
+ The version of the view.
+
+
+ class
+ varchar
+ x
+ The class of the view as specified by Archi (may be one of ArchimateDiagramModel, CanvasModel or SketchModel).
+
+
+ name
+ varchar
+
+ The name of the view. Please note that the view may be renamed from one version to another, so you must not rely on the name to distinguish views but rely on the id instead.
+
+
+ documentation
+ clob
+
+ The documentation of the view.
+
+
+ background
+ int
+
+ The background of the view (relevant if the class is SketchModel).
+
+
+ connection_router_type
+ int
+ x
+ The connection router type of the view.
+
+
+ viewpoint
+ varchar
+
+ The viewpoint of the view (relevant if the class is ArchimateDiagramModel).
+
+
+ screenshot
+ clob
+
+ Screenshot of the view (only when option is activated in the plugin preferences).
+
+
+ created_by
+ varchar
+ x
+ The name of the user who exported the version of the view to the database.
+
+
+ created_on
+ timestamp
+ x
+ The date and time when the version of the view has been exported to the database.
+
+
+ checkedin_by
+ varchar
+
+ Not used yet.
+
+
+ checkedin_on
+ timestamp
+
+ Not used yet
+
+
+ deleted_by
+ varchar
+
+ Not used yet.
+
+
+ deleted_on
+ timestamp
+
+ Not used yet.
+
+
+ checksum
+ varchar
+ x
+ A md5 checksum that includes the view object content (when it is a container), calculated at export time to allow versions comparison.
+
+
+ container_checksum
+ varchar
+ x
+ A md5 checksum that does not includes the view object content (when it is a container), calculated at export time to allow versions comparison.
+
+
+
+Views may have properties .
+
+views_in_model
+This is a relation table that permits to know which views is included in which model (a view may be shared between several models). There is one row per view and per model:
+
+
+
+
+
+
+
+
+ vim_id
+ int
+ x
+ Internal id of the row that guarantees uniqueness.
+
+
+ view_id
+ varchar
+ x
+ The id of the view.
+
+
+ view_version
+ int
+ x
+ The version of the view.
+
+
+ parent_folder_id
+ varchar
+ x
+ The id of the view's parent folder in the model (a view can be moved in the folder tree between model versions).
+
+
+ model_id
+ varchar
+ x
+ The id of the model that contains the view.
+
+
+ model_version
+ int
+ x
+ The version of the model that contains the view.
+
+
+ rank
+ int
+ x
+ Numerical increment that allows to import the views in the same order they've been exported.
+
+
+
+views_objects
+This table contains the graphical objects (representation of elements, notes, ...) that are present in the model views. There is one line per graphical object and per version:
+
+
+
+
+
+
+
+
+ id
+ varchar
+ x
+ The id of the view object.
+
+
+ version
+ int
+ x
+ The version of the view object (starting from 1).
+
+
+ class
+ varchar
+ x
+ The class of the view object as stated by Archi (may be one of CanvasModelBlock, CanvasModelImage, DiagramModelArchimateObject, DiagramModelGroup, DiagramModelReference, SketchModelActor, SketchModelSticky).
+
+
+ container_id
+ varchar
+ x
+ Id of the container that directly contains the view object (a view object can be contained by a view or by another view object).
+
+
+ element_id
+ varchar
+
+ Id of the Archimate element that the view object refers to if any.
+
+
+ element_version
+ int
+
+ Version of the Archimate element that the view object refers to if any.
+
+
+ diagram_ref_id
+ varchar
+
+ Id of the view referenced by the view object if the class is DiagramModelReference.
+
+
+ border_color
+ varchar
+
+ Color of the view object border.
+
+
+ border_type
+ int
+
+ Type of the view object border.
+
+
+ content
+ clob
+
+ Text content of the view object if the class is CanvasModelBlock or CanvasModelSticky.
+
+
+ documentation
+ clob
+
+ Documentation of the view object (only if the view object does not refer to an element, else the documentation of the element is used).
+
+
+ is_locked
+ boolean
+
+ The lock status of the view object
+
+
+ image_path
+ varchar
+
+ The path of the image displayed inside the view object (relevant when class is CanvasBlock or CanvasImage).
+
+
+ image_position
+ int
+
+ The position of the image inside the view object.
+
+
+ line_color
+ varchar
+
+ The line color of the view object.
+
+
+ line_width
+ int
+
+ The line width of the view object.
+
+
+ fill_color
+ varchar
+
+ The background color used to fill the view object.
+
+
+ alpha
+ integer
+
+ The alpha (transparency) of the view object, from 0 (transparent) to 255(opaque).
+
+
+ font
+ varchar
+
+ The font used to display the view object label.
+
+
+ font_color
+ varchar
+
+ The color used display the view object label.
+
+
+ name
+ varchar
+
+ The name of the view object (used only if the view object does not refer to an element, else the name of the element is used).
+
+
+ notes
+ clob
+
+ The notes of the view object.
+
+
+ text_alignment
+ int
+
+ Horizontal alignment of the text in the view object.
+
+
+ text_position
+ int
+
+ Vertical alignment of the text in the view object.
+
+
+ type
+ int
+
+ Type of the view object.
+
+
+ x
+ int
+
+ X coordinate of the view object inside its container.
+
+
+ y
+ int
+
+ Y coordinate of the view object inside its container.
+
+
+ width
+ int
+
+ Width of the view object.
+
+
+ height
+ int
+
+ Height of the view object.
+
+
+ created_by
+ varchar
+ x
+ The name of the user who exported the version of the view object to the database.
+
+
+ created_on
+ timestamp
+ x
+ The date and time when the version of the view object has been exported to the database.
+
+
+ checkedin_by
+ varchar
+
+ Not used yet.
+
+
+ checkedin_on
+ timestamp
+
+ Not used yet
+
+
+ deleted_by
+ varchar
+
+ Not used yet.
+
+
+ deleted_on
+ timestamp
+
+ Not used yet.
+
+
+ checksum
+ varchar
+ x
+ A md5 checksum calculated at export time to allow versions comparison.
+
+
+
+views_objects_in_view
+This is a relation table that permits to know which view object is included in which view. There is one row per view object and per view:
+
+
+
+
+
+
+
+
+ oiv_id
+ int
+ x
+ Internal id of the row that guarantees uniqueness.
+
+
+ object_id
+ varchar
+ x
+ The id of the view object.
+
+
+ object_version
+ int
+ x
+ The version of the view object.
+
+
+ view_id
+ varchar
+ x
+ The id of the view that contains the view object.
+
+
+ view_version
+ int
+ x
+ The version of the view that contains the view object.
+
+
+ rank
+ int
+ x
+ Numerical increment that allows to import the views objects in the same order they've been exported.
+
+
+
+views_connections
+This table contains the graphical connections (representation of relationships) that are present in the model views. There is one line per graphical connection and per version:
+
+
+
+
+
+
+
+
+ id
+ varchar
+ x
+ Id of the view connection.
+
+
+ version
+ int
+ x
+ Version of the view connection (starting from 1).
+
+
+ class
+ varchar
+ x
+ Class of the view connection as stated by Archi (DiagramModelArchimateConnection, DiagramModelConnection or CanvasModelConnection)
+
+
+ container_id
+ varchar
+ x
+ Id of the container that directly contains the view connection (view connections can be contained by a view or a view object ).
+
+
+ relationship_id
+ varchar
+
+ the id of the Archimate relationship referred by the view connection if any.
+
+
+ relationship_version
+ int
+
+ The version of the Archimte relationship referred by the view connection if any.
+
+
+ name
+ varchar
+
+ The name of the view connection (used only if the view connection does not refer to a relationship, else the name of the relationship is used).
+
+
+ documentation
+ clob
+
+ The documentation of the view connection (only if the view connection does not refer to a relationship, else the documentation of the relationship is used)
+
+
+ is_locked
+ boolean
+
+ The locked status of the view connection.
+
+
+ line_color
+ varchar
+
+ The line color of the view connection.
+
+
+ line_width
+ int
+
+ The line width of the view connection.
+
+
+ font
+ varchar
+
+ The font used to display the view connection label.
+
+
+ font_color
+ varchar
+
+ The color used to display the view connection label.
+
+
+ source_object_id
+ varchar
+
+ Id of the view object or view connection that this view connection sources.
+
+
+ target_object_id
+ varchar
+
+ Id of the view object or view connection that this view connection targets.
+
+
+ text_position
+ int
+
+ Vertical alignment of the text in the view object.
+
+
+ type
+ int
+
+ Type of the view connection.
+
+
+ created_by
+ varchar
+ x
+ The name of the user who exported the version of the view connection to the database.
+
+
+ created_on
+ timestamp
+ x
+ The date and time when the version of the view connection has been exported to the database.
+
+
+ checkedin_by
+ varchar
+
+ Not used yet.
+
+
+ checkedin_on
+ timestamp
+
+ Not used yet
+
+
+ deleted_by
+ varchar
+
+ Not used yet.
+
+
+ deleted_on
+ timestamp
+
+ Not used yet.
+
+
+ checksum
+ varchar
+ x
+ A md5 checksum calculated at export time to allow versions comparison.
+
+
+View connections are compound of bendpoints .
+
+views_connections_in_view
+This is a relation table that permits to know which view connection is included in which view. There is one row per view connection and per view:
+
+
+
+
+
+
+
+
+ civ_id
+ int
+ x
+ Internal id of the row that guarantees uniqueness.
+
+
+ connection_id
+ varchar
+ x
+ The id of the view connection.
+
+
+ connection_version
+ int
+ x
+ The version of the view connection.
+
+
+ view_id
+ varchar
+ x
+ The id of the view that contains the view connection.
+
+
+ view_version
+ int
+ x
+ The version of the view that contains the view connection.
+
+
+ rank
+ int
+ x
+ Numerical increment that allows to import the views connections in the same order they've been exported.
+
+
+
+bendpoints
+Views connections are compound of bendpoints. There is one row per bendpoint and per view connection:
+
+
+ parent_id
+ varchar
+ x
+ Id of the view connection.
+
+
+ parent_version
+ int
+ x
+ Version of the view connection.
+
+
+ rank
+ int
+ x
+ Numerical increment that allows to import properties in the same order they've been exported.
+
+
+ start_x
+ int
+ x
+ X coordinate of the point starting the segment.
+
+
+ start_y
+ int
+ x
+ Y coordinate of the point starting the segment.
+
+
+ end_x
+ int
+ x
+ X coordinate of the point ending the segment.
+
+
+ end_y
+ int
+ x
+ Y coordinate of the point ending the segment.
+
+
+
+images
+This table contains the images of CanvasBlock and CanvasImage objects. There is one line per image:
+
+
+
+
+
+
+
+
+ path
+ varchar
+ x
+ Path of the image as calculated by Archi.
+
+
+ image
+ blob
+
+ image itself in PNG format.
+
+
+
+properties
+Models , folders , elements , relationships and views may have properties. There is one row per property and per parent:
+
+
+ parent_id
+ varchar
+ x
+ Id of the component that owns the property.
+
+
+ parent_version
+ int
+ x
+ Version of the component that owns the property.
+
+
+ rank
+ int
+ x
+ Numerical increment that allows to import properties in the same order they've been exported.
+
+
+ name
+ varchar
+
+ Name of the property.
+
+
+ value
+ varchar
+
+ Value of the property.
+
+
+
+
\ No newline at end of file
diff --git a/sources/help/html/exportModel.html b/sources/help/html/exportModel.html
new file mode 100644
index 00000000..fe7b8dfc
--- /dev/null
+++ b/sources/help/html/exportModel.html
@@ -0,0 +1,101 @@
+
+
+
+
+
+ Model export
+
+
+
+
+Export a model to a database
+
+This page describes how to export a model in a database.
+
+To export a model to a database, you first need to select the model to export, then either access the File / Export / Export model to database menu option of Archi, or right-click on the model's name and select the Export model to database context menu option.
+The graphical interface
+As every window of the database plugin, the export window is split in 5 zones:
+
+ The left zone shows the plugin's logo and the list of actions.
+ The right hand-side of the export window is split in 3 zones:
+
+ The database selection
+ The versions of the model
+ The model's components
+
+
+
+
+The database selection
+This section allows to select the database where the model should be exported. The databases are presented in the order defined on the preference page.
+
+The "set preferences" button allows to directly open the preference page to update the database list or set preferences.
+
+Please note that it is possible to export any model in any database, even if the model has been imported from another database or loaded from an Archimate file.
+The versions of the model
+This section lists the versions of the model that already exist in the database.
+
+The "Now" line represents the version that will be exported in the database. It allows to change the model name and purpose, but also to set a release note.
+
+The model's components
+This section lists how many components are present in your model.
+
+The plugin can also show the comparison between the model as it is in Archi and as it is in the database.
+
+To achieve this comparison, the plugin uses the components ID to check if it already exists in the database:
+
+ If the component does not exist in the database:
+ The component is assumed to be a new component created by Archi, either manually or loaded from an Archimate file --> The component will be created in the database.
+
+ If the component does exist in the database:
+
+ The plugin calculates the current checksum and retrieves all the other needed checksums and versions from the database:
+ The component's "initial version and checksum" that is the latest version in the database that has got the same checksum,
+ The component's "latest version and checksum" that is the latest version in the database that is part of the same model,
+ The component's "latest database version and checksum" that is the latest version in the database whatever the model the component is in.
+
+ Then it is then possible to compare all the versions and checksums:
+ If the "latest version" and the "latest database version" are equal, then the component has not been updated by another model (thus, only the "current checksum" and "initial checksum" are relevant):
+ If the "current checksum" and "initial checksum" are identical then the component is in sync with the database --> it does not need to be exported to the database
+ If the "current checksum" and "initial checksum" differ then the component has been updated in Archi --> it needs to be exported to the database
+
+ If the "database version" is zero then the component does not exist anymore in the latest version of the model in the database --> it needs to be deleted in Archi
+ If the "current checksum" is identical to the "latest database checksum" then the component is in sync with the database --> it does not need to be exported to the database
+ If the "initial checksum" differs from the the "current checksum" then the component has been updated in Archi
+ If the "initial checksum" differs from the the "database checksum" then the component has been updated in the database
+ If the component has been updated in Archi but not in the database --> it needs to be exported to the database
+ If the component has been updated in the database but not in Archi --> it needs to be updated in Archi with the values from the database
+ If the component has been updated in both Archi and the database:
+ If the "current checksum" and "database checksum" are identical, then the same modifications have been done in Archi and in the database --> it does not need to be exported to the database
+ If they differ, then the modifications done in Archi and in the database are different --> there is a conflict that needs to be manually resolved by the user
+
+
+
+
+
+During this check, the plugin also lists all the components that are referenced in the database version of the model but that are not in Archi --> they will be imported from the database .
+
+The plugin shows the number of components in each situation, either automatically if configured in the preferences, either when the user clicks on the "Compare model to the database" button.
+
+The export process
+When the user clicks on the "export" button, the plugin:
+
+ Recalculates the status of all the components as it may have changed since the last comparison,
+ Imports missing components from the database and update those that have been updated in the database,
+ Exports components that have been updated in Archi,
+ References all the model components as been pat of the model (even those that do not need to be exported),
+ If conflicts are detected, the user is invited to resolve them.
+
+As the export process may take some time, the databases list is replaced by a progress bar to show the export progress.
+
+At the end of the export process, the progress bar is replaced by a status message with a color that highlights the export status (green if successful, yellow in case of error). In case of any error, the export is rolled-back and the database is left untouched. This behavior allows to guarantee the database coherence.
+
+The export to the database cannot be undone, but in case some components have been imported or updated during the export process, the whole import/update can be undone using Archi undo/redo mechanism (menu Undo/Redo or keys ctrl-Z/ctrl-Y).
+
+Conflict resolution
+Undo / redo
+All the imports or updates done during the export process can be undone using the Ctrl-Z key or Archi's menu, and redone using the Ctrl-Y key or Archi's menu.
+
+Nevertheless, one a new version is written to the database, it cannot be undone.
+
+
\ No newline at end of file
diff --git a/sources/help/html/importComponent.html b/sources/help/html/importComponent.html
new file mode 100644
index 00000000..110a41e2
--- /dev/null
+++ b/sources/help/html/importComponent.html
@@ -0,0 +1,65 @@
+
+
+
+
+
+ Single component import
+
+
+
+
+Import components from a database
+This page describes how to import components from a database.
+
+To import a component, you need to right-click on any existing model's component and select the Import components from database context menu option.
+
+The graphical interface
+As every window of the database plugin, the export window is split in 5 zones:
+
+ The left zone shows the plugin's logo and the list of actions.
+ The right hand-side of the export window is split in 3 zones:
+ The database selection
+ The class of components to import
+ The components to import
+
+
+The database selection
+This section allows to select the database from where the components should be imported. The databases are presented in the order defined on the preference page.
+
+The "set preferences" button allows to directly open the preference page to update the database list or set preferences.
+
+Please note that the Neo4j databases are not presented here as only exporting is supported to Neo4j databases.
+
+The class of components to import
+At this stage, you need to choose if you wish to import a model (i.e. merge a model), an element or a view (at this time, folders are not supported):
+
+
+
+
+
+
+A filter allows to show up the components whose name contain the content of the filter (the case is ignored). It is possible to use the percent sign (%) as a wildcard.
+
+When the elements type is selected, you may choose as well the classes to list in the components table. You may select/unselect a class, a complete row or a complete column by clicking on it. Please be aware that the elements list can become huge, so it would be wise not to select too mny classes at the same time if you've got many elements in your database.
+
+The components to import
+The bottom part of the window lists the models, elements or views that correspond to your choice. You may then select one or several of them.
+
+When a view is selected, a screenshot of the view is shown next to the table if the database contains views screenshots.When the mouse stands over a component, then a popup is shown with the component's properties (if it has got any).
+
+To import the selected component(s), you may either double click in the table or click on the "Import " button.
+The import modes
+The import mode allows to specify how the components will be imported. Three modes are available:
+
+ Force copy mode : in this mode, all the components will have a new ID that will be distinct from the one in the database. The imported components and the components in the database will therefore be independent: updating the ones will not impact the others.
+ Force shared mode : in this mode, all the components will be imported with their existing ID from the database. All the components will therefore be shared across the models: the updates done on those components in one model will be seen across all the models where they are present.
+ Template mode : in this mode, which allows to mix copy and shared mode, the import mode is distinct for each component and depends on their properties:
+ If the component has got a property called "template " with value "copy ": then the component is imported in copy mode ,
+ If the component doesn't have a property called "template ", or if its value is not "copy ": then the component is imported in shared mode .
+
+
+A "(copy) " mention is appended to all the components imported in copy mode. This mention can be modified or removed in the plugin's preferences.
+Undo / redo
+All the imports can be undone using the Ctrl-Z key or Archi's menu, and redone using the Ctrl-Y key or Archi's menu.
+
+
\ No newline at end of file
diff --git a/sources/help/html/importModel.html b/sources/help/html/importModel.html
new file mode 100644
index 00000000..011b8e3d
--- /dev/null
+++ b/sources/help/html/importModel.html
@@ -0,0 +1,50 @@
+
+
+
+
+
+ Model import
+
+
+
+
+Import a model from a database
+
+This page describes how to import a model from a database.
+
+To import a model from a database, you can access the File / Import / Import model from database menu option of Archi, or if no model exist in Archi, right-click on model's tree area and select the Import model from database context menu option.
+The graphical interface
+As every window of the database plugin, the import window is split in 5 zones:
+
+ The left zone shows the plugin's logo and the list of actions.
+ The right hand-side of the import window is split in 3 zones:
+
+ The database selection
+ The models
+ The versions of the selected model
+
+
+
+The database selection
+This section allows to select the database from where the model should be imported. The databases are presented in the order defined on the preference page.
+
+The "set preferences" button allows to directly open the preference page to update the database list or set preferences.
+
+Please note that the Neo4j databases are not presented here as the plugin uniquely allows exports to Neo4j databases.
+
+The models
+The models that are found in the database are presented in alphabetical order. A filter allows to limit the list to models having the specified string in their name (case insensitive). You may use the percent sign (%) as a wildcard.
+
+The versions of the selected model
+Once you select a model, the versions of the selected model are displayed.
+
+Once on select a version, it's name, purpose and release note are displayed.
+
+Importing a model
+It is possible to import a model by a double-click on the desired version, or by a simple click on the "Import " button:
+
+ When a numbered version is selected, the plugin imports the version as it was when it has been exported. This means that any update done after the export on the model components, through other models, are not taken in account.
+ When the special "latest version " version is selected, the plugin imports the latest version of all the model components, even if they've been updated through other models.
+
+
+
\ No newline at end of file
diff --git a/sources/help/html/index.html b/sources/help/html/index.html
new file mode 100644
index 00000000..c8f8799c
--- /dev/null
+++ b/sources/help/html/index.html
@@ -0,0 +1,29 @@
+
+
+
+
+
+ Table of Contents
+
+
+
+
+Database plugin
+This plugin is written by Hervé Jouin (herve.jouin@gmail.com) and extends the Archi capabilities.
+
+It allows to persist models in a database.
+
+Table of Contents
+
+
+
\ No newline at end of file
diff --git a/sources/help/html/installPlugin.html b/sources/help/html/installPlugin.html
new file mode 100644
index 00000000..799e98f5
--- /dev/null
+++ b/sources/help/html/installPlugin.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+ Preference page
+
+
+
+
+Install the plugin
+The plugin consists of a single org.archicontribs.database_xxx.jar file. There are several ways to install it.
+First installation
+Method 1 (semi-automatic installation)
+Download the org.archicontribs.database_xxx.zip ZIP file from GitHub, then open the Help/Install Archi plugin-in menu in Archi and select the downloaded zip file.
+
+Once the plugin in installed, Archi will require to restart itself.
+Method 2 (manual installation)
+Download the org.archicontribs.database_xxx.jar JAR file from GitHub and manually copy it to Archi's plugin folder.
+
+Usually, this folder is _C:\Program Files\Archi\plugins_ or _C:\Program Files (x86)\Archi\plugins_ on Windows.
+
+Once the jar file is copied, start (or restart) Archi.
+Update the plugin to a newer release
+Method 1 (automatic update)
+Once installed, the plugin is able to update itself, provided you've got an Internet connection (please check the Configure the plugin page should you require to configure a proxy).
+
+Please go to the plugin's preference page and click on the Check for update button.
+
+The plugin will indicate if a new version is available. You'll then be able to print the release note and automatically download and install the new release.
+Method 2 (manual update)
+Alternatively, you may delete the JAR file from Archi's plugin folder and use the new plugin installation procedure.
+
+
\ No newline at end of file
diff --git a/sources/help/html/pluginObjectives.html b/sources/help/html/pluginObjectives.html
new file mode 100644
index 00000000..46b9a156
--- /dev/null
+++ b/sources/help/html/pluginObjectives.html
@@ -0,0 +1,29 @@
+
+
+
+
+
+ Plugin objectives
+
+
+
+
+Plugin's objectives
+The main objective of the database plugin, as its name states, is to use a database as a central model repository .
+
+The key functionalities are:
+
+ Export models to, and import models back from a SQL database (Microsoft SQL Server, MySQL, Oracle, PostGreSQL, and SQLite are supported so far)
+ Export elements and relationships to a graph database (Neo4j) to ease impact analysis
+ Version the models and all their components:
+ Keeps a trace of who does what
+ Allows to roll back any model or component to any point in time
+
+ Allows several people to work on the dame model at the same time
+ During export, the updates done by other people are imported,
+ All the conflicts are detected and presented to the user for manual resolution.
+
+ Allow to share components between models (all the updates done on those components through one model will be visible in all the models)
+
+
+
\ No newline at end of file
diff --git a/sources/help/html/releaseNotes.html b/sources/help/html/releaseNotes.html
new file mode 100644
index 00000000..89c7d59f
--- /dev/null
+++ b/sources/help/html/releaseNotes.html
@@ -0,0 +1,288 @@
+
+
+
+
+
+ Release notes
+
+
+
+
+Database plugin
+Release notes
+
+v 2.1 (14/03/2018)
+
+ Import components from database:
+ Rename "import individual component" to "import components"
+ Added documentation column to help distinguish components having the same name
+ Added tooltip with properties to help distinguish components having the same name
+ Added message during the import as it may take some time
+ Use commands to allow undo/redo
+ Added a label to explain that the icons can be selected
+ The categories can now be clicked to select/unselect the whole category
+ The component is imported by default in the selected folder
+ The element class is pre-selected depending on the selected folder
+ In case one view is selected for import, show view screenshot if available in the database
+ Introduce new template mode that mixes shared and copy modes depending on each component properties
+ Possibility to import a whole model into another one (merge models)
+
+ Import model:
+ A context menu entry allowing to import a model has been added when no model is selected
+ Automatically open the default view (if any) at the end of the import
+ Fix number of images to import
+
+ Export model:
+ For relational databases:
+ The export is now in "collaborative mode", which syncs the model with the database:
+ It can be compared to a pull+push to GitHub.
+ It is slower than the previous mode but allows several people to work on the same model at the same time
+
+ Allow to specify border width and scale factor for views screenshots
+ To simplify, it is no more possible to choose between whole export or elements and relationships only
+
+ For Neo4J databases:
+ Create two export modes: native and extended
+ New option to empty the database before the export
+ New option to specialize relationships
+
+ Rewrite version management (check timestamps in addition of the version number)
+ Remove the name, the documentation and the properties from view objects and connections checksum calculation as they are related to the corresponding concept
+ Plugin preferences:
+ The default import mode (shared or copy) has been removed as the default import mode is now the template mode
+ Add an option to compare the model from the database before exporting it
+ Allow to specify the generated view screenshots border width and scale factor
+ Allow to specify a suffix to add to components imported in copy mode
+ Add an option to check for max memory at startup (Xmx should be set to 1g)
+ Add an option to show or hide zero values in import and export windows
+
+ Get history from database:
+ Allows to get history for diagrams, canvas and sketches
+ Allows to export/import component to/from the database directly from the history window
+
+ Other:
+ Bug fixes:
+ Exporting blocks or images objects with no images set does not generate errors anymore
+ Fix plugin initialization failure that occurred some times
+ Fix progress bar during download new version of the plugin from GitHub
+ Increase compiler severity to maximum and resolve all the warnings to improve code resiliency
+ Reduce memory leak
+ Fix centering of GUI windows, especially on hiDPI displays
+ Fix calculation of numbers of images to import
+ Better management of the cancel button during the import and export process
+ Cleanup properties before import rather than update existing values as several properties can have the same name
+ Fix centering of GUI windows especially on HiDPI displays
+
+ Improvements:
+ Fill in the online help pages
+ Rewrite debug and trace messages to be more useful
+ Add the ability to import an image from the database (on the Image and Block objects in Canvas)
+ Some annoying popups have been replaced by messages directly in the import/export window
+ Remove the name, the documentation and the properties from view objects and connections checksum as they are not related to the view objects and connections themselves, but to the related element or relationship
+ Add procedures that can be called by the script plugin
+ The inline help can be accessed using the interrogation mark on every plugin window.
+ Export and import back the model's "metadata" (may be used by other external tools)
+ Do not calculate checksum on images anymore as the path is already a kind of checksum
+ A new "show debug information" window has been created
+ Add "import model from database" menu entry on right click when no model has been loaded yet
+ Manage the objects transparency (introduced in Archi 4.3)
+ Check for max memory available at startup and suggest to increase it (Xmx parameter) if less than 1 GB
+ Add the ability to import an image from the database on Canvas Image and Block objects
+ Update JDBC drivers
+ Neo4J to 3.1.0
+ SQLite to 3.21.0
+ PostGreSQL to 42.2.1
+
+
+
+
+
+v 2.0.7b (01/07/2017)
+
+
+
+v 2.0.7 (30/06/2017)
+
+ Rollback to single thread as multi-threading causes to many side effects and does not accelerate the import and export duration as expected
+ Improve checksum mechanism
+ Add an option to show up ID and checksum in context menu rather than relying on the logger mode
+ Import model:
+ Solve bug where the filter field was not working as expected
+ Change the filter request to be case insensitive
+
+ Export model:
+ Use of a Tree rather than a Table to show up conflicts
+ Show up more information about conflicting components
+ Increase the conflict detection and resolution
+
+
+
+v 2.0.6 (30/05/2017)
+
+ Import model:
+ Solve bug when importing a model which has got a shared view which has been updated by another model
+ The import SQL request have been rewritten because of Oracle specificity
+ A double click on a model's version now launches the import
+
+ Import components from database:
+ Solve bug where all the views versions were added in the table, resulting in several entries with the same name
+
+ Database model:
+ Added column "element_version" to table "views_objects"
+ Added column "relationship_version" to table "views_connections"
+
+
+
+v 2.0.5 (17/05/2017)
+
+ Export model:
+ Change order of folders export (exporting all the root folders first)
+
+ Import model:
+ Solve bug in counting components to import prior the import itself which can cause false error messages even when the import is successful
+ Solve bug in folder import where the parent folder was not created yet before its content
+
+
+
+v 2.0.4 (11/05/2017)
+
+ Export model:
+ Solve bug where export conflicts were not detected correctly on MySQL databases
+
+ Import components from database:
+ The import type (shared or copy) can now be changed directly on the import window
+
+ Preference page:
+ Correct traversal order of fields on preference page
+ The default database port is automatically filled-in when port field is empty or equals 0
+ The default for new databases is to not export view snapshots
+ When saving preferences while editing database properties, the plugin now asks if the updates need to be saved or discarded
+
+ Miscellaneous:
+ Rewrite of the checksum calculation procedure to ensure it is always the same length
+ Rewrite of the views connections import procedure to ensure that they are imported in the same order as in the original model
+ This leads to 2 new columns (source_connections and target_connections) in the view_objects and views_connections database tables
+
+
+
+v 2.0.3 (07/05/2017)
+
+ Export model:
+ Make conflict management more reliable on PostGreSQL databases
+ Added a preference to remove the dirty flag on the model after a successful export
+ Solve bug where count of exported components could be erroneous
+
+ Import components from database:
+ Added missing "location" class
+ Add the ability to import several components at the same time
+ The components are now sorted alphabetically
+ Solve bug where the same component could be imported several times
+
+ Miscellaneous:
+ Allow to specify a database schema in the database configuration
+ It is now possible to check a database connection without the need to edit their details
+ Reduce memory consumption
+ Remove the NOT NULL constraints on some columns because Oracle does not do any difference between an empty string and a null value
+ Renamed mssql driver to ms-sql to be visually more distinctive from mysql
+
+
+
+v 2.0.2 (02/05/2017)
+
+ Solve errors during table creation in PostGreSQL database
+ Solve "Operation not allowed after ResultSet closed" error message on model export
+ Add a menu entry to replace old fashion IDs to Archi 4 IDs (to ensure uniqueness of all components)
+
+
+v 2.0.1 (01/05/2017)
+
+ Add the ability to export images of views in the database
+ Add a preference to keep the imported model even in case of error
+ Reduce memory leak
+ Added back Neo4J support (elements and relationships export only)
+ Solve NullPointerException while checking database
+
+
+v 2.0.0 (30/04/2017)
+
+ Export Model
+ Solve bug where properties were not exported correctly
+ Solve bug where connections could be exported twice
+ Rewrite the conflict detection when exporting to make it more accurate
+ Create the status page on the export model window
+ Add a popup when nothing needs to be exported
+
+ Import components from database:
+ Add the ability to hide existing components in the import component module
+
+ Get component history:
+ Solve bug where the plugin could not find the component in the database
+
+ Preferences:
+ Add a preference entry to automatically close import and export windows on success
+ Add a preference entry to automatically start to export the model to the default database
+ Add a preference entry to automatically download and install the plugin updates
+ Add a preference entry to Import components from database in shared or copy mode by default
+
+ Miscellaneous:
+ Solve bug in the logger where some multi-lines messages were not printed correctly
+ From now on, folders and views have got their own version number
+ Increase performance by reusing compiled SQL requests
+ Check database version before using it
+ Automatically create database tables if they do not exist
+ Stop replacing the folders type
+ Replaced database table "archi_plugin" by new table "database_version"
+ Opens the model in the tree after import
+
+
+
+v 2.0.0.beta4 (29/03/2017)
+
+ Correct import folders properties
+ Add version numbers of imported objects in debug mode
+ Solve MySQL compatibility issue on elements import SQL request
+ Detect folders and views changes using checksum
+
+
+v 2.0.0.beta3 (21/03/2017)
+
+ Correct preference page where some options are outside the window on some displays
+ Solve SQL duplicate key error message on model export
+ Solve bug where save button does not show up in preferences page
+
+
+v 2.0.0.beta2 (19/03/2017)
+
+ Importing an element now imports its relationships as well
+ Add import folder functionality
+ Add import view functionality
+ Change RCP methods to insert entries in menus in order to be more friendly with other plugins
+ Solve a bug with MySQL databases for which aliases in SQL joins are mandatory
+ Solve a bug in progressBar which did not represent 100%
+ Launch the import process on double-click in the model list table
+ The ID is now shown in right menu only in debug mode
+ Few java optimizations
+ Improve exceptions catching between threads
+ Replace boolean database columns by integer columns for better compatibility
+
+
+v 2.0.0.beta1 (26/02/2017) - from v1 plugin:
+
+ Added log4j support
+ Version all the elements and relationships
+ Reduce the quantity of data exported by exporting only updated components (use of checksums)
+ Detect database conflicts and add a conflict resolution mechanism
+ Reduce number of database tables
+ Reduce database table names to be compliant will all database brands
+ Add back Oracle JDBC driver
+ Temporarily remove the Neo4j driver
+ Accelerate import and export processes by using multi-threading
+ Complete rework of the graphical interface
+ Add the ability to Import components from database
+ Add inline help
+
+
+
+
\ No newline at end of file
diff --git a/sources/help/html/showDebug.html b/sources/help/html/showDebug.html
new file mode 100644
index 00000000..d9864be2
--- /dev/null
+++ b/sources/help/html/showDebug.html
@@ -0,0 +1,71 @@
+
+
+
+
+
+ Configure plugin
+
+
+
+
+Debugging information
+
+The plugin can show detailed information any component in the model.
+
+
+This debugging information can be accessed using the context menu (right-click) of the component.
+
+
+
+
+
+You may choose a database to compare the component to the database content.
+
+The fields provided are:
+
+ Name : the name of the component
+ Id : the internal ID of the component
+ Class : the class of the component
+ Image path : the path of the embedded image (if any)
+ Database status : the status of the component regarding the selected database
+
+ isSynced : The component is sync'ed with the database. It doesn't need to be exported to the database.
+ isNewInModel : The component does not exist in the database. It needs to be exported to the database.
+ isUpadtedInDatabase : The component has been updated in the database by another person (either in the same model or another one). The model needs to be updated with the new values from the database.
+ isUpdatedInModel : The component does exist in the database and has been updated in the model. The new values need to be exported to the database.
+ isDeletedInDatabase : The component does exist in the database but the latest version of the model does not includes it anymore. It needs to be deleted from the model.
+ isConflicting : The component has been updated both in the database and in the model. The conflict will have to be manually resolved during the next export process.
+
+
+
+The array provides the following columns:
+
+ Version : version of the component
+ Container checksum : checksum of the component without its content
+ Checksum : checksum of the component taking in account its content
+ Created on : date when the component has been created in the database
+
+
+These columns are provided for several states of the component:
+
+ Initial : Version of the component as it was when the model has been imported from or exported to the database.
+
+ If null, this means that the component has been created or loaded from an Archimate file.
+ Else, this means that the component has been imported from the database, or already exported to the database.
+
+ Current : Actual version of the component in the model
+ Database : Version of the component as it is registered in the latest version of the model in the database
+
+ If null, this means that the component is not part of the latest version of the model in the database
+ Else, this means that the component is part of the latest version of the model in the database
+
+ Latest database : Latest version of the component (whichever the model)
+
+ If null, then the component does not exist in the database
+ Else, the component does exist in the database.
+
+
+
+
+When the selected component is a graphical object or connection, the corresponding Archimate concept is also shown.
+
\ No newline at end of file
diff --git a/sources/help/html/style.css b/sources/help/html/style.css
new file mode 100644
index 00000000..99008a3f
--- /dev/null
+++ b/sources/help/html/style.css
@@ -0,0 +1,146 @@
+.body {
+ counter-reset: h2counter;
+}
+
+.image {
+ border: 1px solid #0;
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+ box-shadow: 10px 10px 5px #ccc;
+ -moz-box-shadow: 10px 10px 5px #ccc;
+ -webkit-box-shadow: 10px 10px 5px #ccc;
+ -khtml-box-shadow: 10px 10px 5px #ccc;
+}
+
+li.selected {
+ background: url('../img/selected.png') no-repeat left top;
+ padding-left: 20px;
+ display: block;
+}
+
+li.not_selected {
+ background: url('../img/not_selected.png') no-repeat left top;
+ padding-left: 20px;
+ display: block;
+}
+
+h1 {
+ font-size: 32px;
+ border: 1px solid grey;
+ text-shadow: -1px -1px blue, 1px 1px orange, -3px 0 4px black;
+ font-family: "Segoe print", Arial, Helvetica, sans-serif;
+ padding: 16px;
+ font-weight: lighter;
+ -moz-box-shadow: 2px 2px 6px grey;
+ -webkit-box-shadow: 2px 2px 6px grey;
+ box-shadow: 2px 2px 6px grey;
+ display: block;
+ margin: 16px;
+ counter-reset: h2counter;
+}
+
+h2 {
+ font-size: 24px;
+ border: 1px solid grey;
+ text-shadow: -1px -1px blue, 1px 1px orange, -3px 0 4px black;
+ font-family: "Segoe print", Arial, Helvetica, sans-serif;
+ padding: 0px;
+ font-weight: lighter;
+ -moz-box-shadow: 2px 2px 6px grey;
+ -webkit-box-shadow: 2px 2px 6px grey;
+ box-shadow: 2px 2px 6px grey;
+ display: block;
+ margin: 16px;
+ counter-reset: h3counter;
+}
+
+h2:before {
+ content: "\00a0\00a0" counter(h2counter) ". ";
+ counter-increment: h2counter;
+}
+
+h3 {
+ font-size: 20px;
+ border: 1px solid grey;
+ text-shadow: -1px -1px blue, 1px 1px orange, -3px 0 4px black;
+ font-family: "Segoe print", Arial, Helvetica, sans-serif;
+ padding: 0px;
+ font-weight: lighter;
+ -moz-box-shadow: 2px 2px 6px grey;
+ -webkit-box-shadow: 2px 2px 6px grey;
+ box-shadow: 2px 2px 6px grey;
+ display: block;
+ margin: 16px;
+ counter-reset: h4counter;
+}
+
+h3:before {
+ content: "\00a0\00a0" counter(h2counter) "." counter(h3counter) ". ";
+ counter-increment: h3counter;
+}
+
+h4 {
+ font-size: 18px;
+ border: 1px solid grey;
+ text-shadow: -1px -1px blue, 1px 1px orange, -3px 0 4px black;
+ font-family: "Segoe print", Arial, Helvetica, sans-serif;
+ padding: 0px;
+ font-weight: lighter;
+ -moz-box-shadow: 2px 2px 6px grey;
+ -webkit-box-shadow: 2px 2px 6px grey;
+ box-shadow: 2px 2px 6px grey;
+ display: block;
+ margin: 16px;
+ counter-reset: h5counter;
+}
+
+h4:before {
+ content: "\00a0\00a0" counter(h2counter) "." counter(h3counter) "." counter(h4counter) ". ";
+ counter-increment: h4counter;
+}
+
+.tg {
+ border-collapse: collapse;
+ border-spacing: 0;
+ border-color: #aabcfe;
+ margin-left: 10%;
+ margin-right: 10%;
+ width: 80%;
+}
+
+.tg td {
+ font-family: Arial, sans-serif;
+ font-size: 14px;
+ padding: 2px 5px;
+ border-style: solid;
+ border-width: 1px;
+ overflow: hidden;
+ word-break: normal;
+ border-color: #aabcfe;
+ color: #669;
+ background-color: #e8edff;
+}
+
+.tg th {
+ font-family: Arial, sans-serif;
+ font-size: 14px;
+ font-weight: normal;
+ padding: 10px 5px;
+ border-style: solid;
+ border-width: 1px;
+ overflow: hidden;
+ word-break: normal;
+ border-color: #aabcfe;
+ color: #039;
+ background-color: #b9c9fe;
+}
+
+.tg .tg-header {
+ font-weight: bold;
+ text-align: center
+}
+
+.tg .tg-center {
+ text-align: center
+}
\ No newline at end of file
diff --git a/sources/help/img/component-history.png b/sources/help/img/component-history.png
new file mode 100644
index 00000000..dd128137
Binary files /dev/null and b/sources/help/img/component-history.png differ
diff --git a/sources/help/img/databaseStructure.jpg b/sources/help/img/databaseStructure.jpg
new file mode 100644
index 00000000..b6f0911d
Binary files /dev/null and b/sources/help/img/databaseStructure.jpg differ
diff --git a/sources/help/img/debugging-information.png b/sources/help/img/debugging-information.png
new file mode 100644
index 00000000..f94be7f0
Binary files /dev/null and b/sources/help/img/debugging-information.png differ
diff --git a/sources/help/img/export-gui.png b/sources/help/img/export-gui.png
new file mode 100644
index 00000000..60c20abf
Binary files /dev/null and b/sources/help/img/export-gui.png differ
diff --git a/sources/help/img/help.png b/sources/help/img/help.png
new file mode 100644
index 00000000..f571e07a
Binary files /dev/null and b/sources/help/img/help.png differ
diff --git a/sources/help/img/import-gui.png b/sources/help/img/import-gui.png
new file mode 100644
index 00000000..01cfd4bd
Binary files /dev/null and b/sources/help/img/import-gui.png differ
diff --git a/sources/help/img/import_individual_element.png b/sources/help/img/import_individual_element.png
new file mode 100644
index 00000000..a33c77c5
Binary files /dev/null and b/sources/help/img/import_individual_element.png differ
diff --git a/sources/help/img/import_individual_model.png b/sources/help/img/import_individual_model.png
new file mode 100644
index 00000000..de9c16d7
Binary files /dev/null and b/sources/help/img/import_individual_model.png differ
diff --git a/sources/help/img/import_individual_view.png b/sources/help/img/import_individual_view.png
new file mode 100644
index 00000000..d96e7508
Binary files /dev/null and b/sources/help/img/import_individual_view.png differ
diff --git a/sources/help/img/not_selected.png b/sources/help/img/not_selected.png
new file mode 100644
index 00000000..797ff051
Binary files /dev/null and b/sources/help/img/not_selected.png differ
diff --git a/sources/help/img/please_wait_counting_model_s_components.png b/sources/help/img/please_wait_counting_model_s_components.png
new file mode 100644
index 00000000..6fa7e8cd
Binary files /dev/null and b/sources/help/img/please_wait_counting_model_s_components.png differ
diff --git a/sources/help/img/please_wait_while_comparing_model_from_the_database.png b/sources/help/img/please_wait_while_comparing_model_from_the_database.png
new file mode 100644
index 00000000..b046a7bd
Binary files /dev/null and b/sources/help/img/please_wait_while_comparing_model_from_the_database.png differ
diff --git a/sources/help/img/preferences-behaviour.png b/sources/help/img/preferences-behaviour.png
new file mode 100644
index 00000000..b3a26c75
Binary files /dev/null and b/sources/help/img/preferences-behaviour.png differ
diff --git a/sources/help/img/preferences-logger_expert.png b/sources/help/img/preferences-logger_expert.png
new file mode 100644
index 00000000..df53f8fc
Binary files /dev/null and b/sources/help/img/preferences-logger_expert.png differ
diff --git a/sources/help/img/preferences-logger_simple.png b/sources/help/img/preferences-logger_simple.png
new file mode 100644
index 00000000..604118ff
Binary files /dev/null and b/sources/help/img/preferences-logger_simple.png differ
diff --git a/sources/help/img/preferences-neo4j.png b/sources/help/img/preferences-neo4j.png
new file mode 100644
index 00000000..1f715522
Binary files /dev/null and b/sources/help/img/preferences-neo4j.png differ
diff --git a/sources/help/img/preferences-relational.png b/sources/help/img/preferences-relational.png
new file mode 100644
index 00000000..52df112d
Binary files /dev/null and b/sources/help/img/preferences-relational.png differ
diff --git a/sources/help/img/preferences-sqlite.png b/sources/help/img/preferences-sqlite.png
new file mode 100644
index 00000000..afca8355
Binary files /dev/null and b/sources/help/img/preferences-sqlite.png differ
diff --git a/sources/help/img/selected.png b/sources/help/img/selected.png
new file mode 100644
index 00000000..c36d97cb
Binary files /dev/null and b/sources/help/img/selected.png differ
diff --git a/sources/help_contexts.xml b/sources/help_contexts.xml
new file mode 100644
index 00000000..bbe3cc2e
--- /dev/null
+++ b/sources/help_contexts.xml
@@ -0,0 +1,8 @@
+
+
+
+
+ You may select the Configure the plugin link below to get help about how to configure the database plugin.
+
+
+
diff --git a/sources/img/10x10/bypassed.png b/sources/img/10x10/bypassed.png
new file mode 100644
index 00000000..c4eb6a14
Binary files /dev/null and b/sources/img/10x10/bypassed.png differ
diff --git a/sources/img/10x10/clock.png b/sources/img/10x10/clock.png
new file mode 100644
index 00000000..244e8c3d
Binary files /dev/null and b/sources/img/10x10/clock.png differ
diff --git a/sources/img/10x10/error.png b/sources/img/10x10/error.png
new file mode 100644
index 00000000..5a5eaf68
Binary files /dev/null and b/sources/img/10x10/error.png differ
diff --git a/sources/img/10x10/lock.png b/sources/img/10x10/lock.png
new file mode 100644
index 00000000..7ed90f42
Binary files /dev/null and b/sources/img/10x10/lock.png differ
diff --git a/sources/img/10x10/ok.png b/sources/img/10x10/ok.png
new file mode 100644
index 00000000..a47c4e20
Binary files /dev/null and b/sources/img/10x10/ok.png differ
diff --git a/sources/img/10x10/right_arrow.png b/sources/img/10x10/right_arrow.png
new file mode 100644
index 00000000..b369fd5d
Binary files /dev/null and b/sources/img/10x10/right_arrow.png differ
diff --git a/sources/img/10x10/unlock.png b/sources/img/10x10/unlock.png
new file mode 100644
index 00000000..bd90e396
Binary files /dev/null and b/sources/img/10x10/unlock.png differ
diff --git a/sources/img/10x10/warning.png b/sources/img/10x10/warning.png
new file mode 100644
index 00000000..a970e3f9
Binary files /dev/null and b/sources/img/10x10/warning.png differ
diff --git a/sources/img/16x16/debug.png b/sources/img/16x16/debug.png
new file mode 100644
index 00000000..75e7ef59
Binary files /dev/null and b/sources/img/16x16/debug.png differ
diff --git a/sources/img/16x16/export.png b/sources/img/16x16/export.png
new file mode 100644
index 00000000..e184ae7b
Binary files /dev/null and b/sources/img/16x16/export.png differ
diff --git a/sources/img/16x16/history.png b/sources/img/16x16/history.png
new file mode 100644
index 00000000..bb9301ca
Binary files /dev/null and b/sources/img/16x16/history.png differ
diff --git a/sources/img/16x16/import.png b/sources/img/16x16/import.png
new file mode 100644
index 00000000..e866c54a
Binary files /dev/null and b/sources/img/16x16/import.png differ
diff --git a/sources/img/16x16/replace.png b/sources/img/16x16/replace.png
new file mode 100644
index 00000000..4d824a68
Binary files /dev/null and b/sources/img/16x16/replace.png differ
diff --git a/sources/img/22x22/export.png b/sources/img/22x22/export.png
new file mode 100644
index 00000000..12462ce0
Binary files /dev/null and b/sources/img/22x22/export.png differ
diff --git a/sources/img/22x22/import.png b/sources/img/22x22/import.png
new file mode 100644
index 00000000..c2ef0706
Binary files /dev/null and b/sources/img/22x22/import.png differ
diff --git a/sources/img/28x28/help.png b/sources/img/28x28/help.png
new file mode 100644
index 00000000..f571e07a
Binary files /dev/null and b/sources/img/28x28/help.png differ
diff --git a/sources/img/grey.png b/sources/img/grey.png
new file mode 100644
index 00000000..9808a50f
Binary files /dev/null and b/sources/img/grey.png differ
diff --git a/sources/img/logo.png b/sources/img/logo.png
new file mode 100644
index 00000000..63bc3b25
Binary files /dev/null and b/sources/img/logo.png differ
diff --git a/sources/lib/json-simple-1.1.1.jar b/sources/lib/json-simple-1.1.1.jar
new file mode 100644
index 00000000..dfd5856d
Binary files /dev/null and b/sources/lib/json-simple-1.1.1.jar differ
diff --git a/sources/lib/log4j-1.2.17.jar b/sources/lib/log4j-1.2.17.jar
new file mode 100644
index 00000000..068867eb
Binary files /dev/null and b/sources/lib/log4j-1.2.17.jar differ
diff --git a/sources/lib/lombok.jar b/sources/lib/lombok.jar
new file mode 100644
index 00000000..d3434f69
Binary files /dev/null and b/sources/lib/lombok.jar differ
diff --git a/sources/lib/mssql-jdbc-8.2.2.jre11.jar b/sources/lib/mssql-jdbc-8.2.2.jre11.jar
new file mode 100644
index 00000000..4d565b2c
Binary files /dev/null and b/sources/lib/mssql-jdbc-8.2.2.jre11.jar differ
diff --git a/sources/lib/mysql-connector-java-5.1.48.jar b/sources/lib/mysql-connector-java-5.1.48.jar
new file mode 100644
index 00000000..fcd53a51
Binary files /dev/null and b/sources/lib/mysql-connector-java-5.1.48.jar differ
diff --git a/sources/lib/neo4j-jdbc-driver-4.0.0.jar b/sources/lib/neo4j-jdbc-driver-4.0.0.jar
new file mode 100644
index 00000000..96192289
Binary files /dev/null and b/sources/lib/neo4j-jdbc-driver-4.0.0.jar differ
diff --git a/sources/lib/ojdbc10.jar b/sources/lib/ojdbc10.jar
new file mode 100644
index 00000000..7c37edca
Binary files /dev/null and b/sources/lib/ojdbc10.jar differ
diff --git a/sources/lib/orai18n.jar b/sources/lib/orai18n.jar
new file mode 100644
index 00000000..58d2a9c7
Binary files /dev/null and b/sources/lib/orai18n.jar differ
diff --git a/sources/lib/postgresql-42.2.12.jar b/sources/lib/postgresql-42.2.12.jar
new file mode 100644
index 00000000..1f393bb7
Binary files /dev/null and b/sources/lib/postgresql-42.2.12.jar differ
diff --git a/sources/lib/sqlite-jdbc-3.30.1.jar b/sources/lib/sqlite-jdbc-3.30.1.jar
new file mode 100644
index 00000000..85837370
Binary files /dev/null and b/sources/lib/sqlite-jdbc-3.30.1.jar differ
diff --git a/sources/plugin.xml b/sources/plugin.xml
new file mode 100644
index 00000000..9cb5fb58
--- /dev/null
+++ b/sources/plugin.xml
@@ -0,0 +1,168 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sources/src/org/archicontribs/database/DBCheckForPluginUpdate.java b/sources/src/org/archicontribs/database/DBCheckForPluginUpdate.java
new file mode 100644
index 00000000..57d38ab6
--- /dev/null
+++ b/sources/src/org/archicontribs/database/DBCheckForPluginUpdate.java
@@ -0,0 +1,380 @@
+/**
+ * This program and the accompanying materials
+ * are made available under the terms of the License
+ * which accompanies this distribution in the file LICENSE.txt
+ */
+package org.archicontribs.database;
+
+import java.awt.Toolkit;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.Authenticator;
+import java.net.PasswordAuthentication;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.net.ssl.HttpsURLConnection;
+
+import org.apache.log4j.Level;
+import org.archicontribs.database.GUI.DBGui;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.layout.FormLayout;
+import org.eclipse.swt.program.Program;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.ProgressBar;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.osgi.framework.Version;
+
+/**
+ * Checks if a new version of the plugin exists on GitHub and download it if required
+ *
+ * @author Herve Jouin
+ */
+public class DBCheckForPluginUpdate {
+ static final DBLogger logger = new DBLogger(DBCheckForPluginUpdate.class);
+
+ private FileSystem fileSystem = FileSystems.getDefault();
+
+ private Display display = Display.getDefault();
+
+ DropinsPluginHandler dropinsPluginHandler = new DropinsPluginHandler();
+
+ ProgressBar updateProgressbar = null;
+ int updateDownloaded = 0;
+ int answer;
+
+ /**
+ * Establishes an https connection to GitHub, get a list of available jar files and get the versions from the jar filename.
+ * If the greater version of the jar files is greater than the current plugin version, then a popup asks the user if it wishes to doanload it.
+ * If yes, then the jar file is downloaded to a temporary file and a task is created to replace the existing jar file with the new one when Archi is stopped.
+ * @param showPopup is true show popup with error message, else only log the error messages in log file
+ * @param pluginApiUrl
+ * @param releaseNoteUrl
+ */
+ public DBCheckForPluginUpdate(boolean showPopup, String pluginApiUrl, String releaseNoteUrl) {
+ // first, we check we can write to the dropins folder
+
+ // unfortunately, the getUserDropinsFolder method is private, we need to force
+ File dropinsFolder;
+ String dropinsFolderName;
+ try {
+ dropinsFolder = this.dropinsPluginHandler.getDefaultDropinsFolder();
+ dropinsFolderName = dropinsFolder.getCanonicalPath();
+ } catch (IOException err) {
+ if ( showPopup )
+ DBGui.popup(Level.ERROR, "Failed to get dropins folder.", err);
+ else
+ logger.error("Failed to get dropins folder.", err);
+ return;
+ }
+
+ if ( !dropinsFolder.canWrite() ) {
+ if ( showPopup )
+ DBGui.popup(Level.ERROR, "Can't write to \""+dropinsFolderName+"\" folder.");
+ else
+ DBGui.popup(Level.ERROR, "Can't write to \""+dropinsFolderName+"\" folder.");
+ return;
+ }
+
+ Map versions = new TreeMap(Collections.reverseOrder());
+ JSONParser parser = new JSONParser();
+
+ if ( showPopup )
+ DBGui.popup("Checking for a new database plugin version on GitHub ...");
+ else
+ logger.debug("Checking for a new database plugin version on GitHub");
+
+ try {
+ Authenticator.setDefault(new Authenticator() {
+ @Override
+ protected PasswordAuthentication getPasswordAuthentication() {
+ if ( logger.isTraceEnabled() ) logger.trace(" Requestor type = "+getRequestorType());
+ if (getRequestorType() == RequestorType.PROXY) {
+ String prot = getRequestingProtocol().toLowerCase();
+ String host = System.getProperty(prot + ".proxyHost", "");
+ String port = System.getProperty(prot + ".proxyPort", "80");
+ String user = System.getProperty(prot + ".proxyUser", "");
+ String pass = System.getProperty(prot + ".proxyPassword", "");
+
+ if ( logger.isDebugEnabled() )
+ logger.debug("Proxy request from "+getRequestingHost()+":"+getRequestingPort());
+ if ( logger.isTraceEnabled() ) {
+ logger.trace(" Proxy configuration:");
+ logger.trace(" prot: "+prot);
+ logger.trace(" host: "+host);
+ logger.trace(" port: "+port);
+ logger.trace(" user: "+user);
+ logger.trace(" pass: (xxxxx)");
+ }
+
+ // we check if the request comes from the proxy (IP or hostname), else we do not send the password (for security reason)
+ if ( (getRequestingSite().getHostAddress().equalsIgnoreCase(host) || getRequestingHost().equalsIgnoreCase(host)) && (getRequestingPort() == Integer.parseInt(port)) ) {
+ // Seems to be OK.
+ if ( logger.isDebugEnabled() ) logger.debug("Setting PasswordAuthenticator");
+ return new PasswordAuthentication(user, pass.toCharArray());
+ }
+ }
+ return null;
+ }
+ });
+
+
+ HttpsURLConnection conn = null;
+ JSONArray result = null;
+ InputStreamReader streamReader = null;
+
+ try {
+ if ( logger.isDebugEnabled() ) logger.debug("Connecting to "+pluginApiUrl);
+ conn = (HttpsURLConnection)new URL(pluginApiUrl).openConnection();
+
+ if ( logger.isDebugEnabled() ) logger.debug("Getting file list");
+ streamReader = new InputStreamReader(conn.getInputStream());
+ result = (JSONArray)parser.parse(streamReader);
+ } finally {
+ if ( conn != null )
+ conn.disconnect();
+ if ( streamReader != null )
+ streamReader.close();
+ }
+
+ if ( result == null ) {
+ if ( showPopup ) {
+ DBGui.closePopup();
+ DBGui.popup(Level.ERROR, "Failed to check for new database plugin version.\n\nParsing error.");
+ } else
+ logger.error("Failed to check for new database plugin version.\n\nParsing error.");
+ return;
+ }
+
+ if ( logger.isDebugEnabled() ) logger.debug("Searching for \"archiplugin\" files");
+ Pattern p = Pattern.compile(DBPlugin.pluginsPackage+"_(.*).archiplugin") ;
+
+ Iterator iterator = result.iterator();
+ while (iterator.hasNext()) {
+ JSONObject file = iterator.next();
+ Matcher m = p.matcher((String)file.get("name")) ;
+ if ( m.matches() ) {
+ if ( logger.isDebugEnabled() ) logger.debug("Found version "+m.group(1)+" ("+(String)file.get("download_url")+")");
+ versions.put(m.group(1), (String)file.get("download_url"));
+ }
+ }
+
+ if ( showPopup ) DBGui.closePopup();
+
+ if ( versions.isEmpty() ) {
+ if ( showPopup )
+ DBGui.popup(Level.ERROR, "Failed to check for new database plugin version.\n\nDid not find any "+DBPlugin.pluginsPackage+"_*.archiplugin file.");
+ else
+ logger.error("Failed to check for new database plugin version.\n\nDid not find any "+DBPlugin.pluginsPackage+"_*.archiplugin file.");
+ return;
+ }
+ } catch (Exception e) {
+ if ( showPopup ) {
+ DBGui.closePopup();
+ DBGui.popup(Level.ERROR, "Failed to check for new version on GitHub.", e);
+ } else {
+ logger.error("Failed to check for new version on GitHub.", e);
+ }
+ return;
+ }
+
+ String newPluginFilename = null;
+ try {
+ // treemap is sorted in descending order, so first entry should have the "bigger" key value, i.e. the latest version
+ Entry entry = versions.entrySet().iterator().next();
+
+ if ( DBPlugin.pluginVersion.compareTo(new Version(entry.getKey())) >= 0 ) {
+ if ( showPopup )
+ DBGui.popup(Level.INFO, "You already have got the latest version: "+DBPlugin.pluginVersion.toString());
+ else
+ logger.info("You already have got the latest version: "+DBPlugin.pluginVersion.toString());
+ return;
+ }
+
+ if ( !DBPlugin.pluginsFilename.endsWith(".jar") ) {
+ if ( showPopup )
+ DBGui.popup(Level.ERROR,"A new version of the database plugin is available:\n actual version: "+DBPlugin.pluginVersion.toString()+"\n new version: "+entry.getKey()+"\n\nUnfortunately, it cannot be downloaded while Archi is running inside Eclipse.");
+ else
+ logger.error("A new version of the database plugin is available:\n actual version: "+DBPlugin.pluginVersion.toString()+"\n new version: "+entry.getKey()+"\n\nUnfortunately, it cannot be downloaded while Archi is running inside Eclipse.");
+ return;
+ }
+
+ boolean ask = true;
+ while ( ask ) {
+ this.display.syncExec(new Runnable() { @Override public void run() { DBCheckForPluginUpdate.this.answer = DBGui.question("A new version of the database plugin is available:\n actual version: "+DBPlugin.pluginVersion.toString()+"\n new version: "+entry.getKey()+"\n\nDo you wish to download and install it ?", new String[] {"Yes", "No", "Check release note"}); }});
+ switch ( this.answer ) {
+ case 0: ask = false ; break; // Yes
+ case 1: return ; // No
+ case 2: ask = true ; // release note
+ Program.launch(releaseNoteUrl);
+ break;
+ default: break; // should never be here, but just in case
+ }
+ }
+
+ this.display.syncExec(new Runnable() { @Override public void run() { DBCheckForPluginUpdate.this.updateProgressbar = progressbarPopup("Downloading new version of the database plugin ..."); }});
+
+ URLConnection conn = new URL(entry.getValue()).openConnection();
+ String FileType = conn.getContentType();
+ int fileLength = conn.getContentLength();
+
+ newPluginFilename = dropinsFolderName+File.separator+entry.getValue().substring(entry.getValue().lastIndexOf('/')+1, entry.getValue().length());
+
+ if ( logger.isTraceEnabled() ) {
+ logger.trace(" File URL: " + entry.getValue());
+ logger.trace(" File type: " + FileType);
+ logger.trace(" File length: "+fileLength);
+ logger.trace(" download file: " + newPluginFilename);
+ }
+
+ // we delete the file in case a previous download failed
+ Files.deleteIfExists(this.fileSystem.getPath(newPluginFilename));
+
+ if (fileLength == -1)
+ throw new IOException("Failed to get file size.");
+
+ this.display.syncExec(new Runnable() { @Override public void run() { DBCheckForPluginUpdate.this.updateProgressbar.setMaximum(fileLength); }});
+
+ try ( InputStream in = conn.getInputStream() ) {
+ try ( FileOutputStream fos = new FileOutputStream(new File(newPluginFilename)) ) {
+ byte[] buff = new byte[1024];
+ int n;
+ this.updateDownloaded = 0;
+
+ if ( logger.isDebugEnabled() ) logger.debug("Downloading file ...");
+ while ((n=in.read(buff)) !=-1) {
+ fos.write(buff, 0, n);
+ this.updateDownloaded +=n;
+ this.display.syncExec(new Runnable() { @Override public void run() { DBCheckForPluginUpdate.this.updateProgressbar.setSelection(DBCheckForPluginUpdate.this.updateDownloaded); }});
+ //if ( logger.isTraceEnabled() ) logger.trace(updateDownloaded+"/"+fileLength);
+ }
+ fos.flush();
+ }
+ }
+
+ if ( logger.isDebugEnabled() ) logger.debug("Download finished");
+
+ } catch (Exception e) {
+ if( this.updateProgressbar != null ) this.display.syncExec(new Runnable() { @Override public void run() { DBCheckForPluginUpdate.this.updateProgressbar.getShell().dispose(); DBCheckForPluginUpdate.this.updateProgressbar = null; }});
+ // we delete the file in case the download failed
+ try {
+ Files.deleteIfExists(this.fileSystem.getPath(newPluginFilename));
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "Failed to delete partially downloaded file \""+newPluginFilename+"\".", err);
+ }
+ if ( showPopup )
+ DBGui.popup(Level.ERROR, "Failed to download the new version of the database plugin.", e);
+ else
+ logger.error("Failed to download the new version of the database plugin.",e);
+ return;
+ }
+
+ if( this.updateProgressbar != null ) this.display.syncExec(new Runnable() { @Override public void run() { DBCheckForPluginUpdate.this.updateProgressbar.getShell().dispose(); DBCheckForPluginUpdate.this.updateProgressbar = null;}});
+
+ // we ask Archi to install it
+ try {
+ IStatus status = this.dropinsPluginHandler.installFile(new File(newPluginFilename));
+ if ( !status.isOK() ) {
+ if ( showPopup )
+ DBGui.popup(Level.ERROR, "Failed to install new plugin version.");
+ else
+ logger.error("Failed to install new plugin version.");
+ return;
+ }
+ } catch (IOException e) {
+ if ( showPopup )
+ DBGui.popup(Level.ERROR, "Failed to install new plugin version.", e);
+ else
+ logger.error("Failed to install new plugin version.",e);
+ return;
+ }
+
+
+ if( DBGui.question("A new version on the database plugin has been downloaded. Archi needs to be restarted to install it.\n\nDo you wish to restart Archi now ?") ) {
+ this.display.syncExec(new Runnable() {
+ @Override public void run() {
+ PlatformUI.getWorkbench().restart();
+ }
+ });
+ }
+ }
+
+ /**
+ * Shows up an on screen popup with a progressbar
+ * it is the responsibility of the caller to dismiss the popup
+ * @param msg Message to show in the progressbar
+ * @return
+ */
+ ProgressBar progressbarPopup(String msg) {
+ if (logger.isDebugEnabled())
+ logger.debug("New progressbarPopup(\"" + msg + "\")");
+
+ final FontData SYSTEM_FONT = this.display.getSystemFont().getFontData()[0];
+ final Color LIGHT_BLUE = new Color(this.display, 240, 248, 255);
+ final Font TITLE_FONT = new Font(this.display, SYSTEM_FONT.getName(), SYSTEM_FONT.getHeight() + 2, SWT.BOLD);
+
+ Shell shell = new Shell(this.display, SWT.SHELL_TRIM);
+ shell.setSize(600, 100);
+ shell.setLocation((Toolkit.getDefaultToolkit().getScreenSize().width - shell.getSize().x) / 4, (Toolkit.getDefaultToolkit().getScreenSize().height - shell.getSize().y) / 4);
+ shell.setLayout(new FormLayout());
+
+ Composite composite = new Composite(shell, SWT.NONE);
+ composite.setBackground(LIGHT_BLUE);
+ FormData fd = new FormData();
+ fd.left= new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ fd.top = new FormAttachment(0);
+ fd.bottom = new FormAttachment(100);
+ composite.setLayoutData(fd);
+ composite.setLayout(new FormLayout());
+
+ Label label = new Label(composite, SWT.CENTER);
+ fd = new FormData();
+ fd.left= new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ fd.top = new FormAttachment(0, 10);
+ label.setLayoutData(fd);
+ label.setBackground(LIGHT_BLUE);
+ label.setFont(TITLE_FONT);
+ label.setText(msg);
+
+ ProgressBar progressBar = new ProgressBar(composite, SWT.SMOOTH);
+ fd = new FormData();
+ fd.left= new FormAttachment(0, 20);
+ fd.right = new FormAttachment(100, -20);
+ fd.bottom = new FormAttachment(100, -20);
+ progressBar.setLayoutData(fd);
+ progressBar.setMinimum(0);
+ progressBar.setMaximum(100);
+
+ shell.layout();
+ shell.open();
+
+ return progressBar;
+ }
+}
diff --git a/sources/src/org/archicontribs/database/DBColumn.java b/sources/src/org/archicontribs/database/DBColumn.java
new file mode 100644
index 00000000..1e2658cc
--- /dev/null
+++ b/sources/src/org/archicontribs/database/DBColumn.java
@@ -0,0 +1,237 @@
+package org.archicontribs.database;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ *
+ * @author Herve
+ *
+ */
+public class DBColumn {
+ @Getter @Setter String name = "";
+ @Getter @Setter String type = "";
+ @Getter @Setter int length = 0;
+ @Getter @Setter boolean notNull = true;
+ @Getter @Setter Object metadata = null;
+ @Getter int maxLength = 2000000000; // do not know why, but it seems to be hard coded in JDBC
+
+ /**
+ *
+ * @param name
+ * @param type
+ * @param length
+ * @param isNotNull
+ */
+ @SuppressWarnings("hiding")
+ public DBColumn(String name, String type, int length, boolean isNotNull) {
+ set(name, type, length, isNotNull);
+ }
+
+ /**
+ *
+ * @param name
+ * @param dbEntry
+ * @param columnType
+ * @param isNotNull
+ * @throws SQLException
+ */
+ @SuppressWarnings("hiding")
+ public DBColumn (String name, DBDatabaseEntry dbEntry, DBColumnType columnType, boolean isNotNull) throws SQLException {
+ switch (dbEntry.getDriver()) {
+ case "postgresql":
+ switch ( columnType ) {
+ case AUTO_INCREMENT : set(name, "SERIAL", 0, isNotNull); break;
+ case BOOLEAN : set(name, "INT2", 0, isNotNull); break;
+ case COLOR : set(name, "VARCHAR", 7, isNotNull); break;
+ case DATETIME : set(name, "TIMESTAMP", 0, isNotNull); break;
+ case FONT : set(name, "VARCHAR", 150, isNotNull); break;
+ case IMAGE : set(name, "BYTEA", 0, isNotNull); break;
+ case INTEGER : set(name, "INT4", 0, isNotNull); break;
+ case OBJECTID : set(name, "VARCHAR", 50, isNotNull); break;
+ case OBJ_NAME : set(name, "VARCHAR", 1024, isNotNull); break;
+ case STRENGTH : set(name, "VARCHAR", 20, isNotNull); break;
+ case TEXT : set(name, "TEXT", 0, isNotNull); break;
+ case TYPE : set(name, "VARCHAR", 3, isNotNull); break;
+ case USERNAME : set(name, "VARCHAR", 30, isNotNull); break;
+ default: break;
+ }
+ break;
+ case "ms-sql":
+ switch ( columnType ) {
+ case AUTO_INCREMENT : set(name, "INT IDENTITY",0, isNotNull); break;
+ case BOOLEAN : set(name, "TINYINT", 0, isNotNull); break;
+ case COLOR : set(name, "VARCHAR", 7, isNotNull); break;
+ case DATETIME : set(name, "DATETIME", 0, isNotNull); break;
+ case FONT : set(name, "VARCHAR", 150, isNotNull); break;
+ case IMAGE : set(name, "IMAGE", 0, isNotNull); break;
+ case INTEGER : set(name, "INT", 0, isNotNull); break;
+ case OBJECTID : set(name, "VARCHAR", 50, isNotNull); break;
+ case OBJ_NAME : set(name, "VARCHAR", 1024, isNotNull); break;
+ case STRENGTH : set(name, "VARCHAR", 20, isNotNull); break;
+ case TEXT : set(name, "NVARCHAR", -1, isNotNull); break;
+ case TYPE : set(name, "VARCHAR", 3, isNotNull); break;
+ case USERNAME : set(name, "VARCHAR", 30, isNotNull); break;
+ default: break;
+ }
+ break;
+ case "mysql":
+ switch ( columnType ) {
+ case AUTO_INCREMENT : set(name, "INT AUTO_INCREMENT", 0, isNotNull); break;
+ case BOOLEAN : set(name, "TINYINT", 0, isNotNull); break;
+ case COLOR : set(name, "VARCHAR", 7, isNotNull); break;
+ case DATETIME : set(name, "DATETIME", 0, isNotNull); break;
+ case FONT : set(name, "VARCHAR", 150, isNotNull); break;
+ case IMAGE : set(name, "LONGBLOB", 0, isNotNull); break;
+ case INTEGER : set(name, "INT", 10, isNotNull); break;
+ case OBJECTID : set(name, "VARCHAR", 50, isNotNull); break;
+ case OBJ_NAME : set(name, "VARCHAR", 1024, isNotNull); break;
+ case STRENGTH : set(name, "VARCHAR", 20, isNotNull); break;
+ case TEXT : set(name, "MEDIUMTEXT", 0, isNotNull); break;
+ case TYPE : set(name, "VARCHAR", 3, isNotNull); break;
+ case USERNAME : set(name, "VARCHAR", 30, isNotNull); break;
+ default: break;
+ }
+ break;
+ case "neo4j":
+ return;
+ case "oracle":
+ switch ( columnType ) {
+ case AUTO_INCREMENT : set(name, "INTEGER", 0, isNotNull); break;
+ case BOOLEAN : set(name, "CHAR", 1, isNotNull); break;
+ case COLOR : set(name, "VARCHAR", 7, isNotNull); break;
+ case DATETIME : set(name, "DATE", 0, isNotNull); break;
+ case FONT : set(name, "VARCHAR", 150, isNotNull); break;
+ case IMAGE : set(name, "BLOB", 0, isNotNull); break;
+ case INTEGER : set(name, "INTEGER", 0, isNotNull); break;
+ case OBJECTID : set(name, "VARCHAR", 50, isNotNull); break;
+ case OBJ_NAME : set(name, "VARCHAR", 1024, isNotNull); break;
+ case STRENGTH : set(name, "VARCHAR", 20, isNotNull); break;
+ case TEXT : set(name, "CLOB", 0, isNotNull); break;
+ case TYPE : set(name, "VARCHAR", 3, isNotNull); break;
+ case USERNAME : set(name, "VARCHAR", 30, isNotNull); break;
+ default: break;
+ }
+ break;
+ case "sqlite":
+ switch ( columnType ) {
+ case AUTO_INCREMENT : set(name, "INTEGER", 0, isNotNull); break;
+ case BOOLEAN : set(name, "TINYINT", 0, isNotNull); break;
+ case COLOR : set(name, "VARCHAR", 7, isNotNull); break;
+ case DATETIME : set(name, "TIMESTAMP", 0, isNotNull); break;
+ case FONT : set(name, "VARCHAR", 150, isNotNull); break;
+ case IMAGE : set(name, "BLOB", 0, isNotNull); break;
+ case INTEGER : set(name, "INTEGER", 10, isNotNull); break;
+ case OBJECTID : set(name, "VARCHAR", 50, isNotNull); break;
+ case OBJ_NAME : set(name, "VARCHAR", 1024, isNotNull); break;
+ case STRENGTH : set(name, "VARCHAR", 20, isNotNull); break;
+ case TEXT : set(name, "CLOB", 0, isNotNull); break;
+ case TYPE : set(name, "VARCHAR", 3, isNotNull); break;
+ case USERNAME : set(name, "VARCHAR", 30, isNotNull); break;
+ default: break;
+ }
+ break;
+ default: throw new SQLException("Unknonwn driver " + dbEntry.getDriver()); // just in case;
+ }
+ }
+
+ @SuppressWarnings("hiding")
+ private void set(String name, String type, int length, boolean isNotNull) {
+ this.name = name;
+ // if type has got parenthesis, the number enclosed takes precedence over the dbLenght parameter
+ int parenthesis = type.indexOf('(');
+ if ( parenthesis == -1 ) {
+ this.type = type;
+ this.length = length;
+ } else {
+ this.type = type.substring(0,parenthesis);
+ this.length = Integer.parseInt(type.substring(parenthesis+1, type.length()-1));
+ }
+ this.notNull = isNotNull;
+ }
+
+ /**
+ *
+ * @param columns
+ * @return
+ */
+ static public String[] getColumnNames(List columns) {
+ String[] columnNames = new String[columns.size()];
+ for ( int i = 0 ; i < columns.size() ; ++i ) {
+ columnNames[i] = columns.get(i).getName();
+ }
+ return columnNames;
+ }
+
+ /**
+ *
+ * @return
+ */
+ @Override public String toString() {
+ StringBuilder result = new StringBuilder(this.name);
+ result.append(": ");
+ result.append (getFullType());
+
+ return result.toString();
+ }
+
+ /**
+ * @return
+ */
+ public String getFullType() {
+ StringBuilder fullType = new StringBuilder();
+
+ fullType.append (this.type);
+
+ if ( this.length != 0 && this.length != this.maxLength) {
+ fullType.append("(");
+ if ( this.length > 0 )
+ fullType.append(this.length);
+ else
+ fullType.append("MAX");
+ fullType.append(")");
+ }
+
+ if ( this.notNull ) {
+ fullType.append(" NOT NULL");
+ }
+
+ return fullType.toString();
+ }
+
+ /**
+ *
+ * @param compareTo
+ * @return
+ */
+ public boolean equals(DBColumn compareTo) {
+ if ( this.name.compareToIgnoreCase(compareTo.name) != 0 )
+ return false;
+
+ // we compare only the fist word in the type, to avoid checking for AUTO_INCREMENT
+ String thisType = this.type.split(" ")[0].toUpperCase();
+ String compareToType = compareTo.type.split(" ")[0].toUpperCase();
+
+ // we consider VARCHAR & VARCHAR2, and NUMBER & INTEGER being the same
+ if ( !(thisType.startsWith("VARCHAR") && compareToType.startsWith("VARCHAR"))
+ && !((thisType.equals("NUMBER") || compareToType.equals("NUMBER")) && (thisType.equals("INTEGER") || compareToType.equals("INTEGER")))
+ && thisType.compareToIgnoreCase(compareToType) != 0
+ )
+ return false;
+
+ // we consider NUMBER(38) and INTEGER(10) being the same
+ if ( (this.length > 0 && compareTo.length > 0 && this.length != compareTo.length)
+ && !((thisType.equals("NUMBER") || thisType.equals("INTEGER")) && Math.abs(this.length-compareTo.length)==28)
+ )
+ return false;
+
+ if ( this.notNull != compareTo.notNull )
+ return false;
+
+ return true;
+ }
+}
+
diff --git a/sources/src/org/archicontribs/database/DBColumnType.java b/sources/src/org/archicontribs/database/DBColumnType.java
new file mode 100644
index 00000000..c0896e32
--- /dev/null
+++ b/sources/src/org/archicontribs/database/DBColumnType.java
@@ -0,0 +1,18 @@
+package org.archicontribs.database;
+
+public enum DBColumnType {
+ AUTO_INCREMENT,
+ BOOLEAN,
+ COLOR,
+ DATETIME,
+ FONT,
+ IMAGE,
+ INTEGER,
+ OBJECTID,
+ OBJ_NAME,
+ //PRIMARY_KEY,
+ STRENGTH,
+ TEXT,
+ TYPE,
+ USERNAME;
+}
diff --git a/sources/src/org/archicontribs/database/DBDatabaseEntry.java b/sources/src/org/archicontribs/database/DBDatabaseEntry.java
new file mode 100644
index 00000000..b4846737
--- /dev/null
+++ b/sources/src/org/archicontribs/database/DBDatabaseEntry.java
@@ -0,0 +1,609 @@
+package org.archicontribs.database;
+
+import java.io.IOException;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.Enumeration;
+import java.util.List;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.log4j.Level;
+import org.archicontribs.database.GUI.DBGui;
+import org.archicontribs.database.data.DBDatabase;
+import org.eclipse.jface.preference.IPersistentPreferenceStore;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * This class contains all the information required to connect to to a database
+ *
+ * @author Herve Jouin
+ */
+public class DBDatabaseEntry {
+ private static final DBLogger logger = new DBLogger(DBDatabaseEntry.class);
+
+ /**
+ * prefix used in the preference store
+ */
+ final static String preferenceName = "databases";
+
+ /**
+ * Creates a new DBDatabaseEntry.
+ */
+ public DBDatabaseEntry() {
+ }
+
+ /**
+ * DBDatabaseEntries are sorted, so we keep its index
+ */
+ @Getter @Setter private int index = -1; // -1 means not initialized; i.e. not persisted in the preference store
+
+ /**
+ * ID of the database Entry
+ */
+ @Getter @Setter private String id = "";
+
+ /**
+ * Name of the database Entry
+ */
+ @Getter @Setter private String name = "";
+
+ /**
+ * Driver to use to access the database
+ *
+ * must be one of @DBDatabase.VALUES
+ */
+ @Getter private String driver = "";
+
+ /**
+ * @return the class of the JDBC driver
+ * @throws SQLException
+ */
+ public String getDriverClass() throws SQLException {
+ switch (this.getDriver()) {
+ case "postgresql": return "org.postgresql.Driver";
+ case "ms-sql": return "com.microsoft.sqlserver.jdbc.SQLServerDriver";
+ case "mysql": return "com.mysql.jdbc.Driver";
+ case "neo4j": return "org.neo4j.jdbc.Driver";
+ case "oracle": return "oracle.jdbc.driver.OracleDriver";
+ case "sqlite": return "org.sqlite.JDBC";
+ default: throw new SQLException("Unknonwn driver " + this.getDriver()); // just in case;
+ }
+ }
+
+ /**
+ * Driver to use to access the database
+ *
+ * @param driverName must be one of {@link DBDatabase.VALUES}
+ * @throws SQLException when the driver is not recognized
+ */
+ public void setDriver(String driverName) throws SQLException {
+ // we ensure that the driver is known
+ this.driver = null;
+ for ( DBDatabase db: DBDatabase.VALUES ) {
+ if ( DBPlugin.areEqual(db.getDriverName(), driverName) ) {
+ this.driver = driverName.toLowerCase();
+ return;
+ }
+ }
+ throw new SQLException("Unknown driver "+driverName);
+ }
+
+ /**
+ * Name or IP address of the server hosting the database
+ */
+ @Getter @Setter private String server = "";
+
+ /**
+ * TCP port on which the database listens to
+ *
+ * port should be between 0 and 65535
+ */
+ @Getter private int port = 0;
+
+ /**
+ * TCP port on which the database listens to
+ *
+ * @param portValue should be between 0 and 65535
+ * @throws Exception if the port is negative or greater than 65535
+ */
+ public void setPort(int portValue) throws Exception {
+ // we ensure that the port is > 0 and < 65536
+ if ( (portValue < 0) || (portValue > 65535) )
+ throw new Exception("Port should be between 0 and 65535");
+ this.port = portValue;
+ }
+
+ /**
+ * Database name
+ */
+ @Getter @Setter private String database = "";
+
+ /**
+ * Schema name
+ */
+ @Getter @Setter private String schema = "";
+
+ /**
+ * Username used to connect to the database
+ */
+ @Getter @Setter private String username = "";
+
+ /**
+ * Encrypted password used to connect to the database
+ */
+ @Getter @Setter private String encryptedPassword = "";
+
+ /**
+ * Get the decrypted the password used to connect to the database
+ * @return decrypted password
+ * @throws InvalidKeyException
+ * @throws IllegalBlockSizeException
+ * @throws BadPaddingException
+ * @throws InvalidAlgorithmParameterException
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchPaddingException
+ */
+ public String getDecryptedPassword() throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException {
+ if ( this.encryptedPassword.equals("") )
+ return "";
+ return new String(getCipher(Cipher.DECRYPT_MODE).doFinal(Base64.getDecoder().decode(this.encryptedPassword)));
+ }
+
+ /**
+ * Set the decrypted password used to connect to the database
+ * @param password the decrypted password
+ * @throws InvalidKeyException
+ * @throws IllegalBlockSizeException
+ * @throws BadPaddingException
+ * @throws InvalidAlgorithmParameterException
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchPaddingException
+ */
+ public void setDecryptedPassword(String password) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException {
+ this.encryptedPassword = DBPlugin.isEmpty(password) ? "" : Base64.getEncoder().encodeToString(getCipher(Cipher.ENCRYPT_MODE).doFinal(password.getBytes()));
+ }
+
+ /**
+ * Should we export snapshots of the views
+ */
+ @Getter @Setter private boolean viewSnapshotRequired = false;
+
+ /**
+ * Border width to add around view snapshots
+ */
+ @Getter @Setter private int viewsImagesBorderWidth = 10;
+
+ /**
+ * Scale factor of view snapshots
+ */
+ @Getter @Setter private int viewsImagesScaleFactor = 100;
+
+ /**
+ * In case of Neo4J database, should we generate native relationships
+ */
+ @Getter @Setter private boolean neo4jNativeMode = false;
+
+ /**
+ * In case of Neo4J database, should we empty the database before export
+ */
+ @Setter private boolean shouldEmptyNeo4jDB = false;
+
+ /**
+ * In case of a Neo4J database
+ * @return true if the plugin should empty the database before exporting the Archi components
+ */
+ public boolean shouldEmptyNeo4jDB() {
+ return this.shouldEmptyNeo4jDB;
+ }
+
+ /**
+ * Should we use typed relationships in Neo4j databases
+ */
+ @Getter @Setter private boolean neo4jTypedRelationship = false;
+
+
+ /**
+ * @param driver
+ * @return the default TCP port for a given driver
+ */
+ public static int getDefaultPort(String driver) {
+ for ( DBDatabase database: DBDatabase.VALUES ) {
+ if ( DBPlugin.areEqual(database.getDriverName(), driver.toLowerCase()) ) return database.getDefaultPort();
+ }
+ return 0;
+ }
+
+ /**
+ * @return if the schema is set, returns the schema name followed by a dot, directly usable in SQL requests
+ */
+ public String getSchemaPrefix() {
+ if ( this.schema.isEmpty() )
+ return "";
+ return this.schema + ".";
+ }
+
+ /**
+ * @return CQL if Neo4j database selected, or SQL in all other cases
+ */
+ public String getLanguage() {
+ if ( DBPlugin.areEqual(this.driver, "neo4j") )
+ return "CQL";
+ return "SQL";
+ }
+
+
+ /**
+ * Standard mode (in which the JDBC connection string is calculated from fields)
+ * Expert mode (in which the JDBC connection string is provided by the user)
+ */
+ @Getter @Setter private boolean expertMode = false;
+
+ /**
+ * in Standard mode, the JDBC string is calculated from the individual strings
+ * in Export mode, the JDBC string is provided as is
+ */
+ @Setter private String jdbcConnectionString;
+
+ /**
+ * in Standard mode, the JDBC string is calculated from the individual strings
+ * in Export mode, the JDBC string is provided as is
+ * @return the JDBC connection string, "" if the driver is unknown
+ */
+ public String getJdbcConnectionString() {
+ if ( ! isExpertMode() ) {
+ switch (this.getDriver()) {
+ case "postgresql":
+ this.jdbcConnectionString = "jdbc:postgresql://" + this.getServer() + ":" + this.getPort() + "/" + this.getDatabase();
+ break;
+ case "ms-sql":
+ this.jdbcConnectionString = "jdbc:sqlserver://" + this.getServer() + ":" + this.getPort() + ";databaseName=" + this.getDatabase();
+ try {
+ if ( DBPlugin.isEmpty(this.getUsername()) && DBPlugin.isEmpty(this.getDecryptedPassword()) )
+ this.jdbcConnectionString += ";integratedSecurity=true";
+ } catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException | NoSuchAlgorithmException | NoSuchPaddingException e) {
+ DBGui.popup(Level.ERROR, "Failed to decrypt password.", e);
+ this.jdbcConnectionString = "";
+ }
+ break;
+ case "mysql":
+ this.jdbcConnectionString = "jdbc:mysql://" + this.getServer() + ":" + this.getPort() + "/" + this.getDatabase();
+ break;
+ case "neo4j":
+ this.jdbcConnectionString = "jdbc:neo4j:bolt://" + this.getServer() + ":" + this.getPort();
+ break;
+ case "oracle":
+ this.jdbcConnectionString = "jdbc:oracle:thin:@" + this.getServer() + ":" + this.getPort() + ":" + this.getDatabase();
+ break;
+ case "sqlite":
+ this.jdbcConnectionString = "jdbc:sqlite:"+this.getServer();
+ break;
+ default:
+ this.jdbcConnectionString = "";
+ }
+ }
+ return this.jdbcConnectionString;
+ }
+
+ /**
+ * Calculates a JDBC connection string
+ * @param driverName
+ * @param serverName
+ * @param port
+ * @param databaseName
+ * @param username
+ * @param password
+ * @return the JDBC connection string
+ * @throws SQLException if the JDBC driver is unknown
+ */
+ static public String getJdbcConnectionString(String driverName, String serverName, int port, String databaseName, String username, String password) throws SQLException {
+ String jdbcString = "";
+
+ switch (driverName) {
+ case "postgresql":
+ jdbcString = "jdbc:postgresql://" + serverName + ":" + port + "/" + databaseName;
+ break;
+ case "ms-sql":
+ jdbcString = "jdbc:sqlserver://" + serverName + ":" + port + ";databaseName=" + databaseName;
+ if ( DBPlugin.isEmpty(username) && DBPlugin.isEmpty(password) )
+ jdbcString += ";integratedSecurity=true";
+ break;
+ case "mysql":
+ jdbcString = "jdbc:mysql://" + serverName + ":" + port + "/" + databaseName;
+ break;
+ case "neo4j":
+ jdbcString = "jdbc:neo4j:bolt://" + serverName + ":" + port;
+ break;
+ case "oracle":
+ jdbcString = "jdbc:oracle:thin:@" + serverName + ":" + port + ":" + databaseName;
+ break;
+ case "sqlite":
+ jdbcString = "jdbc:sqlite:"+serverName;
+ break;
+ default:
+ throw new SQLException("Unknonwn driver " + driverName); // just in case
+ }
+
+ return jdbcString;
+ }
+
+ /**
+ * Gets all the database entries from the preference store
+ *
+ * @param includeNeo4j True if the Neo4J database must be included, false if the Neo4J databases must me excluded
+ * @return List of the database entries
+ */
+ public static List getAllDatabasesFromPreferenceStore() {
+ if ( logger.isDebugEnabled() ) logger.debug("Getting databases preferences from preference store");
+ List databaseEntries = new ArrayList();
+ IPersistentPreferenceStore store = DBPlugin.INSTANCE.getPreferenceStore();
+
+ databaseEntries.clear();
+
+ int lines = store.getInt(preferenceName);
+
+ for (int line = 0; line databaseEntries) {
+ cleanupDatabaseEntriesFromPreferenceStore();
+
+ if ( logger.isDebugEnabled() ) logger.debug("Persisting all database entries in the preference store");
+
+ IPersistentPreferenceStore store = DBPlugin.INSTANCE.getPreferenceStore();
+
+ int nbDatabases = databaseEntries.size();
+ store.setValue(preferenceName, nbDatabases);
+
+ for (int i = 0; i < nbDatabases; ++i) {
+ DBDatabaseEntry databaseEntry = databaseEntries.get(i);
+ databaseEntry.setIndex(i); // just in case, we force the index value
+ databaseEntry.persistIntoPreferenceStore();
+ }
+
+ try {
+ store.save();
+ } catch (IOException e) {
+ DBGui.popup(Level.ERROR, "Failed to save your preferences.", e);
+ }
+ }
+
+ /**
+ * Get a database entry from the database name
+ *
+ * @param databaseName database name of the database entry
+ * @return The database entry corresponding to the database name
+ * @throws Exception
+ */
+ public static DBDatabaseEntry getDBDatabaseEntryFromDatabaseName(String databaseName) throws Exception {
+ List databaseEntries = getAllDatabasesFromPreferenceStore();
+
+ for (DBDatabaseEntry databaseEntry : databaseEntries) {
+ if ( DBPlugin.areEqual(databaseEntry.getName(), databaseName) ) {
+ return databaseEntry;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get a database entry from the database ID
+ *
+ * @param databaseId database ID of the database entry
+ * @return The database entry corresponding to the database ID
+ * @throws Exception
+ */
+ public static DBDatabaseEntry getDBDatabaseEntryFromDatabaseID(String databaseId) throws Exception {
+ List databaseEntries = getAllDatabasesFromPreferenceStore();
+
+ for (DBDatabaseEntry databaseEntry : databaseEntries) {
+ if ( DBPlugin.areEqual(databaseEntry.getId(), databaseId) ) {
+ return databaseEntry;
+ }
+ }
+ return null;
+ }
+
+ private static Cipher getCipher(int cipherMode) throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException {
+ String passwordEncryptionKey = null;
+ boolean errorMessageAlreadyPrinted = false;
+
+ // the default key is the MAC address of the first physical network interface
+ try {
+ Enumeration nics = NetworkInterface.getNetworkInterfaces();
+ while (nics.hasMoreElements()) {
+ NetworkInterface net = nics.nextElement();
+ byte[] mac = net.getHardwareAddress();
+
+ if ( mac != null ) {
+ StringBuilder key = new StringBuilder();
+ for (int i = 0; i < mac.length; i++) {
+ key.append(String.format("%x", mac[i]));
+ if (i < mac.length - 1)
+ key.append(":");
+ }
+
+ passwordEncryptionKey = key.toString();
+ break;
+ }
+ }
+ } catch (SocketException e) {
+ logger.error("Failed to calculate encryption key, defaulting to default one.", e);
+ errorMessageAlreadyPrinted = true;
+ }
+
+ if ( passwordEncryptionKey == null ) {
+ passwordEncryptionKey = "VerySimpleKey."; // default key in case we cannot calculate a unique one for the running machine
+ if ( !errorMessageAlreadyPrinted )
+ logger.error("Failed to calculate encryption key, defaulting to default one.");
+ }
+
+ int maxKeyLength = Cipher.getMaxAllowedKeyLength("Blowfish");
+ if ( passwordEncryptionKey.length() > maxKeyLength )
+ passwordEncryptionKey = passwordEncryptionKey.substring(0, maxKeyLength-1);
+
+ int minKeyLength = 32;
+ if ( passwordEncryptionKey.length() < minKeyLength ) {
+ StringBuilder sb = new StringBuilder(passwordEncryptionKey);
+ while ( sb.length() < minKeyLength )
+ sb.append(passwordEncryptionKey.substring(0,Math.min(passwordEncryptionKey.length(), minKeyLength-sb.length())));
+ passwordEncryptionKey = sb.toString();
+ }
+
+ SecretKeySpec secretKeySpec = new SecretKeySpec(passwordEncryptionKey.getBytes(), "Blowfish");
+ Cipher cipher = Cipher.getInstance("Blowfish");
+ cipher.init(cipherMode, secretKeySpec, cipher.getParameters());
+
+ return cipher;
+ }
+}
diff --git a/sources/src/org/archicontribs/database/DBException.java b/sources/src/org/archicontribs/database/DBException.java
new file mode 100644
index 00000000..e29f9477
--- /dev/null
+++ b/sources/src/org/archicontribs/database/DBException.java
@@ -0,0 +1,42 @@
+/**
+ * This program and the accompanying materials
+ * are made available under the terms of the License
+ * which accompanies this distribution in the file LICENSE.txt
+ */
+
+package org.archicontribs.database;
+
+
+/**
+ * The BDException class is an Exception class that is thrown each time there is an impossibility to import or export a component to the datatabase
+ *
+ * @author Herve Jouin
+ */
+public class DBException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Creates a new exception
+ * @param message describes the error that is raised
+ */
+ public DBException (String message) {
+ super (message);
+ }
+
+ /**
+ * Creates a new exception
+ * @param cause describes the primary exception that causes this exception
+ */
+ public DBException (Throwable cause) {
+ super (cause);
+ }
+
+ /**
+ * Creates a new exception
+ * @param message describes the error that is raised
+ * @param cause describes the primary exception that causes this exception
+ */
+ public DBException (String message, Throwable cause) {
+ super (message, cause);
+ }
+}
diff --git a/sources/src/org/archicontribs/database/DBExporter.java b/sources/src/org/archicontribs/database/DBExporter.java
new file mode 100644
index 00000000..bc8b2ea3
--- /dev/null
+++ b/sources/src/org/archicontribs/database/DBExporter.java
@@ -0,0 +1,41 @@
+/**
+ * This program and the accompanying materials
+ * are made available under the terms of the License
+ * which accompanies this distribution in the file LICENSE.txt
+ */
+
+package org.archicontribs.database;
+
+import java.io.IOException;
+
+import org.apache.log4j.Level;
+import org.archicontribs.database.GUI.DBGui;
+import org.archicontribs.database.GUI.DBGuiExportModel;
+import org.archicontribs.database.model.DBArchimateModel;
+import com.archimatetool.editor.model.IModelExporter;
+import com.archimatetool.model.IArchimateModel;
+
+/**
+ * Database Model Exporter. This class exports the model components into a central repository (database).
+ *
+ * @author Herve Jouin
+ */
+public class DBExporter implements IModelExporter {
+ private static final DBLogger logger = new DBLogger(DBExporter.class);
+
+ /**
+ * Exports the model into the database.
+ * This method is called when the user clicks on the "Export / Export to database" menu entry of Archi
+ */
+ @Override
+ public void export(IArchimateModel archimateModel) throws IOException {
+ logger.info("Exporting model "+archimateModel.getName());
+
+ try {
+ DBGuiExportModel exportModel = new DBGuiExportModel((DBArchimateModel)archimateModel, "Export model");
+ exportModel.run();
+ } catch (Exception e) {
+ DBGui.popup(Level.ERROR,"Cannot export model", e);
+ }
+ }
+}
diff --git a/sources/src/org/archicontribs/database/DBImporter.java b/sources/src/org/archicontribs/database/DBImporter.java
new file mode 100644
index 00000000..4cc17673
--- /dev/null
+++ b/sources/src/org/archicontribs/database/DBImporter.java
@@ -0,0 +1,46 @@
+/**
+ * This program and the accompanying materials
+ * are made available under the terms of the License
+ * which accompanies this distribution in the file LICENSE.txt
+ */
+
+package org.archicontribs.database;
+
+import java.io.IOException;
+import java.lang.invoke.MethodHandles;
+
+import org.apache.log4j.Level;
+import org.archicontribs.database.GUI.DBGui;
+import org.archicontribs.database.GUI.DBGuiImportModel;
+import com.archimatetool.editor.model.IModelImporter;
+import com.archimatetool.editor.model.ISelectedModelImporter;
+import com.archimatetool.model.IArchimateModel;
+
+/**
+ * Import from Database
+ *
+ * @author Herve Jouin
+ */
+public class DBImporter implements IModelImporter, ISelectedModelImporter {
+ private static final DBLogger logger = new DBLogger(MethodHandles.lookup().lookupClass());
+
+ @Override
+ public void doImport() throws IOException {
+ doImport(null);
+ }
+ /**
+ * Imports the model from the database.
+ * This method is called when the user clicks on the "Import / Import from database" menu entry of Archi
+ */
+ @Override
+ public void doImport(IArchimateModel notUsed) throws IOException {
+ logger.info("Importing model.");
+
+ try {
+ DBGuiImportModel importModel = new DBGuiImportModel("Import model");
+ importModel.run();
+ } catch (Exception e) {
+ DBGui.popup(Level.ERROR,"Cannot import model", e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/sources/src/org/archicontribs/database/DBLogger.java b/sources/src/org/archicontribs/database/DBLogger.java
new file mode 100644
index 00000000..b8127033
--- /dev/null
+++ b/sources/src/org/archicontribs/database/DBLogger.java
@@ -0,0 +1,398 @@
+/**
+ * This program and the accompanying materials
+ * are made available under the terms of the License
+ * which accompanies this distribution in the file LICENSE.txt
+ */
+
+package org.archicontribs.database;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.log4j.PropertyConfigurator;
+import org.archicontribs.database.GUI.DBGui;
+
+import lombok.Getter;
+
+/**
+ * The BDLogger class is a proxy for the log4j Logger class.
+ *
+ * @author Herve jouin
+ */
+public class DBLogger {
+ static private boolean initialised = false;
+ private String topCornerString = (char)0x250c+" ";
+ private String verticalString = (char)0x2502+" ";
+ private String bottomCornerString = (char)0x2514+" ";
+
+ /**
+ * Gets the logger
+ */
+ @Getter private Logger logger;
+
+ /**
+ * Creates a proxy to to the Log4J logger class
+ * @param clazz Class that will be reported on the log lines
+ */
+ public DBLogger(Class clazz) {
+ if ( ! initialised ) {
+ try {
+ configure();
+ } catch (Exception e) {
+ initialised = false;
+ DBGui.popup(Level.ERROR, "Failed to configure logger", e);
+ }
+ }
+ this.logger = Logger.getLogger(clazz);
+ }
+
+ /**
+ * Configure the logger
+ * @throws Exception
+ */
+ public void configure() throws Exception {
+ LinkedProperties properties = getLoggerProperties();
+
+ if ( properties != null ) {
+ PropertyConfigurator.configure(properties);
+ initialised = true;
+ } else {
+ LogManager.shutdown();
+ initialised = false;
+ }
+
+ if ( initialised ) {
+ Logger oldLogger = this.logger;
+ this.logger = Logger.getLogger(DBLogger.class);
+ info("Logger initialised.");
+ if ( isTraceEnabled() ) {
+ StringBuilder param = new StringBuilder();
+ String eol = "";
+ if ( properties!= null ) {
+ for ( Object oKey: properties.orderedKeys() ) {
+ param.append(" "+(String)oKey+" = "+properties.getProperty((String)oKey)+eol);
+ eol = "\n";
+ }
+ trace(param.toString());
+ }
+ }
+ this.logger = oldLogger;
+ }
+ }
+
+ /**
+ * Logs a message
+ * @param clazz Class that will be reported in the log line
+ * @param level level of the log line (may be Level.ERROR, Level.WARN, Level.INFO, Level.DEBUG, Level.TRACE)
+ * @param message Message to print on the log line
+ * @param t Exception to add to the log file (the exception message and stacktrace will be added to the log file)
+ */
+ public void log(Class clazz, Level level, String message, Throwable t) {
+ String className = clazz.getName();
+
+ if ( initialised ) {
+ String[] lines = message.split("\n");
+ if ( lines.length == 1 ) {
+ this.logger.log(className, level, "- "+message.replace("\r",""), t);
+ } else {
+ this.logger.log(className, level, this.topCornerString+lines[0].replace("\r",""), null);
+ for ( int i=1 ; i < lines.length-1 ; ++i) {
+ this.logger.log(className, level, this.verticalString+lines[i].replace("\r",""), null);
+ }
+ this.logger.log(className, level, this.bottomCornerString+lines[lines.length-1].replace("\r",""), t);
+ }
+ }
+ }
+
+ /**
+ * Logs a message
+ * @param level level of the log line (may be Level.ERROR, Level.WARN, Level.INFO, Level.DEBUG, Level.TRACE)
+ * @param message Message to print on the log line
+ */
+ public void log(Level level, String message) { log(this.getClass(), level, message, null); }
+
+ /**
+ * Logs a message
+ * @param clazz Class that will be reported in the log line
+ * @param level level of the log line (may be Level.ERROR, Level.WARN, Level.INFO, Level.DEBUG, Level.TRACE)
+ * @param message Message to print on the log line
+ */
+ public void log(Class clazz, Level level, String message) { log(clazz, level, message, null); }
+
+ /**
+ * Logs a fatal message
+ * @param message
+ */
+ public void fatal(String message) { log(this.getClass(), Level.FATAL, message, null); }
+
+ /**
+ * Logs a fatal message
+ * @param message
+ * @param t
+ */
+ public void fatal(String message, Throwable t) { log(this.getClass(), Level.FATAL, message, t); }
+ /**
+ * Logs a fatal message
+ * @param clazz
+ * @param message
+ */
+ public void fatal(Class clazz, String message) { log(clazz, Level.FATAL, message, null); }
+ /**
+ * Logs a fatal message
+ * @param clazz
+ * @param message
+ * @param t
+ */
+ public void fatal(Class clazz, String message, Throwable t) { log(clazz, Level.FATAL, message, t); }
+
+ /**
+ * Logs an error message
+ * @param message
+ */
+ public void error(String message) { log(this.getClass(), Level.ERROR, message, null); }
+ /**
+ * Logs an error message
+ * @param message
+ * @param t
+ */
+ public void error(String message, Throwable t) { log(this.getClass(), Level.ERROR, message, t); }
+ /**
+ * Logs an error message
+ * @param clazz
+ * @param message
+ */
+ public void error(Class clazz, String message) { log(clazz, Level.ERROR, message, null); }
+ /**
+ * Logs an error message
+ * @param clazz
+ * @param message
+ * @param t
+ */
+ public void error(Class clazz, String message, Throwable t) { log(clazz, Level.ERROR, message, t); }
+
+ /**
+ * Logs a warn message
+ * @param message
+ */
+ public void warn(String message) { log(this.getClass(), Level.WARN, message, null); }
+ /**
+ * Logs a warn message
+ * @param message
+ * @param t
+ */
+ public void warn(String message, Throwable t) { log(this.getClass(), Level.WARN, message, t); }
+ /**
+ * Logs a warn message
+ * @param clazz
+ * @param message
+ */
+ public void warn(Class clazz, String message) { log(clazz, Level.WARN, message, null); }
+ /**
+ * Logs a warn message
+ * @param clazz
+ * @param message
+ * @param t
+ */
+ public void warn(Class clazz, String message, Throwable t) { log(clazz, Level.WARN, message, t); }
+
+ /**
+ * Logs an info message
+ * @param message to print in the log file
+ */
+ public void info(String message) { log(this.getClass(), Level.INFO, message, null); }
+ /**
+ * Logs an info message
+ * @param message to print in the log file
+ * @param t exception to add to the log file
+ */
+ public void info(String message, Throwable t) { log(this.getClass(), Level.INFO, message, t); }
+ /**
+ * Logs an info message
+ * @param clazz class for which the message is printed to the log file
+ * @param message to print in the log file
+ */
+ public void info(Class clazz, String message) { log(clazz, Level.INFO, message, null); }
+ /**
+ * Logs an info message
+ * @param clazz class for which the message is printed to the log file
+ * @param message to print in the log file
+ * @param t exception to add to the log file
+ */
+ public void info(Class clazz, String message, Throwable t) { log(clazz, Level.INFO, message, t); }
+
+ /**
+ * Logs a debug message
+ * @param message to print in the log file
+ */
+ public void debug(String message) { log(this.getClass(), Level.DEBUG, message, null); }
+ /**
+ * Logs a debug message
+ * @param message to print in the log file
+ * @param t exception to add to the log file
+ */
+ public void debug(String message, Throwable t) { log(this.getClass(), Level.DEBUG, message, t); }
+ /**
+ * Logs a debug message
+ * @param clazz class for which the message is printed to the log file
+ * @param message to print in the log file
+ */
+ public void debug(Class clazz, String message) { log(clazz, Level.DEBUG, message, null); }
+ /**
+ * Logs a debug message
+ * @param clazz class for which the message is printed to the log file
+ * @param message to print in the log file
+ * @param t exception to add to the log file
+ */
+ public void debug(Class clazz, String message, Throwable t) { log(clazz, Level.DEBUG, message, t); }
+
+ /**
+ * Logs a trace message
+ * @param message to print in the log file
+ */
+ public void trace(String message) { log(this.getClass(), Level.TRACE, message, null); }
+ /**
+ * Logs a trace message
+ * @param message to print in the log file
+ * @param t exception to add to the log file
+ */
+ public void trace(String message, Throwable t) { log(this.getClass(), Level.TRACE, message, t); }
+ /**
+ * Logs a trace message
+ * @param clazz class for which the message is printed to the log file
+ * @param message to print in the log file
+ */
+ public void trace(Class clazz, String message) { log(clazz, Level.TRACE, message, null); }
+ /**
+ * Logs a trace message
+ * @param clazz class for which the message is printed to the log file
+ * @param message to print in the log file
+ * @param t exception to add to the log file
+ */
+ public void trace(Class clazz, String message, Throwable t) { log(clazz, Level.TRACE, message, t); }
+
+ /**
+ * Get the initialized state of the logger
+ * @return true if the logger is initialized, false if it needs to be initialized
+ */
+ public static boolean isInitialised() {
+ return initialised;
+ }
+
+ /**
+ * Gets the logger properties
+ * @return the logger properties
+ * @throws Exception if the properties cannot be get
+ */
+ private LinkedProperties getLoggerProperties() throws Exception {
+ //LogManager.resetConfiguration();
+
+
+ String loggerMode = DBPlugin.INSTANCE.getPreferenceStore().getString("loggerMode");
+ if ( loggerMode == null )
+ return null;
+
+ LinkedProperties properties = new LinkedProperties() {
+ private static final long serialVersionUID = 1L;
+ @Override
+ public Set keySet() { return Collections.unmodifiableSet(new TreeSet(super.keySet())); }
+ };
+
+ debug("getting logger preferences from store");
+
+ switch (loggerMode) {
+ case "disabled":
+ return null;
+
+ case "simple":
+ properties.setProperty("log4j.rootLogger", DBPlugin.INSTANCE.getPreferenceStore().getString("loggerLevel").toUpperCase()+", stdout, file");
+
+ properties.setProperty("log4j.appender.stdout", "org.apache.log4j.ConsoleAppender");
+ properties.setProperty("log4j.appender.stdout.Target", "System.out");
+ properties.setProperty("log4j.appender.stdout.layout", "org.apache.log4j.PatternLayout");
+ properties.setProperty("log4j.appender.stdout.layout.ConversionPattern", "%d{yyyy-MM-dd HH:mm:ss} %-5p %4L:%-40.40C{1} %m%n");
+
+ properties.setProperty("log4j.appender.file", "org.apache.log4j.FileAppender");
+ properties.setProperty("log4j.appender.file.ImmediateFlush", "true");
+ properties.setProperty("log4j.appender.file.Append", "false");
+ properties.setProperty("log4j.appender.file.Encoding", "UTF-8");
+ properties.setProperty("log4j.appender.file.File", DBPlugin.INSTANCE.getPreferenceStore().getString("loggerFilename"));
+ properties.setProperty("log4j.appender.file.layout", "org.apache.log4j.PatternLayout");
+ properties.setProperty("log4j.appender.file.layout.ConversionPattern", "%d{yyyy-MM-dd HH:mm:ss} %-5p %4L:%-40.40C{1} %m%n");
+ break;
+
+ case "expert":
+ String loggerExpert = DBPlugin.INSTANCE.getPreferenceStore().getString("loggerExpert");
+ if ( loggerExpert == null ) DBPlugin.INSTANCE.getPreferenceStore().getDefaultString("loggerExpert");
+
+ try {
+ properties.load(new StringReader(loggerExpert));
+ } catch (@SuppressWarnings("unused") IOException err) {
+ throw new Exception("Error while parsing \"loggerExpert\" properties from the preference store");
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return properties;
+ }
+
+ /**
+ * List that maintain elements order
+ */
+ private class LinkedProperties extends Properties {
+ private static final long serialVersionUID = 1L;
+
+ private final HashSet keys = new LinkedHashSet();
+
+ public LinkedProperties() {
+ }
+
+ public Iterable orderedKeys() {
+ return Collections.list(keys());
+ }
+
+ @Override
+ public synchronized Enumeration keys() {
+ return Collections.enumeration(this.keys);
+ }
+
+ @Override
+ public synchronized Object put(Object key, Object value) {
+ this.keys.add(key);
+ return super.put(key, value);
+ }
+ }
+
+ /**
+ * @return true if the logger is configured to print trace messages
+ */
+ public boolean isTraceEnabled() {
+ return initialised && this.logger.isTraceEnabled();
+ }
+
+ /**
+ * @return true if the logger is configured to print debug messages
+ */
+ public boolean isDebugEnabled() {
+ return initialised && this.logger.isDebugEnabled();
+ }
+
+ /**
+ * @return true if the logger is configured to print SQL requests
+ */
+ public boolean isTraceSQLEnabled() {
+ return isTraceEnabled() && DBPlugin.INSTANCE.getPreferenceStore().getBoolean("traceSQL");
+ }
+}
diff --git a/sources/src/org/archicontribs/database/DBPlugin.java b/sources/src/org/archicontribs/database/DBPlugin.java
new file mode 100644
index 00000000..2ac53127
--- /dev/null
+++ b/sources/src/org/archicontribs/database/DBPlugin.java
@@ -0,0 +1,364 @@
+/**
+ * This program and the accompanying materials
+ * are made available under the terms of the License
+ * which accompanies this distribution in the file LICENSE.txt
+ */
+
+package org.archicontribs.database;
+
+import java.io.File;
+import java.io.IOException;
+import org.osgi.framework.Version;
+import java.util.Locale;
+import java.util.UUID;
+
+import org.apache.log4j.Level;
+import org.archicontribs.database.GUI.DBGui;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jface.preference.IPersistentPreferenceStore;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.eclipse.ui.preferences.ScopedPreferenceStore;
+
+import com.archimatetool.model.IIdentifier;
+
+import lombok.Getter;
+
+
+/**
+ * Database Model Importer / Exporter
+ *
+ * The DBPlugin class implements static methods and properties used everywhere else in the database plugin.
+ *
+ * @author Herve Jouin
+ *
+ * v4.9.0 22/09/2021 Change plugin version numbering to match Archi version
+ * Adapt plugin to Archi 4.9, especially specialization
+ *
+ * v4.8.1 22/09/2021 fix coherence checking
+ * change plugin numbering to follow Archi's and indicate more clearly that this version is compatible with Archi 4.8 and not Archi 4.9
+ *
+ * v4.8.2 22/09/2021 fix exception raised when model purpose is null rather than an empty string
+ *
+ * TO-DO list:
+ * ----------
+ * Import components from database:
+ * allow to import elements recursively (with depth limit)
+ * Get component history:
+ * show view screenshots to ease views comparison
+ * Miscellaneous:
+ * add an option to check for relationships that are in the database but would not be in the in memory model
+ * --> nearly done with "get history from database". Just needs to compare the list of relationships
+ * create a new windows that will show up detailed statistics about the model
+ * add more jdbc drivers (mongodb, odbc, etc ...)
+ * add an option to duplicate a model
+ * create database admin procedures
+ */
+public class DBPlugin extends AbstractUIPlugin {
+ /** ID of the plugin */
+ public static final String PLUGIN_ID = "org.archicontribs.database";
+
+ /** version of the plugin */
+ public static Version pluginVersion = Platform.getBundle(PLUGIN_ID).getVersion();
+
+
+ /** Name ofthe plugin */
+ public static final String pluginName = "DatabasePlugin";
+
+ /** Title od the plugin's windows */
+ public static final String pluginTitle = "Database import/export plugin v" + pluginVersion.toString();
+
+ /** Name of the plugin's package */
+ public static String pluginsPackage;
+
+ /** folder where the plugin is installed */
+ public static String pluginsFolder;
+
+ /** Name of the plugin's JAR file */
+ public static String pluginsFilename;
+
+ /**
+ * static instance that allow to keep information between calls of the plugin
+ */
+ public static DBPlugin INSTANCE;
+
+ /**
+ * PreferenceStore allowing to store the plugin configuration.
+ */
+ private static IPersistentPreferenceStore preferenceStore = null;
+
+ /**
+ * Name of all the table names in a SQL database
+ */
+ public static String[] allSQLTables = { "archimatediagrammodel", "archimateelement", "bendpoint", "canvasmodel", "canvasmodelblock", "canvasmodelimage", "canvasmodelsticky", "connection", "diagrammodelarchimateobject", "diagrammodelreference", "folder", "model", "property", "relationship", "sketchmodel", "sketchmodelactor", "sketchmodelsticky"};
+
+ static DBLogger logger;
+
+ /**
+ * Choices available when a conflict is detected in the database
+ * askUser Ask the user what he wishes to do
+ * doNotExport Do not export to the database
+ * exportToDatabase Export to the database
+ * importFromDatabase Replace the component with the version in the database
+ */
+ public enum CONFLICT_CHOICE {
+ /** Ask the user what he wishes to do */ askUser,
+ /** Do not export to the database */ doNotExport,
+ /** Export to the database */ exportToDatabase,
+ /** Replace the component with the version in the database */ importFromDatabase
+ }
+
+ /**
+ * Returns true is runs on Windows operating system, false for all other operating systems
+ */
+ @Getter private static boolean WindowsOperatingSystem = System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("windows");
+
+ /**
+ * The DBPlugin class is instantiated when Archi starts
+ * It:
+ * 1- configures the preference store,
+ * 2- defines default values for standard options (in case they've not be defined in the preference store)
+ * 3- checks if a new version of the plugin is available on GitHub
+ */
+ public DBPlugin() {
+ INSTANCE = this;
+
+ // forcing UTF-8
+ System.setProperty("client.encoding.override", "UTF-8");
+ System.setProperty("file.encoding", "UTF-8");
+
+ preferenceStore = this.getPreferenceStore();
+ preferenceStore.setDefault("exportWithDefaultValues", false);
+ preferenceStore.setDefault("checkForUpdateAtStartup", false);
+ preferenceStore.setDefault("closeIfSuccessful", false);
+ preferenceStore.setDefault("showZeroValues", false);
+ preferenceStore.setDefault("compareBeforeExport", true);
+ preferenceStore.setDefault("deleteIfImportError", true);
+ preferenceStore.setDefault("removeDirtyFlag", false);
+ preferenceStore.setDefault("showIdInContextMenu", false);
+ preferenceStore.setDefault("traceSQL", true);
+ preferenceStore.setDefault("checkMaxMemory", true);
+ preferenceStore.setDefault("checkNotNullConstraints", true);
+ preferenceStore.setDefault("copySuffix", " (copy)");
+ preferenceStore.setDefault("defaultImportMode", "template");
+ preferenceStore.setDefault("loggerMode", "disabled");
+ preferenceStore.setDefault("loggerLevel", "INFO");
+ preferenceStore.setDefault("loggerFilename", System.getProperty("user.home")+File.separator+pluginName+".log");
+ preferenceStore.setDefault("loggerExpert",
+ "log4j.rootLogger = INFO, stdout, file\n"+
+ "\n"+
+ "log4j.appender.stdout = org.apache.log4j.ConsoleAppender\n"+
+ "log4j.appender.stdout.Target = System.out\n"+
+ "log4j.appender.stdout.layout = org.apache.log4j.PatternLayout\n"+
+ "log4j.appender.stdout.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %4L:%-40.40C{1} %m%n\n"+
+ "\n"+
+ "log4j.appender.file = org.apache.log4j.FileAppender\n"+
+ "log4j.appender.file.ImmediateFlush = true\n"+
+ "log4j.appender.file.Append = false\n"+
+ "log4j.appender.file.Encoding = UTF-8\n"+
+ "log4j.appender.file.File = "+(System.getProperty("user.home")+File.separator+pluginName+".log").replace("\\", "\\\\")+"\n"+
+ "log4j.appender.file.layout = org.apache.log4j.PatternLayout\n"+
+ "log4j.appender.file.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %4L:%-40.40C{1} %m%n");
+ logger = new DBLogger(DBPlugin.class);
+ logger.info("Initialising "+pluginName+" plugin ...");
+
+ logger.info("===============================================");
+ // we force the class initialization by the SWT thread
+ Display.getDefault().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ DBGui.closePopup();
+ }
+ });
+
+ // we check if the database plugin has got 1 GB max memory (in fact, Xmx1g = 954 MB so in reality we check for 950 MB)
+ int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1000000);
+
+ if ( maxMemory < 950 ) {
+ if ( getPreferenceStore().getBoolean("checkMaxMemory") )
+ DBGui.popup(Level.WARN, "Archi is configured with "+maxMemory+" MB max memory.\n\n"
+ + "If you plan to use the database plugin with huge models, we recommand to configure Archi\n"
+ + "with 1 GB of memory (you may add or update the \"-Xmx\" parameter in the Archi.ini file).\n\n"
+ + "You may deactivate the memory check in the database plugin preference page.");
+ else
+ logger.warn("Archi is configured with "+maxMemory+" MB max memory instead of the 1 GB recommanded.");
+ } else
+ logger.debug("Archi is setup with "+maxMemory+" MB of memory.");
+
+
+
+ String welcomeMessage = null;
+ String preferenceStorePluginVersion = preferenceStore.getString("pluginVersion");
+ if ( (preferenceStorePluginVersion == null) || preferenceStorePluginVersion.isEmpty() ) {
+ // if the "pluginVersion" preference is not set, this means that this is the first time the plugin is run
+ // so we print out a welcome message
+ welcomeMessage = "Welcome to the Archi Database Plugin.\n\nThis plugin allows you to centralize your models in a SQL database, and export them to a graph database for analysis purpose.\n\nThe next step is to configure your database(s) on the plugin's preference page.";
+ } else {
+ Version oldPluginVersion = new Version(preferenceStorePluginVersion);
+ if ( oldPluginVersion.compareTo(pluginVersion) < 0 ) {
+ // if the "pluginVersion" preference is older, then the plugin has been upgraded
+ // so we print out a message confirming the upgrade
+ welcomeMessage = "The Database plugin has been upgraded from version "+preferenceStorePluginVersion+" to version "+pluginVersion.toString()+".";
+ } else if ( oldPluginVersion.compareTo(pluginVersion) > 0 ) {
+ // if the "pluginVersion" preference is newer, then the plugin has been downgraded
+ // so we print out a message confirming the downgrade
+ welcomeMessage = "The Database plugin has been downgraded from version "+preferenceStorePluginVersion+" to version "+pluginVersion.toString()+".";
+ }
+ }
+
+ preferenceStore.setValue("pluginVersion", pluginVersion.toString());
+ if ( welcomeMessage != null ) {
+ // we get all the DBDatabaseEntries in order to replace plain text passwords by encrypted passwords
+ try {
+ DBDatabaseEntry.getAllDatabasesFromPreferenceStore();
+ preferenceStore.save();
+ } catch (IOException e) {
+ DBGui.popup(Level.ERROR, "Failed to save your preferences.", e);
+ }
+ DBGui.popup(Level.INFO, welcomeMessage);
+ }
+
+ // we check if the plugin has been upgraded using the automatic procedure
+ try {
+ pluginsPackage = DBPlugin.class.getPackage().getName();
+ pluginsFilename = new File(DBPlugin.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getCanonicalPath();
+ pluginsFolder = (new File(pluginsFilename+File.separator+"..")).getCanonicalPath();
+
+ if ( logger.isDebugEnabled() ) {
+ logger.debug("Plugin's package = "+pluginsPackage);
+ logger.debug("Plugin's version = "+pluginVersion.toString());
+ logger.debug("Plugin's folder = "+pluginsFolder);
+ logger.debug("Plugin's filename = "+pluginsFilename);
+ }
+
+ if ( !pluginsFilename.endsWith(".jar") ) {
+ if ( logger.isTraceEnabled() ) logger.trace(" The plugin's filename is not a jar file, so we do not check for new plugin version on GitHub.");
+ } else {
+ if ( preferenceStore.getBoolean("checkForUpdateAtStartup") )
+ checkForUpdate(false);
+ }
+ } catch ( IOException e ) {
+ DBGui.popup(Level.ERROR, "Failed to get database plugin's folder.", e);
+ }
+ }
+
+ @Override
+ public IPersistentPreferenceStore getPreferenceStore() {
+ if (preferenceStore == null) {
+ preferenceStore = new ScopedPreferenceStore( InstanceScope.INSTANCE, PLUGIN_ID );
+ }
+ return preferenceStore;
+ }
+
+ /**
+ * Check if two strings are equals
+ *
+ * Replaces string.equals() to avoid nullPointerException
+ * @param str1 first string to compare
+ * @param str2 secong string to compare
+ * @return true if the strings are both null or have the same content, false if they are different
+ */
+ public static boolean areEqual(String str1, String str2) {
+ if ( str1 == null )
+ return str2 == null;
+
+ if ( str2 == null )
+ return false; // as str1 cannot be null at this stage
+
+ return str1.equals(str2);
+ }
+
+ /**
+ * Check if two strings are equals (ignore case)
+ *
+ * Replaces string.equals() to avoid nullPointerException
+ * @param str1 first string to compare
+ * @param str2 secong string to compare
+ * @return true if the strings are both null or have the same content, false if they are different
+ */
+ public static boolean areEqualIgnoreCase(String str1, String str2) {
+ if ( str1 == null )
+ return str2 == null;
+
+ if ( str2 == null )
+ return false; // as str1 cannot be null at this stage
+
+ return str1.equalsIgnoreCase(str2);
+ }
+
+ /**
+ * Check if a string is null or empty
+ *
+ * Replaces string.isEmpty() to avoid nullPointerException
+ * @param str string to check
+ * @return true if the string is null or empty, false if the string contains at least one char
+ */
+ public static boolean isEmpty(String str) {
+ return (str==null) || str.isEmpty();
+ }
+
+ /**
+ * Checks on GitHub if a new version of the plugin is available
+ * @param verbose
+ */
+ public static void checkForUpdate(boolean verbose) {
+ @SuppressWarnings("unused")
+ DBCheckForPluginUpdate dbCheckForUpdate = new DBCheckForPluginUpdate(
+ verbose,
+ "https://api.github.com/repos/archi-contribs/database-plugin/contents/v2",
+ "https://github.com/archi-contribs/database-plugin/blob/master/v2/release_note.md"
+ );
+ }
+
+ /**
+ * Generates a new ID for any Archi component
+ *
+ * @return Archi ID
+ */
+ public static String createID() {
+ return createID(null);
+ }
+
+ /**
+ * Generates a new ID for a given Archi component
+ * @param obj object for which the ID should be generated
+ *
+ * @return Archi ID
+ */
+ public static String createID(IIdentifier obj) {
+ // until Archi 4.4: the ID was created using model.getIDAdapter().getNewID()
+ // Archi 4.5 updated the ArchimateModel class to remove the getIDAdapter() method and introduces a new UUIDFactory class with a createID() method.
+
+ // as I wish my plugin works for both versions, I decided to write my own method (based on UUIDFactory.createID())
+
+ return UUID.randomUUID().toString();
+ }
+
+ /**
+ * Gets the boolean value from a Boolean, an Integer or a String
+ * @param obj
+ * @return Boolean : true if the obj value is true Integer: true if the obj value is greater than 0 String : true if the string can be converted to an Integer greater then 0 false in all other cases
+ */
+ static public boolean getBooleanValue(Object obj) {
+ if ( obj == null )
+ return false;
+
+ if ( obj instanceof Boolean )
+ return ((Boolean)obj).booleanValue();
+
+ if ( obj instanceof Integer )
+ return (Integer)obj != 0;
+
+ if ( obj instanceof String ) {
+ try {
+ return Integer.valueOf((String)obj) != 0;
+ } catch (@SuppressWarnings("unused") NumberFormatException ign) {
+ // ignore
+ }
+ return Boolean.valueOf((String)obj);
+ }
+
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/sources/src/org/archicontribs/database/DBScript.java b/sources/src/org/archicontribs/database/DBScript.java
new file mode 100644
index 00000000..82da5535
--- /dev/null
+++ b/sources/src/org/archicontribs/database/DBScript.java
@@ -0,0 +1,151 @@
+package org.archicontribs.database;
+
+import java.util.List;
+
+import org.archicontribs.database.connection.DBDatabaseConnection;
+import org.archicontribs.database.connection.DBDatabaseImportConnection;
+import org.archicontribs.database.model.DBArchimateFactory;
+import org.archicontribs.database.model.DBArchimateModel;
+import org.archicontribs.database.model.DBMetadata;
+import org.eclipse.gef.commands.CommandStack;
+
+import com.archimatetool.editor.model.IArchiveManager;
+import com.archimatetool.editor.model.IEditorModelManager;
+import com.archimatetool.model.IArchimateModel;
+import com.archimatetool.model.IDiagramModel;
+
+/**
+ * This class is an API for the script plugin
+ *
+ * @author Herve Jouin
+ */
+public class DBScript {
+ private static final DBLogger logger = new DBLogger(DBDatabaseConnection.class);
+
+ /**
+ * Imports the latest version of a model
+ * @param modelName name of the model top import
+ * @param databaseName name of the database to import from, as stated in the list of databases on the plugin's preference page
+ * @param force if true, allow to have another model with the same name, else, the model's name must be unique in Archi
+ * @return the model
+ * @throws Exception if the model cannot be imported
+ */
+ public static IArchimateModel importModel(String modelName, String databaseName, boolean force) throws Exception {
+
+ // we get the databases list from the preferences
+ List databaseEntries = DBDatabaseEntry.getAllDatabasesFromPreferenceStore();
+ if ( (databaseEntries == null) || (databaseEntries.size() == 0) )
+ throw new RuntimeException("Cannot find any database.");
+
+ // we get the database by its name
+ DBDatabaseEntry databaseEntry = null;
+ for ( DBDatabaseEntry entry: databaseEntries ) {
+ if ( entry.getName().equals(databaseName) ) {
+ databaseEntry = entry;
+ break;
+ }
+
+ }
+
+ // we check that the database exists
+ if ( databaseEntry == null )
+ throw new RuntimeException("Cannot find database \""+databaseName+"\"");
+
+ // we connect to the database
+ try ( DBDatabaseImportConnection connection = new DBDatabaseImportConnection(databaseEntry) ) {
+ // we check if we are connected to the database
+ if ( !connection.isConnected() )
+ throw new RuntimeException("Cannot connect to the database \""+databaseName+"\"");
+
+ // we check if the model exists in the database
+ String modelId = connection.getModelId(modelName, false);
+
+ if ( modelId == null )
+ throw new RuntimeException("Cannot find model \""+ modelName +"\" in the database \""+databaseName+"\"");
+
+ // we check that the model is not already in memory
+ List allModels = IEditorModelManager.INSTANCE.getModels();
+ for ( IArchimateModel existingModel: allModels ) {
+ if ( DBPlugin.areEqual(modelId, existingModel.getId()) )
+ throw new RuntimeException("A model with ID \""+modelId+"\" is already opened.");
+ if ( DBPlugin.areEqual(modelName, existingModel.getName()) && !force )
+ throw new RuntimeException("A model with name \""+modelName+"\" is already opened.");
+ }
+
+ // we create the model
+ DBArchimateModel modelToImport = (DBArchimateModel)DBArchimateFactory.eINSTANCE.createArchimateModel();
+ modelToImport.setId(modelId);
+ modelToImport.setName(modelName);
+
+ // awe create the model's archive manager
+ modelToImport.setAdapter(IArchiveManager.class, IArchiveManager.FACTORY.createArchiveManager(modelToImport));
+
+ try {
+ // at last, we import the model
+ connection.importModel(modelToImport);
+
+ if ( logger.isDebugEnabled() ) logger.debug("Importing the folders ...");
+ connection.prepareImportFolders(modelToImport);
+ while ( connection.importFolders(modelToImport) ) {
+ // each loop imports a folder
+ }
+
+ if ( logger.isDebugEnabled() ) logger.debug("Importing the elements ...");
+ connection.prepareImportElements(modelToImport);
+ while ( connection.importElements(modelToImport) ) {
+ // each loop imports an element
+ }
+
+ if ( logger.isDebugEnabled() ) logger.debug("Importing the relationships ...");
+ connection.prepareImportRelationships(modelToImport);
+ while ( connection.importRelationships(modelToImport) ) {
+ // each loop imports a relationship
+ }
+
+ modelToImport.resolveSourceAndTargetRelationships();
+
+ if ( logger.isDebugEnabled() ) logger.debug("Importing the views ...");
+ connection.prepareImportViews(modelToImport);
+ while ( connection.importViews(modelToImport) ) {
+ // each loop imports a view
+ }
+
+ if ( logger.isDebugEnabled() ) logger.debug("Importing the views objects ...");
+ for (IDiagramModel view: modelToImport.getAllViews().values()) {
+ connection.prepareImportViewsObjects(view.getId(), DBMetadata.getDBMetadata(view).getInitialVersion().getVersion());
+ while ( connection.importViewsObjects(modelToImport, view) ) {
+ // each loop imports a view object
+ }
+ }
+
+ if ( logger.isDebugEnabled() ) logger.debug("Importing the views connections ...");
+ for (IDiagramModel view: modelToImport.getAllViews().values()) {
+ connection.prepareImportViewsConnections(view.getId(), DBMetadata.getDBMetadata(view).getInitialVersion().getVersion());
+ while ( connection.importViewsConnections(modelToImport) ) {
+ // each loop imports a view connection
+ }
+ }
+
+ modelToImport.resolveSourceAndTargetConnections();
+
+ if ( logger.isDebugEnabled() ) logger.debug("Importing the images ...");
+ for (String path: connection.getAllImagePaths())
+ connection.importImage(modelToImport, path);
+ } catch ( Exception e) {
+ // in case of an import error, we remove the newly created model, except if we are in force mode
+ if ( !force ) {
+ // we remove the 'dirty' flag (i.e. we consider the model as saved) because we do not want the closeModel() method ask to save it
+ CommandStack stack = (CommandStack)modelToImport.getAdapter(CommandStack.class);
+ if ( stack != null ) stack.markSaveLocation();
+
+ IEditorModelManager.INSTANCE.closeModel(modelToImport);
+ }
+ throw e;
+ }
+ // we add the new model in the manager
+ IEditorModelManager.INSTANCE.registerModel(modelToImport);
+
+ return modelToImport;
+ }
+ }
+}
diff --git a/sources/src/org/archicontribs/database/DBTable.java b/sources/src/org/archicontribs/database/DBTable.java
new file mode 100644
index 00000000..ac53712f
--- /dev/null
+++ b/sources/src/org/archicontribs/database/DBTable.java
@@ -0,0 +1,76 @@
+package org.archicontribs.database;
+
+import java.util.List;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.Setter;
+
+/**
+ *
+ * @author Herve
+ *
+ */
+@AllArgsConstructor()
+@Getter
+@Setter
+public class DBTable {
+ String schema;
+ @NonNull String name;
+ @NonNull List columns;
+ List primaryKeys;
+
+ /**
+ * @return
+ */
+ public String getFullName() {
+ StringBuilder fullName = new StringBuilder();
+ if ( !DBPlugin.isEmpty(this.schema) ) {
+ fullName.append(this.schema);
+ fullName.append(".");
+ }
+ fullName.append(this.name);
+
+ return fullName.toString();
+ }
+
+ /**
+ * @return
+ */
+ public String generateCreateStatement() {
+ StringBuilder tbls = new StringBuilder();
+ StringBuilder pkey = new StringBuilder();
+
+ for ( int i = 0 ; i < this.columns.size() ; ++i ) {
+ if ( tbls.length() != 0 )
+ tbls.append(", ");
+ DBColumn col = this.columns.get(i);
+ tbls.append(col.getName());
+ tbls.append(" ");
+ tbls.append(col.getFullType());
+ }
+
+ if ( this.primaryKeys != null ) {
+ for ( int i = 0 ; i < this.primaryKeys.size() ; ++i ) {
+ if ( pkey.length() == 0 )
+ pkey.append(", PRIMARY KEY (");
+ else
+ pkey.append(", ");
+ String colPK = this.primaryKeys.get(i);
+ pkey.append(colPK);
+ }
+ if ( pkey.length() != 0 )
+ pkey.append(")");
+ }
+
+ StringBuilder createRequest = new StringBuilder("CREATE TABLE ");
+ createRequest.append(getFullName());
+ createRequest.append(" (");
+ createRequest.append(tbls);
+ createRequest.append(pkey);
+ createRequest.append(")");
+
+ return createRequest.toString();
+ }
+}
diff --git a/sources/src/org/archicontribs/database/DropinsPluginHandler.java b/sources/src/org/archicontribs/database/DropinsPluginHandler.java
new file mode 100644
index 00000000..62bb5ccc
--- /dev/null
+++ b/sources/src/org/archicontribs/database/DropinsPluginHandler.java
@@ -0,0 +1,474 @@
+package org.archicontribs.database;
+
+/**
+ * This file is adapted from the com.archimatetool.editor.p2.DropinsPluginHandler @author Phillip Beauvoir
+ */
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.osgi.framework.Bundle;
+
+import com.archimatetool.editor.ArchiPlugin;
+import com.archimatetool.editor.Logger;
+import com.archimatetool.editor.utils.FileUtils;
+import com.archimatetool.editor.utils.PlatformUtils;
+import com.archimatetool.editor.utils.ZipUtils;
+
+/**
+ * @author Herve
+ *
+ */
+public class DropinsPluginHandler {
+
+ File userDropinsFolder, systemDropinsFolder, instanceDropinsFolder;
+
+ boolean success;
+ boolean needsClose;
+
+ static final int CONTINUE = 0;
+ static final int RESTART = 1;
+ static final int CLOSE = 2;
+
+ static final String MAGIC_ENTRY = "archi-plugin"; //$NON-NLS-1$
+
+ static final String DROPINS_DIRECTORY = "org.eclipse.equinox.p2.reconciler.dropins.directory"; //$NON-NLS-1$
+
+ /**
+ *
+ */
+ public DropinsPluginHandler() {
+ }
+
+ /**
+ * @return
+ * @throws IOException
+ */
+ public List getInstalledPlugins() throws IOException {
+ List list = new ArrayList();
+
+ for(Bundle bundle : ArchiPlugin.INSTANCE.getBundle().getBundleContext().getBundles()) {
+ File file = getDropinsBundleFile(bundle);
+ if(file != null) {
+ list.add(bundle);
+ }
+ }
+
+ return list;
+ }
+
+ /**
+ * @param shell
+ * @return
+ * @throws IOException
+ */
+ public int install(Shell shell) throws IOException {
+ if(!checkCanWriteToFolder(shell, getDefaultDropinsFolder())) {
+ return status();
+ }
+
+ List files = askOpenFiles(shell);
+ if(files.isEmpty()) {
+ return status();
+ }
+
+ List stats = new ArrayList();
+
+ Exception[] exception = new Exception[1];
+
+ BusyIndicator.showWhile(Display.getCurrent(), new Runnable() {
+ @Override
+ public void run() {
+ for(File file : files) {
+ try {
+ IStatus status = installFile(file);
+ stats.add(status);
+ }
+ catch(IOException ex) {
+ exception[0] = ex;
+ }
+ }
+ }
+ });
+
+ if(exception[0] != null) {
+ displayErrorDialog(shell, exception[0].getMessage());
+ return status();
+ }
+
+ String resultMessage = ""; //$NON-NLS-1$
+ boolean hasError = false;
+
+ for(int i = 0; i < stats.size(); i++) {
+ IStatus status = stats.get(i);
+
+ if(status.isOK()) {
+ this.success = true;
+ resultMessage += NLS.bind("{0} - Installed\n", files.get(i).getName()); //$NON-NLS-1$
+ }
+ else {
+ hasError = true;
+
+ if(status.getCode() == 666) {
+ resultMessage += NLS.bind("{0} - Is not an Archi plug-in.\n", files.get(i).getName()); //$NON-NLS-1$
+ }
+ else {
+ resultMessage += NLS.bind("{0} - Not installed.\n", files.get(i).getName()); //$NON-NLS-1$
+ }
+ }
+ }
+
+ if(hasError) {
+ MessageDialog.openInformation(shell, "Install status", resultMessage);
+ }
+
+ return status();
+ }
+
+ /**
+ * @param zipFile
+ * @return
+ * @throws IOException
+ */
+ public IStatus installFile(File zipFile) throws IOException {
+ if(!isPluginZipFile(zipFile)) {
+ return new Status(IStatus.ERROR, "com.archimatetool.editor", 666, //$NON-NLS-1$
+ NLS.bind("{0} is not a plug-in file", zipFile.getAbsolutePath()), null);
+ }
+
+ Path tmp = Files.createTempDirectory("archi"); //$NON-NLS-1$
+ File tmpFolder = tmp.toFile();
+
+ try {
+ ZipUtils.unpackZip(zipFile, tmpFolder);
+
+ File pluginsFolder = getDefaultDropinsFolder();
+ pluginsFolder.mkdirs();
+
+ for(File file : tmpFolder.listFiles()) {
+ // Ignore the magic entry file
+ if(MAGIC_ENTRY.equalsIgnoreCase(file.getName())) {
+ continue;
+ }
+
+ // Delete old plugin on exit in target plugins folder
+ deleteOlderPluginOnExit(file, pluginsFolder);
+
+ // Copy new ones
+ if(file.isDirectory()) {
+ FileUtils.copyFolder(file, new File(pluginsFolder, file.getName()));
+ }
+ else {
+ FileUtils.copyFile(file, new File(pluginsFolder, file.getName()), false);
+ }
+ }
+ }
+ finally {
+ FileUtils.deleteFolder(tmpFolder);
+ }
+
+ return new Status(IStatus.OK, "com.archimatetool.editor", 777, NLS.bind("{0} installed", zipFile.getPath()), null); //$NON-NLS-1$
+ }
+
+ /**
+ * @param shell
+ * @param selected
+ * @return
+ * @throws IOException
+ */
+ public int uninstall(Shell shell, List selected) throws IOException {
+ if(selected.isEmpty()) {
+ return status();
+ }
+
+ boolean ok = MessageDialog.openQuestion(shell,
+ "Uninstall Archi Plug-ins",
+ "Are you sure you want to uninstall these plug-ins?");
+
+ if(!ok) {
+ return status();
+ }
+
+ for(Bundle bundle : selected) {
+ File file = getDropinsBundleFile(bundle);
+ if(file != null) {
+ deleteOnExit(file);
+ }
+ else {
+ Logger.logError(NLS.bind("Could not create file location to uninstall plugin: {0}", bundle.getLocation()));
+ }
+ }
+
+ this.success = true;
+
+ return status();
+ }
+
+ int status() {
+ if(this.success && this.needsClose) {
+ return CLOSE;
+ }
+ if(this.success) {
+ return RESTART;
+ }
+
+ return CONTINUE;
+ }
+
+ // Delete matching older plugin
+ void deleteOlderPluginOnExit(File newPlugin, File pluginsFolder) throws IOException {
+ for(File file : findMatchingPlugins(pluginsFolder, newPlugin)) {
+ deleteOnExit(file);
+ }
+ }
+
+ static File[] findMatchingPlugins(File pluginsFolder, File newPlugin) {
+ String pluginName = getPluginName(newPlugin.getName());
+
+ return pluginsFolder.listFiles(new FileFilter() {
+ @Override
+ public boolean accept(File file) {
+ String targetPluginName = getPluginName(file.getName());
+ return targetPluginName.equals(pluginName) && !newPlugin.getName().equals(file.getName());
+ }
+ });
+ }
+
+ static String getPluginName(String string) {
+ String result;
+ int index = string.indexOf("_"); //$NON-NLS-1$
+ if(index == -1)
+ result = string;
+ else
+ result = string.substring(0, index);
+
+ return result;
+ }
+
+ static String getPluginVersion(String string) {
+ String result;
+ int index = string.lastIndexOf(".jar"); //$NON-NLS-1$
+ if(index == -1)
+ result = string;
+ else
+ result = string.substring(0, index);
+
+ index = string.lastIndexOf("_"); //$NON-NLS-1$
+ if(index != -1)
+ result = string.substring(index + 1);
+
+ return result;
+ }
+
+ static boolean checkCanWriteToFolder(Shell shell, File folder) {
+ folder.mkdirs();
+
+ if(!Files.isWritable(folder.toPath())) {
+ String message = "Archi does not have write access to the installation folder. "; //$NON-NLS-1$
+
+ if(PlatformUtils.isWindows()) {
+ message += "Please run Archi as Administrator and try again.";
+ }
+ else {
+ message += "Please quit and move the Archi app to a different location and try again.";
+ }
+
+ displayErrorDialog(shell, message);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ static boolean isPluginZipFile(File file) throws IOException {
+ return ZipUtils.isZipFile(file) && ZipUtils.hasZipEntry(file, MAGIC_ENTRY);
+ }
+
+ File getDefaultDropinsFolder() throws IOException {
+ // Get user dropins folder as set in Archi.ini
+ File dropinsFolder = getUserDropinsFolder();
+
+ // Else get the instance dropins folder as set in osgi.instance.area
+ if(dropinsFolder == null) {
+ dropinsFolder = getInstanceDropinsFolder();
+ }
+
+ // Else get the dropins folder as the "dropins" folder in the app installation directory
+ if(dropinsFolder == null) {
+ dropinsFolder = getSystemDropinsFolder();
+ }
+
+ return dropinsFolder;
+ }
+
+ File getUserDropinsFolder() {
+ if(this.userDropinsFolder == null) {
+ // If the dropins dir is set in Archi.ini
+ String dropinsDirProperty = ArchiPlugin.INSTANCE.getBundle().getBundleContext().getProperty(DROPINS_DIRECTORY);
+ if(dropinsDirProperty != null) {
+ // Perform a variable substitution if necessary of %% tokens
+ dropinsDirProperty = substituteVariables(dropinsDirProperty);
+ this.userDropinsFolder = new File(dropinsDirProperty);
+ }
+ }
+
+ return this.userDropinsFolder;
+ }
+
+ File getInstanceDropinsFolder() throws IOException {
+ if(this.instanceDropinsFolder == null) {
+ URL url = Platform.getInstanceLocation().getURL();
+ url = FileLocator.resolve(url);
+ this.instanceDropinsFolder = new File(url.getPath(), "dropins"); //$NON-NLS-1$
+ }
+
+ return this.instanceDropinsFolder;
+ }
+
+ File getSystemDropinsFolder() throws IOException {
+ if(this.systemDropinsFolder == null) {
+ URL url = Platform.getInstallLocation().getURL();
+ url = FileLocator.resolve(url);
+ this.systemDropinsFolder = new File(url.getPath(), "dropins"); //$NON-NLS-1$
+ }
+
+ return this.systemDropinsFolder;
+ }
+
+ /**
+ * This is taken From org.eclipse.equinox.internal.p2.reconciler.dropins.Activator
+ * When the dropins folder contains %% tokens, treat this as a system property.
+ * Example - %user.home%
+ * @param path
+ * @return
+ */
+ static String substituteVariables(String path) {
+ if(path == null) {
+ return path;
+ }
+
+ int beginIndex = path.indexOf('%');
+
+ // no variable
+ if(beginIndex == -1) {
+ return path;
+ }
+
+ beginIndex++;
+
+ int endIndex = path.indexOf('%', beginIndex);
+ // no matching end % to indicate variable
+ if(endIndex == -1) {
+ return path;
+ }
+
+ // get the variable name and do a lookup
+ String var = path.substring(beginIndex, endIndex);
+ if(var.length() == 0 || var.indexOf(File.pathSeparatorChar) != -1) {
+ return path;
+ }
+
+ var = ArchiPlugin.INSTANCE.getBundle().getBundleContext().getProperty(var);
+ if(var == null) {
+ return path;
+ }
+
+ return path.substring(0, beginIndex - 1) + var + path.substring(endIndex + 1);
+ }
+
+ /**
+ * If the bundle is in one of the "dropins" folders return its file (jar or folder), else return null
+ * @param bundle
+ * @return
+ * @throws IOException
+ */
+ File getDropinsBundleFile(Bundle bundle) throws IOException {
+ File bundleFile = FileLocator.getBundleFile(bundle);
+ File parentFolder = bundleFile.getParentFile();
+ return (parentFolder.equals(getUserDropinsFolder())
+ || parentFolder.equals(getInstanceDropinsFolder())
+ || parentFolder.equals(getSystemDropinsFolder())) ? bundleFile : null;
+ }
+
+ static List askOpenFiles(Shell shell) {
+ FileDialog dialog = new FileDialog(shell, SWT.OPEN | SWT.MULTI);
+ dialog.setFilterExtensions(new String[] { "*.archiplugin", "*.zip", "*.*" } ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ String path = dialog.open();
+
+ // TODO: Bug on Mac 10.12 and newer - Open dialog does not close straight away
+ // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=527306
+ if(path != null && PlatformUtils.isMac()) {
+ while(Display.getCurrent().readAndDispatch()) {
+ // nothing to do;
+ }
+ }
+
+ List files = new ArrayList();
+
+ if(path != null) {
+ for(String name : dialog.getFileNames()) {
+ String filterPath = dialog.getFilterPath();
+ filterPath += File.separator; // Issue on OpenJDK if path is like C: or D: - no slash is added when creating File
+ files.add(new File(filterPath, name));
+ }
+ }
+
+ return files;
+ }
+
+ void deleteOnExit(File file) throws IOException {
+ if(file.isDirectory()) {
+ recursiveDeleteOnExit(file.toPath());
+ }
+ else {
+ file.deleteOnExit();
+ }
+
+ // Mac won't delete files with File.deleteOnExit() if workbench is restarted
+ this.needsClose = PlatformUtils.isMac();
+ }
+
+ static void recursiveDeleteOnExit(Path path) throws IOException {
+ Files.walkFileTree(path, new SimpleFileVisitor() {
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+ file.toFile().deleteOnExit();
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
+ dir.toFile().deleteOnExit();
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ }
+
+ static void displayErrorDialog(Shell shell, String message) {
+ MessageDialog.openError(shell,
+ "Install Archi Plug-ins",
+ message);
+ }
+}
diff --git a/sources/src/org/archicontribs/database/GUI/DBGui.java b/sources/src/org/archicontribs/database/GUI/DBGui.java
new file mode 100644
index 00000000..50da7d03
--- /dev/null
+++ b/sources/src/org/archicontribs/database/GUI/DBGui.java
@@ -0,0 +1,1802 @@
+/**
+ * This program and the accompanying materials
+ * are made available under the terms of the License
+ * which accompanies this distribution in the file LICENSE.txt
+ */
+
+package org.archicontribs.database.GUI;
+
+import java.awt.HeadlessException;
+import java.awt.Toolkit;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.sql.SQLException;
+import java.text.Collator;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Priority;
+import org.archicontribs.database.DBDatabaseEntry;
+import org.archicontribs.database.DBLogger;
+import org.archicontribs.database.DBPlugin;
+import org.archicontribs.database.connection.DBDatabaseConnection;
+import org.archicontribs.database.connection.DBDatabaseImportConnection;
+import org.archicontribs.database.data.DBBendpoint;
+import org.archicontribs.database.data.DBDatabase;
+import org.archicontribs.database.data.DBProperty;
+import org.archicontribs.database.model.DBMetadata;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.preference.PreferenceDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.ImageLoader;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.layout.FormLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.ProgressBar;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.PreferencesUtil;
+
+import com.archimatetool.canvas.model.INotesContent;
+import com.archimatetool.editor.diagram.util.DiagramUtils;
+import com.archimatetool.editor.diagram.util.ModelReferencedImage;
+import com.archimatetool.editor.ui.ImageFactory;
+import com.archimatetool.model.FolderType;
+import com.archimatetool.model.IAccessRelationship;
+import com.archimatetool.model.IArchimateDiagramModel;
+import com.archimatetool.model.IArchimateRelationship;
+import com.archimatetool.model.IBorderObject;
+import com.archimatetool.model.IBounds;
+import com.archimatetool.model.IConnectable;
+import com.archimatetool.model.IDiagramModel;
+import com.archimatetool.model.IDiagramModelArchimateComponent;
+import com.archimatetool.model.IDiagramModelArchimateConnection;
+import com.archimatetool.model.IDiagramModelArchimateObject;
+import com.archimatetool.model.IDiagramModelConnection;
+import com.archimatetool.model.IDiagramModelImageProvider;
+import com.archimatetool.model.IDiagramModelNote;
+import com.archimatetool.model.IDiagramModelObject;
+import com.archimatetool.model.IDocumentable;
+import com.archimatetool.model.IFolder;
+import com.archimatetool.model.IFontAttribute;
+import com.archimatetool.model.IInfluenceRelationship;
+import com.archimatetool.model.IJunction;
+import com.archimatetool.model.ILineObject;
+import com.archimatetool.model.ILockable;
+import com.archimatetool.model.INameable;
+import com.archimatetool.model.IProperties;
+import com.archimatetool.model.ISketchModel;
+import com.archimatetool.model.ITextAlignment;
+import com.archimatetool.model.ITextContent;
+import com.archimatetool.model.ITextPosition;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * This class manages the GUI of the plugin.
+ *
+ * @author Herve Jouin
+ */
+public class DBGui {
+ protected static final DBLogger logger = new DBLogger(DBGui.class);
+
+ @Getter @Setter private boolean closedByUser = false;
+
+ protected List databaseEntries;
+ protected List comboDatabaseEntries;
+ protected DBDatabaseEntry selectedDatabase;
+ DBDatabaseImportConnection connection;
+
+ protected static final Display display = Display.getCurrent() == null ? Display.getDefault() : Display.getCurrent();
+ protected Shell dialog;
+ protected Shell parentDialog;
+
+ protected boolean includeNeo4j = true;
+
+ String HELP_HREF = null;
+ boolean mouseOverHelpButton = false;
+
+ protected enum ACTION {One, Two, Three, Four}
+ protected enum STATUS {Empty, Selected, Running, Bypassed, Ok, Warn, Error}
+
+ public static final Color LIGHT_GREEN_COLOR = new Color(display, 204, 255, 229);
+ public static final Color LIGHT_RED_COLOR = new Color(display, 255, 230, 230);
+ public static final Color RED_COLOR = new Color(display, 240, 0, 0);
+ public static final Color GREEN_COLOR = new Color(display, 0, 180, 0);
+ public static final Color WHITE_COLOR = new Color(display, 255, 255, 255);
+ public static final Color GREY_COLOR = new Color(display, 100, 100, 100);
+ public static final Color BLACK_COLOR = new Color(display, 0, 0, 0);
+ public static final Color YELLOW_COLOR = new Color(display, 255, 255, 0);
+
+ public static final Color COMPO_LEFT_COLOR = new Color(display, 240, 248, 255); // light blue
+ public static final Color COMPO_BACKGROUND_COLOR = new Color(display, 250, 250, 250); // light grey
+ public static final Color GROUP_BACKGROUND_COLOR = new Color(display, 235, 235, 235); // light grey (a bit darker than compo background)
+ public static final Color TABLE_BACKGROUND_COLOR = new Color(display, 225, 225, 225); // light grey (a bit darker than group background)
+ public static final Color HIGHLIGHTED_COLOR = display.getSystemColor(SWT.COLOR_GRAY);
+
+ public static final Color STRATEGY_COLOR = new Color(display, 255, 222, 170);
+ public static final Color BUSINESS_COLOR = new Color(display, 255, 255, 181);
+ public static final Color APPLICATION_COLOR = new Color(display, 181, 255, 255);
+ public static final Color TECHNOLOGY_COLOR = new Color(display, 201, 231, 183);
+ public static final Color PHYSICAL_COLOR = new Color(display, 201, 231, 183);
+ public static final Color IMPLEMENTATION_COLOR = new Color(display, 255, 224, 224);
+ public static final Color MOTIVATION_COLOR = new Color(display, 204, 204, 255);
+
+ public static final Color PASSIVE_COLOR = new Color(display, 250, 250, 250);
+
+ public static final Cursor CURSOR_WAIT = new Cursor(null, SWT.CURSOR_WAIT);
+ public static final Cursor CURSOR_ARROW = new Cursor(null, SWT.CURSOR_ARROW);
+
+ public static final FontData SYSTEM_FONT = display.getSystemFont().getFontData()[0];
+ public static final Font GROUP_TITLE_FONT = new Font(display, SYSTEM_FONT.getName(), SYSTEM_FONT.getHeight()+2, SWT.BOLD | SWT.ITALIC);
+ public static final Font TITLE_FONT = new Font(display, SYSTEM_FONT.getName(), SYSTEM_FONT.getHeight()+2, SWT.BOLD);
+ public static final Font BOLD_FONT = new Font(display, SYSTEM_FONT.getName(), SYSTEM_FONT.getHeight(), SWT.BOLD);
+
+ public static final Image LOGO_IMAGE = new Image(display, DBGui.class.getResourceAsStream("/img/logo.png"));
+ public static final Image EXPORT_TO_DATABASE_IMAGE = new Image(display, DBGui.class.getResourceAsStream("/img/22x22/export.png"));
+ public static final Image IMPORT_FROM_DATABASE_IMAGE = new Image(display, DBGui.class.getResourceAsStream("/img/22x22/import.png"));
+
+ public static final Image BYPASSED_ICON = new Image(display, DBGui.class.getResourceAsStream("/img/10x10/bypassed.png"));
+ public static final Image CLOCK_ICON = new Image(display, DBGui.class.getResourceAsStream("/img/10x10/clock.png"));
+ public static final Image ERROR_ICON = new Image(display, DBGui.class.getResourceAsStream("/img/10x10/error.png"));
+ public static final Image WARNING_ICON = new Image(display, DBGui.class.getResourceAsStream("/img/10x10/warning.png"));
+ public static final Image OK_ICON = new Image(display, DBGui.class.getResourceAsStream("/img/10x10/ok.png"));
+ public static final Image RIGHT_ARROW_ICON = new Image(display, DBGui.class.getResourceAsStream("/img/10x10/right_arrow.png"));
+
+ public static final Image LOCK_ICON = new Image(display, DBGui.class.getResourceAsStream("/img/10x10/lock.png"));
+ public static final Image UNLOCK_ICON = new Image(display, DBGui.class.getResourceAsStream("/img/10x10/unlock.png"));
+
+ public static final Image HELP_ICON = new Image(display, DBGui.class.getResourceAsStream("/img/28x28/help.png"));
+
+ private Composite compoLeft;
+ protected Composite compoRight;
+ protected Composite compoRightTop;
+ protected Composite compoRightBottom;
+ private Composite compoBottom;
+
+ private Label imgFirstAction;
+ private Label imgSecondAction;
+ private Label imgThirdAction;
+ private Label imgFourthAction;
+
+ private Label lblFirstAction;
+ private Label lblSecondAction;
+ private Label lblThirdAction;
+ private Label lblFourthAction;
+
+ private Label lblOption;
+ Button radioOption1;
+ Button radioOption2;
+ Button radioOption3;
+
+ @Getter protected Combo comboDatabases;
+ protected Button btnSetPreferences;
+ protected Button btnClose;
+ protected Button btnDoAction;
+ protected Label btnHelp;
+
+ private Group grpDatabase;
+
+ protected Group grpProgressBar = null;
+ protected Label lblProgressBar;
+ private ProgressBar progressBar;
+
+ protected Group grpMessage = null;
+ private CLabel lblMessage;
+
+ /** Default height of a Label widget */
+ @Getter private int defaultLabelHeight;
+
+ /** Default margin between widgets */
+ @Getter private int defaultMargin = 10;
+
+
+ /**
+ * Create the dialog with minimal graphical objects:
+ * left composite: picture of a database with Archimate diagram inside, the plugin version, (my name of course) and 4 icons + texts to list actions
+ * bottom composite: Close, doAction button at the right and help buton on the left
+ * right composite: database list in a combo and a button to set preferences
+ */
+ protected DBGui(String title) {
+ if ( logger.isDebugEnabled() ) logger.debug("Creating Form GUI.");
+
+ setArrowCursor();
+
+ this.parentDialog = display.getActiveShell();
+ this.dialog = new Shell(display, SWT.BORDER | SWT.TITLE | SWT.APPLICATION_MODAL | SWT.RESIZE);
+ this.dialog.setText(DBPlugin.pluginTitle + " - " + title);
+ this.dialog.setMinimumSize(800, 700);
+ this.dialog.setSize(1024, 700);
+
+ int scaleFactor = 1;
+ try {
+ if ( (Toolkit.getDefaultToolkit().getScreenResolution() != 0) && (this.dialog.getDisplay().getDPI() != null) && (this.dialog.getDisplay().getDPI().x != 0) )
+ scaleFactor = Toolkit.getDefaultToolkit().getScreenResolution() / this.dialog.getDisplay().getDPI().x;
+ } catch ( @SuppressWarnings("unused") HeadlessException ign) {
+ // nothing to do
+ }
+ if ( scaleFactor == 0 )
+ scaleFactor = 1; // just in case
+
+ // Use the active shell, if available, to determine the new shell placing
+ int locationX = 0;
+ int locationY = 0;
+ Rectangle shellSize = this.dialog.getBounds();
+ if (this.parentDialog!=null) {
+ Rectangle parentSize = this.parentDialog.getBounds();
+ locationX = (parentSize.width - shellSize.width)/2+parentSize.x;
+ locationY = (parentSize.height - shellSize.height)/2+parentSize.y;
+ } else {
+ locationX = ((Toolkit.getDefaultToolkit().getScreenSize().width / scaleFactor) - this.dialog.getSize().x) / 2;
+ //locationX = (Toolkit.getDefaultToolkit().getScreenSize().width - this.dialog.getSize().x) / 2;
+ locationY = ((Toolkit.getDefaultToolkit().getScreenSize().height / scaleFactor) - this.dialog.getSize().y) / 2;
+ //locationY = (Toolkit.getDefaultToolkit().getScreenSize().height - this.dialog.getSize().y) / 2;
+ }
+ this.dialog.setLocation(new Point(locationX, locationY));
+
+ this.dialog.setLayout(new FormLayout());
+
+ /**
+ * Calculate the default height of a Label widget
+ */
+ Label label = new Label(this.dialog, SWT.NONE);
+ label.setText("Test");
+ this.defaultLabelHeight = label.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
+ label.dispose();
+
+ this.dialog.addListener(SWT.Close, new Listener()
+ {
+ @Override
+ public void handleEvent(Event event)
+ {
+ boolean doIt = true;
+ if ( DBGui.this.btnClose.getText().equals("Cancel") ) {
+ doIt = question("Are you sure you wish to cancel ?");
+ }
+
+ if ( doIt ) {
+ setClosedByUser(true);
+ try {
+ rollbackAndCloseConnection();
+ } catch (SQLException e) {
+ popup(Level.ERROR, "Failed to rollback and close the database connection.", e);
+ }
+ close();
+ event.doit = true;
+ }
+ }
+ });
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////// compoLeft ////////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ this.compoLeft = new Composite(this.dialog, SWT.BORDER);
+ this.compoLeft.setBackground(COMPO_LEFT_COLOR);
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(0, 160);
+ fd.bottom = new FormAttachment(100, -40);
+ this.compoLeft.setLayoutData(fd);
+ this.compoLeft.setLayout(new FormLayout());
+
+ Composite compoTitle = new Composite(this.compoLeft, SWT.BORDER);
+ compoTitle.setBackground(COMPO_LEFT_COLOR);
+ fd = new FormData(140,50);
+ fd.top = new FormAttachment(0, 40);
+ fd.left = new FormAttachment(5);
+ fd.right = new FormAttachment(100, -5);
+ compoTitle.setLayoutData(fd);
+ compoTitle.setLayout(new FormLayout());
+
+ Label lblTitle = new Label(compoTitle, SWT.CENTER);
+ lblTitle.setBackground(COMPO_LEFT_COLOR);
+ lblTitle.setText("Archi database plugin");
+ lblTitle.setFont(TITLE_FONT);
+ fd = new FormData();
+ fd.top = new FormAttachment(10);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ lblTitle.setLayoutData(fd);
+
+ Label lblPluginVersion = new Label(compoTitle, SWT.CENTER);
+ lblPluginVersion.setBackground(COMPO_LEFT_COLOR);
+ lblPluginVersion.setText(DBPlugin.pluginVersion.toString());
+ fd = new FormData();
+ fd.top = new FormAttachment(lblTitle, 5);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ lblPluginVersion.setLayoutData(fd);
+
+ Label imgDatabase = new Label(this.compoLeft, SWT.CENTER);
+ imgDatabase.setBackground(COMPO_LEFT_COLOR);
+ imgDatabase.setImage(LOGO_IMAGE);
+ fd = new FormData(135,115);
+ fd.top = new FormAttachment(compoTitle, 30);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ imgDatabase.setLayoutData(fd);
+
+ this.imgFirstAction = new Label(this.compoLeft, SWT.CENTER);
+ this.imgFirstAction.setBackground(COMPO_LEFT_COLOR);
+ fd = new FormData(10,10);
+ fd.top = new FormAttachment(imgDatabase, 50);
+ fd.left = new FormAttachment(0, 10);
+ this.imgFirstAction.setLayoutData(fd);
+
+ this.lblFirstAction = new Label(this.compoLeft, SWT.NONE);
+ this.lblFirstAction.setBackground(COMPO_LEFT_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.imgFirstAction, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.imgFirstAction, 10);
+ fd.right = new FormAttachment(100, -10);
+ this.lblFirstAction.setLayoutData(fd);
+
+ this.imgSecondAction = new Label(this.compoLeft, SWT.CENTER);
+ this.imgSecondAction.setBackground(COMPO_LEFT_COLOR);
+ fd = new FormData(10,10);
+ fd.top = new FormAttachment(this.imgFirstAction, 10);
+ fd.left = new FormAttachment(0, 10);
+ this.imgSecondAction.setLayoutData(fd);
+
+ this.lblSecondAction = new Label(this.compoLeft, SWT.NONE);
+ this.lblSecondAction.setBackground(COMPO_LEFT_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.imgSecondAction, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.imgSecondAction, 10);
+ fd.right = new FormAttachment(100, -10);
+ this.lblSecondAction.setLayoutData(fd);
+
+ this.imgThirdAction = new Label(this.compoLeft, SWT.CENTER);
+ this.imgThirdAction.setBackground(COMPO_LEFT_COLOR);
+ fd = new FormData(10,10);
+ fd.top = new FormAttachment(this.imgSecondAction, 10);
+ fd.left = new FormAttachment(0, 10);
+ this.imgThirdAction.setLayoutData(fd);
+
+ this.lblThirdAction = new Label(this.compoLeft, SWT.NONE);
+ this.lblThirdAction.setBackground(COMPO_LEFT_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.imgThirdAction, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.imgThirdAction, 10);
+ fd.right = new FormAttachment(100, -10);
+ this.lblThirdAction.setLayoutData(fd);
+
+ this.imgFourthAction = new Label(this.compoLeft, SWT.CENTER);
+ this.imgFourthAction.setBackground(COMPO_LEFT_COLOR);
+ fd = new FormData(10,10);
+ fd.top = new FormAttachment(this.imgThirdAction, 10);
+ fd.left = new FormAttachment(0, 10);
+ this.imgFourthAction.setLayoutData(fd);
+
+ this.lblFourthAction = new Label(this.compoLeft, SWT.NONE);
+ this.lblFourthAction.setBackground(COMPO_LEFT_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.imgFourthAction, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.imgFourthAction, 10);
+ fd.right = new FormAttachment(100, -10);
+ this.lblFourthAction.setLayoutData(fd);
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////// compoRight ///////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ this.compoRight = new Composite(this.dialog, SWT.BORDER);
+ this.compoRight.setBackground(COMPO_BACKGROUND_COLOR);
+ FormData fd_compoRight = new FormData();
+ fd_compoRight.top = new FormAttachment(0);
+ fd_compoRight.bottom = new FormAttachment(100, -40);
+ fd_compoRight.left = new FormAttachment(this.compoLeft);
+ fd_compoRight.right = new FormAttachment(100);
+ this.compoRight.setLayoutData(fd_compoRight);
+ this.compoRight.setLayout(new FormLayout());
+
+ this.compoRightTop = new Composite(this.compoRight, SWT.NONE);
+ this.compoRightTop.setBackground(COMPO_BACKGROUND_COLOR);
+ FormData fd_compoRightUp = new FormData();
+ fd_compoRightUp.top = new FormAttachment(0, 10);
+ fd_compoRightUp.bottom = new FormAttachment(0, 70);
+ fd_compoRightUp.left = new FormAttachment(0, 10);
+ fd_compoRightUp.right = new FormAttachment(100, -10);
+ this.compoRightTop.setLayoutData(fd_compoRightUp);
+ this.compoRightTop.setLayout(new FormLayout());
+
+ this.compoRightBottom = new Composite(this.compoRight, SWT.NONE);
+ this.compoRightBottom.setBackground(COMPO_BACKGROUND_COLOR);
+ FormData fd_compoRightBottom = new FormData();
+ fd_compoRightBottom.top = new FormAttachment(this.compoRightTop, 10);
+ fd_compoRightBottom.bottom = new FormAttachment(100, -10);
+ fd_compoRightBottom.left = new FormAttachment(0, 10);
+ fd_compoRightBottom.right = new FormAttachment(100, -10);
+ this.compoRightBottom.setLayoutData(fd_compoRightBottom);
+ this.compoRightBottom.setLayout(new FormLayout());
+
+ this.grpDatabase = new Group(this.compoRightTop, SWT.SHADOW_ETCHED_IN);
+ this.grpDatabase.setVisible(true);
+ this.grpDatabase.setData("visible", true);
+ this.grpDatabase.setBackground(GROUP_BACKGROUND_COLOR);
+ this.grpDatabase.setFont(GROUP_TITLE_FONT);
+ this.grpDatabase.setText("Database: ");
+ fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ fd.bottom = new FormAttachment(100);
+ this.grpDatabase.setLayoutData(fd);
+ this.grpDatabase.setLayout(new FormLayout());
+
+ Label lblRegisteredDatabases = new Label(this.grpDatabase, SWT.NONE);
+ lblRegisteredDatabases.setBackground(GROUP_BACKGROUND_COLOR);
+ lblRegisteredDatabases.setText("Registered databases:");
+ fd = new FormData();
+ fd.top = new FormAttachment(25);
+ fd.left = new FormAttachment(0, 10);
+ lblRegisteredDatabases.setLayoutData(fd);
+
+ this.btnSetPreferences = new Button(this.grpDatabase, SWT.NONE);
+ this.btnSetPreferences.setText("Set preferences ...");
+ this.btnSetPreferences.addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent event) { try { setPreferences(); } catch (Exception e) { popup(Level.ERROR, "Failed to set preferences", e); } }
+ @Override
+ public void widgetDefaultSelected(SelectionEvent event) { widgetSelected(event); }
+ });
+ fd = new FormData();
+ fd.top = new FormAttachment(lblRegisteredDatabases, 0, SWT.CENTER);
+ fd.right = new FormAttachment(100, -10);
+ this.btnSetPreferences.setLayoutData(fd);
+
+ this.comboDatabases = new Combo(this.grpDatabase, SWT.NONE | SWT.READ_ONLY);
+ this.comboDatabases.setBackground(GROUP_BACKGROUND_COLOR);
+ this.comboDatabases.addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent event) { databaseSelected(); }
+ @Override
+ public void widgetDefaultSelected(SelectionEvent event) { widgetSelected(event); }
+ });
+ fd = new FormData();
+ fd.top = new FormAttachment(lblRegisteredDatabases, 0, SWT.CENTER);
+ fd.left = new FormAttachment(lblRegisteredDatabases, 10);
+ fd.right = new FormAttachment(this.btnSetPreferences, -40);
+ this.comboDatabases.setLayoutData(fd);
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////// compoBottom //////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ this.compoBottom = new Composite(this.dialog, SWT.NONE);
+ this.compoBottom.setBackground(COMPO_BACKGROUND_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(100, -40);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ fd.bottom = new FormAttachment(100);
+ this.compoBottom.setLayoutData(fd);
+ this.compoBottom.setLayout(new FormLayout());
+
+ this.btnHelp = new Label(this.compoBottom, SWT.NONE);
+ this.btnHelp.setVisible(false);
+ this.btnHelp.addListener(SWT.MouseEnter, new Listener() { @Override public void handleEvent(Event event) { DBGui.this.mouseOverHelpButton = true; DBGui.this.btnHelp.redraw(); } });
+ this.btnHelp.addListener(SWT.MouseExit, new Listener() { @Override public void handleEvent(Event event) { DBGui.this.mouseOverHelpButton = false; DBGui.this.btnHelp.redraw(); } });
+ this.btnHelp.addPaintListener(new PaintListener() {
+ @Override
+ public void paintControl(PaintEvent event)
+ {
+ if ( DBGui.this.mouseOverHelpButton ) event.gc.drawRoundRectangle(0, 0, 29, 29, 10, 10);
+ event.gc.drawImage(HELP_ICON, 2, 2);
+ }
+ });
+ this.btnHelp.addListener(SWT.MouseUp, new Listener() { @Override public void handleEvent(Event event) { if ( DBGui.this.HELP_HREF != null ) { if ( logger.isDebugEnabled() ) logger.debug("Showing help: /"+DBPlugin.PLUGIN_ID+"/help/html/"+DBGui.this.HELP_HREF); PlatformUI.getWorkbench().getHelpSystem().displayHelpResource("/"+DBPlugin.PLUGIN_ID+"/help/html/"+DBGui.this.HELP_HREF); } } });
+ fd = new FormData(30,30);
+ fd.top = new FormAttachment(0, 5);
+ fd.left = new FormAttachment(0, 5);
+ this.btnHelp.setLayoutData(fd);
+
+
+ this.btnClose = new Button(this.compoBottom, SWT.NONE);
+ this.btnClose.setText("Close");
+ this.btnClose.addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent event) {
+ boolean doIt = true;
+ if ( DBGui.this.btnClose.getText().equals("Cancel") ) {
+ doIt = question("Are you sure you wish to cancel ?");
+ }
+
+ if ( doIt ) {
+ setClosedByUser(true);
+ try {
+ rollbackAndCloseConnection();
+ } catch (SQLException e) {
+ popup(Level.ERROR, "Failed to rollback and close the database connection.", e);
+ }
+ close();
+ event.doit = true;
+ }
+ }
+ @Override
+ public void widgetDefaultSelected(SelectionEvent event) { widgetSelected(event); }
+ });
+ fd = new FormData(100,25);
+ fd.top = new FormAttachment(0, 8);
+ fd.right = new FormAttachment(100, -10);
+ this.btnClose.setLayoutData(fd);
+
+ this.btnDoAction = new Button(this.compoBottom, SWT.NONE);
+ this.btnDoAction.setEnabled(false);
+ this.btnDoAction.setVisible(false);
+ fd = new FormData(100,25);
+ fd.top = new FormAttachment(0, 8);
+ fd.right = new FormAttachment(this.btnClose, -10);
+ this.btnDoAction.setLayoutData(fd);
+
+ this.radioOption3 = new Button(this.compoBottom, SWT.RADIO);
+ this.radioOption3.setBackground(COMPO_BACKGROUND_COLOR);
+ this.radioOption3.setVisible(false);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.btnDoAction, 0, SWT.CENTER);
+ fd.right = new FormAttachment(this.btnDoAction, -20);
+ this.radioOption3.setLayoutData(fd);
+
+ this.radioOption2 = new Button(this.compoBottom, SWT.RADIO);
+ this.radioOption2.setBackground(COMPO_BACKGROUND_COLOR);
+ this.radioOption2.setVisible(false);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.btnDoAction, 0, SWT.CENTER);
+ fd.right = new FormAttachment(this.radioOption3, -10);
+ this.radioOption2.setLayoutData(fd);
+
+ this.radioOption1 = new Button(this.compoBottom, SWT.RADIO);
+ this.radioOption1.setBackground(COMPO_BACKGROUND_COLOR);
+ this.radioOption1.setVisible(false);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.btnDoAction, 0, SWT.CENTER);
+ fd.right = new FormAttachment(this.radioOption2, -10);
+ this.radioOption1.setLayoutData(fd);
+
+ this.lblOption = new Label(this.compoBottom, SWT.NONE);
+ this.lblOption.setBackground(COMPO_BACKGROUND_COLOR);
+ this.lblOption.setVisible(false);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.btnDoAction, 0, SWT.CENTER);
+ fd.right = new FormAttachment(this.radioOption1, -10);
+ this.lblOption.setLayoutData(fd);
+ }
+
+ public void run() {
+ this.dialog.open();
+ this.dialog.layout();
+ refreshDisplay();
+ }
+
+ /**
+ * Gets the list of configured databases, fill-in the comboDatabases and select the database provided
+ * @param mustIncludeNeo4j if true, include the Neo4J databases in the list, if false, do not include them in the list
+ * @param defaultDatabaseId Indicated the ID of the default database (the first database will be selected, if the database is not found or if null)
+ * @param defaultDatabaseName Indicated the name of the default database (the first database will be selected, if the database is not found or if null) - if both ID and name are provided, the ID has got higher priority
+ * @throws Exception
+ */
+ protected void getDatabases(boolean mustIncludeNeo4j, String defaultDatabaseId, String defaultDatabaseName) throws Exception {
+ refreshDisplay();
+
+ this.databaseEntries = DBDatabaseEntry.getAllDatabasesFromPreferenceStore();
+ this.comboDatabaseEntries = new ArrayList();
+ if ( (this.databaseEntries == null) || (this.databaseEntries.size() == 0) ) {
+ popup(Level.ERROR, "You haven't configure any database yet.\n\nPlease setup at least one database in Archi preferences.");
+ } else {
+ int databaseToSelect = -1;
+ int line = 0;
+ for (DBDatabaseEntry databaseEntry: this.databaseEntries) {
+ if ( mustIncludeNeo4j || !databaseEntry.getDriver().equals(DBDatabase.NEO4J.getDriverName()) ) {
+ this.comboDatabases.add(databaseEntry.getName());
+ this.comboDatabaseEntries.add(databaseEntry);
+ if ( defaultDatabaseId != null && databaseEntry.getId().equals(defaultDatabaseId) )
+ databaseToSelect = line;
+ if ( defaultDatabaseName != null && databaseToSelect != 0 && databaseEntry.getName().equals(defaultDatabaseName) )
+ databaseToSelect = line;
+ ++line;
+ }
+ }
+ if ( line == 0 )
+ popup(Level.ERROR, "You haven't configure any SQL database yet.\n\nPlease setup at least one SQL database in Archi preferences.");
+ else {
+ // if no default database is provided, then we select the first database in the combo
+ if ( defaultDatabaseId == null && defaultDatabaseName == null )
+ databaseToSelect = 0;
+ if ( databaseToSelect != -1 ) {
+ this.comboDatabases.select(databaseToSelect);
+ this.comboDatabases.notifyListeners(SWT.Selection, new Event()); // calls the databaseSelected() method
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the list of configured databases, fill-in the comboDatabases and select the first-one
+ * @param mustIncludeNeo4j if true, include the Neo4J databases in the list, if false, do not include them in the list
+ * @throws Exception
+ */
+ protected void getDatabases(boolean mustIncludeNeo4j) throws Exception {
+ getDatabases(mustIncludeNeo4j, null, null);
+ }
+
+ /**
+ * Called when the user clicks on the "set preferences" button
+ * This method opens up the database plugin preference page that the user can configure database details.
+ * @throws Exception
+ */
+ protected void setPreferences() throws Exception {
+ if ( logger.isDebugEnabled() ) logger.debug("Openning preference page ...");
+ PreferenceDialog prefDialog = PreferencesUtil.createPreferenceDialogOn(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), "org.archicontribs.database.DBPreferencePage", null, null);
+ prefDialog.setBlockOnOpen(true);
+ if ( prefDialog.open() == 0 ) {
+ if ( logger.isDebugEnabled() ) logger.debug("Resetting settings from preferences ...");
+
+ this.comboDatabases.removeAll();
+
+ this.databaseEntries = DBDatabaseEntry.getAllDatabasesFromPreferenceStore();
+ if ( (this.databaseEntries == null) || (this.databaseEntries.size() == 0) ) {
+ this.comboDatabases.select(0);
+ popup(Level.ERROR, "You haven't configure any database yet.\n\nPlease setup at least one database in Archi preferences.");
+ } else {
+ int line = 0;
+ for (DBDatabaseEntry databaseEntry: this.databaseEntries) {
+ if ( this.includeNeo4j || !databaseEntry.getDriver().equals(DBDatabase.NEO4J.getDriverName()) ) {
+ this.comboDatabases.add(databaseEntry.getName());
+ this.comboDatabaseEntries.add(databaseEntry);
+ ++line;
+ }
+ }
+ if ( line == 0 )
+ popup(Level.ERROR, "You haven't configure any SQL database yet.\n\nPlease setup at least one SQL database in Archi preferences.");
+ else {
+ this.comboDatabases.select(0);
+ this.comboDatabases.notifyListeners(SWT.Selection, new Event());
+ }
+ }
+ } else {
+ if ( logger.isDebugEnabled() ) logger.debug("Preferences cancelled ...");
+ if ( this.comboDatabases.getItemCount() == 0 )
+ popup(Level.ERROR, "You won't be able to export until a database is configured in the preferences.");
+ }
+ this.comboDatabases.setFocus();
+ }
+
+ /**
+ * Listener called when a database is selected in the comboDatabases
+ * This method retrieve the database name from the comboDatabases and reads the preferences to get the connection details. A connection is then established to the database.
+ */
+ protected void databaseSelected() {
+ setMessage("Connecting to the database ...");
+ refreshDisplay();
+
+ databaseSelectedCleanup();
+
+ this.btnDoAction.setEnabled(false);
+
+ // we get the databaseEntry corresponding to the selected combo entry
+ this.selectedDatabase = this.comboDatabaseEntries.get(this.comboDatabases.getSelectionIndex());
+ if ( logger.isDebugEnabled() ) logger.debug("Selected database = " + this.selectedDatabase.getName()+" ("+this.selectedDatabase.getDriver()+", "+this.selectedDatabase.getServer()+", "+this.selectedDatabase.getPort()+", "+this.selectedDatabase.getDatabase()+", "+this.selectedDatabase.getUsername());
+
+ // then we connect to the database.
+ try {
+ this.connection = new DBDatabaseImportConnection(this.selectedDatabase);
+ //if the database connection failed, then an exception is raised, meaning that we get here only if the database connection succeeded
+ if ( logger.isDebugEnabled() ) logger.debug(DBGui.class, "We are connected to the database.");
+ } catch (Exception err) {
+ closeMessage();
+ notConnectedToDatabase();
+ popup(Level.ERROR, "Cannot connect to the database.", err);
+ return;
+ }
+
+ // then, we check if the database has got the right pre-requisites
+ try {
+ this.connection.checkDatabase(null);
+ } catch (Exception err) {
+ closeMessage();
+ popup(Level.ERROR, "Cannot use this database.", err);
+ notConnectedToDatabase();
+ return;
+ } finally {
+ closeMessage();
+ }
+
+ connectedToDatabase(true);
+ }
+
+ /**
+ * This method is called by the databaseSelected method. It allows to do some actions when a new database is selected.
+ */
+ protected void databaseSelectedCleanup() {
+ //to be overridden
+ }
+
+ /**
+ * This method is called by the databaseSelected method. It allows to do some actions when the connection to a new database is successful.
+ * @param forceCheckDatabase true when the database should be checked.
+ */
+ protected void connectedToDatabase(boolean forceCheckDatabase) {
+ // to be overridden
+ enableOption();
+ this.btnDoAction.setEnabled(true);
+ }
+
+ /**
+ * This method is called by the databaseSelected method. It allows to do some actions when the connection to a new database is failed.
+ */
+ protected void notConnectedToDatabase() {
+ // to be overridden
+ disableOption();
+ this.btnDoAction.setEnabled(false);
+ }
+
+ /**
+ * Sets the reference of the online help
+ */
+ protected void setHelpHref(String href) {
+ this.HELP_HREF = href;
+ this.btnHelp.setVisible(this.HELP_HREF != null);
+ }
+
+ private ACTION activeAction = null;
+ /**
+ * Activate an action (on the left handside panel)
+ * @param action Reference of the action
+ * @param status status of the action
+ */
+ protected void setActiveAction(ACTION action, STATUS status) {
+ Image icon;
+ switch ( status ) {
+ case Selected: icon = RIGHT_ARROW_ICON; break;
+ case Running: icon = CLOCK_ICON; break;
+ case Bypassed: icon = BYPASSED_ICON; break;
+ case Ok: icon = OK_ICON; break;
+ case Warn: icon = WARNING_ICON; break;
+ case Error: icon = ERROR_ICON; break;
+ case Empty: icon = null; break;
+ default: icon = null;
+ }
+ switch ( action ) {
+ case One: this.activeAction = ACTION.One; this.imgFirstAction.setImage(icon); break;
+ case Two: this.activeAction = ACTION.Two; this.imgSecondAction.setImage(icon); break;
+ case Three: this.activeAction = ACTION.Three; this.imgThirdAction.setImage(icon); break;
+ case Four: this.activeAction = ACTION.Four; this.imgFourthAction.setImage(icon); break;
+ default:
+ }
+ }
+
+ /**
+ * Changes the status of the current action (on the left handside panel)
+ * @param status status of the action
+ */
+ protected void setActiveAction(STATUS status) {
+ if ( this.activeAction == null )
+ this.activeAction = ACTION.One;
+ setActiveAction(this.activeAction, status);
+ }
+
+ /**
+ * Changes the active action (on the left handside panel)
+ * @param action Reference of the action
+ */
+ protected void setActiveAction(ACTION action) {
+ setActiveAction(action, STATUS.Selected);
+ }
+
+ /**
+ * Creates an action (on the left handside panel)
+ * @param action Reference of the action
+ * @param label Label of the action
+ */
+ protected void createAction(ACTION action, String label) {
+ switch ( action ) {
+ case One: this.lblFirstAction.setText(label); break;
+ case Two: this.lblSecondAction.setText(label); break;
+ case Three: this.lblThirdAction.setText(label); break;
+ case Four: this.lblFourthAction.setText(label); break;
+ default:
+ }
+ }
+
+ protected void setOption(int selectedOption) {
+ int realSelectedOption = selectedOption % 3;
+ this.radioOption1.setSelection(realSelectedOption == 0);
+ this.radioOption2.setSelection(realSelectedOption == 1);
+ this.radioOption3.setSelection(realSelectedOption == 2);
+ }
+
+ protected void setOption(String label, String option1, boolean option1Selected, String toolTip1, String option2, boolean option2Selected, String toolTip2, String option3, boolean option3Selected, String toolTip3) {
+ if ( label != null ) this.lblOption.setText(label);
+
+ if ( option1 == null ) {
+ this.radioOption1.setText("");
+ this.radioOption1.setToolTipText("");
+ this.radioOption1.setVisible(false);
+ } else {
+ this.radioOption1.setText(option1);
+ this.radioOption1.setSelection(option1Selected);
+ this.radioOption1.setVisible(true);
+ if ( toolTip1 != null ) this.radioOption1.setToolTipText(toolTip1);
+ }
+
+ if ( option2 == null ) {
+ this.radioOption2.setText("");
+ this.radioOption2.setToolTipText("");
+ this.radioOption2.setVisible(true);
+ } else {
+ this.radioOption2.setText(option2);
+ this.radioOption2.setSelection(option2Selected);
+ this.radioOption2.setVisible(true);
+ if ( toolTip2 != null ) this.radioOption2.setToolTipText(toolTip2);
+ }
+
+ if ( option3 == null ) {
+ this.radioOption3.setText("");
+ this.radioOption3.setToolTipText("");
+ this.radioOption3.setVisible(false);
+ } else {
+ this.radioOption3.setText(option3);
+ this.radioOption3.setSelection(option3Selected);
+ this.radioOption3.setVisible(true);
+ if ( toolTip3 != null ) this.radioOption3.setToolTipText(toolTip3);
+ }
+
+ this.compoBottom.layout();
+
+ showOption();
+ disableOption();
+ }
+
+ protected void enableOption() {
+ this.lblOption.setEnabled(true);
+ this.radioOption1.setEnabled(true);
+ this.radioOption2.setEnabled(true);
+ this.radioOption3.setEnabled(true);
+ }
+
+ protected void disableOption() {
+ this.lblOption.setEnabled(false);
+ this.radioOption1.setEnabled(false);
+ this.radioOption2.setEnabled(false);
+ this.radioOption3.setEnabled(false);
+ }
+
+ protected void hideOption() {
+ this.lblOption.setVisible(false);
+ this.radioOption1.setVisible(false);
+ this.radioOption2.setVisible(false);
+ this.radioOption3.setVisible(false);
+ }
+
+ protected void showOption() {
+ this.lblOption.setVisible(true);
+ this.radioOption1.setVisible(this.radioOption1.getText().length() != 0);
+ this.radioOption2.setVisible(this.radioOption2.getText().length() != 0);
+ this.radioOption3.setVisible(this.radioOption3.getText().length() != 0);
+ }
+
+ /**
+ * Returns the value of the selected option:
+ * 1 for the first option
+ * 2 for the second option
+ * 3 for the third option
+ */
+ protected int getOptionValue() {
+ if ( this.radioOption1.getSelection() )
+ return 1;
+ if ( this.radioOption2.getSelection() )
+ return 2;
+ if ( this.radioOption3.getSelection() )
+ return 3;
+ return 0;
+ }
+
+
+
+ static Shell dialogShell = null;
+ static Composite dialogComposite = null;
+ static Label dialogLabel = null;
+ /**
+ * shows up an on screen popup displaying the message but does not wait for any user input
+ * it is the responsibility of the caller to dismiss the popup
+ */
+ public static Shell popup(String msg) {
+ logger.info(DBGui.class, msg);
+
+ Display.getDefault().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ if ( dialogShell == null ) {
+ dialogShell = new Shell(display, SWT.APPLICATION_MODAL);
+ dialogShell.setSize(500, 70);
+ dialogShell.setBackground(BLACK_COLOR);
+
+ // Use the active shell, if available, to determine the new shell placing
+ int locationX = 0;
+ int locationY = 0;
+ Rectangle shellSize = dialogShell.getBounds();
+ Shell parent = display.getActiveShell();
+ if (parent!=null) {
+ Rectangle parentSize = parent.getBounds();
+ locationX = (parentSize.width - shellSize.width)/2+parentSize.x;
+ locationY = (parentSize.height - shellSize.height)/2+parentSize.y;
+ } else {
+ locationX = (Toolkit.getDefaultToolkit().getScreenSize().width - 500) / 4;
+ locationY = (Toolkit.getDefaultToolkit().getScreenSize().height - 70) / 4;
+ }
+ dialogShell.setLocation(new Point(locationX, locationY));
+
+ int borderWidth = (dialogShell.getBorderWidth()+1)*2;
+ dialogComposite = new Composite(dialogShell, SWT.NONE);
+ dialogComposite.setSize(500-borderWidth, 70-borderWidth);
+ dialogComposite.setLocation(1, 1);
+ dialogComposite.setBackground(COMPO_LEFT_COLOR);
+ dialogComposite.setLayout(new GridLayout( 1, false ) );
+
+ dialogLabel = new Label(dialogComposite, SWT.CENTER | SWT.WRAP);
+ dialogLabel.setBackground(COMPO_LEFT_COLOR);
+ dialogLabel.setLayoutData( new GridData( SWT.CENTER, SWT.CENTER, true, true ) );
+ dialogLabel.setFont(TITLE_FONT);
+ } else {
+ restoreCursors();
+ }
+
+ dialogLabel.setText(msg);
+ dialogShell.layout(true);
+ dialogShell.open();
+
+ dialogComposite.layout();
+
+ setArrowCursor();
+ }
+ });
+
+ return dialogShell;
+ }
+
+ /**
+ * dismiss the popup if it is displayed (else, does nothing)
+ */
+ public static void closePopup() {
+ if ( dialogShell != null ) {
+ Display.getDefault().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ dialogShell.close();
+ dialogShell = null;
+
+ restoreCursors();
+ }
+ });
+ }
+ }
+
+ private static Stack> cursorsStack = new Stack>();
+ public static void setArrowCursor() {
+ Map cursors = new HashMap();
+ for ( Shell shell: display.getShells() ) {
+ cursors.put(shell, shell.getCursor());
+ shell.setCursor(CURSOR_WAIT);
+ }
+ cursorsStack.push(cursors);
+ refreshDisplay();
+ }
+
+ public static void restoreCursors() {
+ Map cursors = cursorsStack.pop();
+ for ( Shell shell: display.getShells() ) {
+ Cursor cursor = (cursors==null) ? null : cursors.get(shell);
+ shell.setCursor(cursor==null ? CURSOR_ARROW : cursor);
+ }
+ refreshDisplay();
+ }
+
+ /**
+ * Shows up an on screen popup displaying the message and wait for the user to click on the "OK" button
+ */
+ public static void popup(Level level, String msg) {
+ popup(level,msg,null);
+ }
+
+ /**
+ * Shows up an on screen popup, displaying the message (and the exception message if any) and wait for the user to click on the "OK" button
+ * The exception stacktrace is also printed on the standard error stream
+ */
+ public static void popup(Level level, String msg, Exception e) {
+ String popupMessage = msg;
+ logger.log(DBGui.class, level, msg, e);
+
+ Throwable cause = e;
+ while ( cause != null ) {
+ if ( cause.getMessage() != null ) {
+ if ( !popupMessage.endsWith(cause.getMessage()) )
+ popupMessage += "\n\n" + cause.getClass().getSimpleName() + ": " + cause.getMessage();
+ } else
+ popupMessage += "\n\n" + cause.getClass().getSimpleName();
+ cause = cause.getCause();
+ }
+
+ switch ( level.toInt() ) {
+ case Priority.FATAL_INT:
+ case Priority.ERROR_INT:
+ MessageDialog.openError(display.getActiveShell(), DBPlugin.pluginTitle, popupMessage);
+ break;
+ case Priority.WARN_INT:
+ MessageDialog.openWarning(display.getActiveShell(), DBPlugin.pluginTitle, popupMessage);
+ break;
+ default:
+ MessageDialog.openInformation(display.getActiveShell(), DBPlugin.pluginTitle, popupMessage);
+ break;
+ }
+
+ refreshDisplay();
+ }
+
+ static int questionResult;
+
+ /**
+ * Shows up an on screen popup displaying the question (and the exception message if any) and wait for the user to click on the "YES" or "NO" button
+ * The exception stacktrace is also printed on the standard error stream
+ */
+ public static boolean question(String msg) {
+ return question(msg, new String[] {"Yes", "No"}) == 0;
+ }
+
+ /**
+ * Shows up an on screen popup displaying the question (and the exception message if any) and wait for the user to click on the "YES" or "NO" button
+ * The exception stacktrace is also printed on the standard error stream
+ */
+ public static int question(String msg, String[] buttonLabels) {
+ if ( logger.isDebugEnabled() ) logger.debug(DBGui.class, "Question: "+msg);
+
+ Display.getDefault().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ //questionResult = MessageDialog.openQuestion(display.getActiveShell(), DBPlugin.pluginTitle, msg);
+ Shell shell = new Shell(display, SWT.SHELL_TRIM);
+ shell.setSize(0, 0);
+ shell.setBackground(BLACK_COLOR);
+
+ // Use the active shell, if available, to determine the new shell placing
+ int locationX = 0;
+ int locationY = 0;
+ Rectangle shellSize = shell.getBounds();
+ Shell parent = display.getActiveShell();
+ if (parent!=null) {
+ Rectangle parentSize = parent.getBounds();
+ locationX = (parentSize.width - shellSize.width)/2+parentSize.x;
+ locationY = (parentSize.height - shellSize.height)/2+parentSize.y;
+ } else {
+ locationX = (Toolkit.getDefaultToolkit().getScreenSize().width - shell.getSize().x) / 4;
+ locationY = (Toolkit.getDefaultToolkit().getScreenSize().height - shell.getSize().y) / 4;
+ }
+ shell.setLocation(new Point(locationX, locationY));
+ MessageDialog messageDialog = new MessageDialog(shell, DBPlugin.pluginTitle, null, msg, MessageDialog.QUESTION, buttonLabels, 0);
+ questionResult = messageDialog.open();
+ }
+ });
+
+ if ( logger.isDebugEnabled() ) logger.debug(DBGui.class, "Answer: "+buttonLabels[questionResult]);
+ return questionResult;
+ }
+
+ static String answeredPassword;
+
+ /**
+ * open up an input dialog and ask for a password
+ * @param message the message on the password dialog
+ * @return the typed password
+ */
+ public static String passwordDialog(String title, String message) {
+ if ( logger.isDebugEnabled() ) logger.debug(DBGui.class, "Asking for password");
+ answeredPassword = "";
+ Display.getDefault().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ Shell shell = new Shell(display, SWT.SHELL_TRIM);
+ shell.setText(title);
+ shell.setSize(0, 0);
+ shell.setBackground(BLACK_COLOR);
+
+ // Use the active shell, if available, to determine the new shell placing
+ int locationX = 0;
+ int locationY = 0;
+ Rectangle shellSize = shell.getBounds();
+ Shell parent = display.getActiveShell();
+ if (parent!=null) {
+ Rectangle parentSize = parent.getBounds();
+ locationX = (parentSize.width - shellSize.width)/2+parentSize.x;
+ locationY = (parentSize.height - shellSize.height)/2+parentSize.y;
+ } else {
+ locationX = (Toolkit.getDefaultToolkit().getScreenSize().width - shell.getSize().x) / 4;
+ locationY = (Toolkit.getDefaultToolkit().getScreenSize().height - shell.getSize().y) / 4;
+ }
+ shell.setLocation(new Point(locationX, locationY));
+
+ DBGuiPasswordDialog passwordDialog = new DBGuiPasswordDialog(shell);
+ if ( passwordDialog.open() == 0 )
+ answeredPassword = passwordDialog.getPassword();
+ else
+ answeredPassword = null;
+ passwordDialog.close();
+ }
+ });
+
+ return answeredPassword;
+ }
+
+ protected void hideGrpDatabase() {
+ this.grpDatabase.setVisible(false);
+ this.grpDatabase.setData("visible", false);
+ }
+
+ protected void showGrpDatabase() {
+ this.grpDatabase.setVisible(true);
+ this.grpDatabase.setData("visible", true);
+ }
+
+ private SelectionListener actionListener = null;
+ protected void setBtnAction(String label, SelectionListener listener) {
+ if ( label == null ) {
+ this.btnDoAction.setVisible(false);
+ } else {
+ this.btnDoAction.setText(label);
+ this.btnDoAction.setVisible(true);
+
+ if ( this.actionListener != null ) {
+ this.btnDoAction.removeSelectionListener(this.actionListener);
+ this.actionListener = null;
+ }
+
+ if ( listener != null ) {
+ this.actionListener = listener;
+ this.btnDoAction.addSelectionListener(this.actionListener);
+ }
+ }
+ }
+
+ /**
+ * Creates the progress bar that will allow to follow the export process
+ */
+ protected void createProgressBar(String label, int min, int max) {
+ if ( this.grpProgressBar == null ) {
+ this.grpProgressBar = new Group(this.compoRightTop, SWT.NONE);
+ this.grpProgressBar.setBackground(GROUP_BACKGROUND_COLOR);
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ fd.bottom = new FormAttachment(100);
+ this.grpProgressBar.setLayoutData(fd);
+ this.grpProgressBar.setLayout(new FormLayout());
+
+
+ this.lblProgressBar = new Label(this.grpProgressBar, SWT.CENTER);
+ this.lblProgressBar.setBackground(GROUP_BACKGROUND_COLOR);
+ this.lblProgressBar.setFont(TITLE_FONT);
+ fd = new FormData();
+ fd.top = new FormAttachment(0, -5);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ this.lblProgressBar.setLayoutData(fd);
+
+ this.progressBar = new ProgressBar(this.grpProgressBar, SWT.NONE);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.lblProgressBar);
+ fd.left = new FormAttachment(25);
+ fd.right = new FormAttachment(75);
+ fd.height = 15;
+ this.progressBar.setLayoutData(fd);
+ }
+
+ this.grpProgressBar.setVisible(true);
+ this.grpProgressBar.setData("visible", true);
+
+ this.grpProgressBar.moveAbove(null);
+
+ this.lblProgressBar.setText(label);
+ logger.info(DBGui.class, label);
+
+ this.progressBar.setMinimum(min);
+ this.progressBar.setMaximum(max);
+
+
+ this.compoRightTop.layout();
+ refreshDisplay();
+
+ resetProgressBar();
+ }
+
+ public void hideProgressBar() {
+ if ( this.progressBar != null ) {
+ this.grpProgressBar.setVisible(false);
+ this.grpProgressBar.setData("visible", false);
+ refreshDisplay();
+ }
+ }
+
+ public void setProgressBarLabel(String label) {
+ if ( this.lblProgressBar == null )
+ createProgressBar(label, 0, 100);
+ else {
+ this.lblProgressBar.setText(label);
+ logger.info(DBGui.class, label);
+ }
+ refreshDisplay();
+ }
+
+ public String getProgressBarLabel() {
+ if ( this.lblProgressBar == null )
+ return "";
+
+ return this.lblProgressBar.getText();
+ }
+
+ /**
+ * Sets the min and max values of the progressBar and reset its selection to zero
+ */
+ public void setProgressBarMinAndMax(int min, int max) {
+ if ( this.lblProgressBar != null ) {
+ this.progressBar.setMinimum(min);
+ this.progressBar.setMaximum(max);
+ }
+ resetProgressBar();
+ }
+
+ /**
+ * Resets the progressBar to zero in the SWT thread (thread safe method)
+ */
+ public void resetProgressBar() {
+ if ( this.lblProgressBar != null )
+ this.progressBar.setSelection(0);
+ refreshDisplay();
+ }
+
+ /**
+ * Increases the progressBar selection in the SWT thread (thread safe method)
+ */
+ public void increaseProgressBar() {
+ if ( this.lblProgressBar != null )
+ this.progressBar.setSelection(this.progressBar.getSelection()+1);
+ refreshDisplay();
+ }
+
+ public void setMessage(String message) {
+ setMessage(message, GROUP_BACKGROUND_COLOR);
+ }
+
+ protected void setMessage(String message, Color background) {
+ if ( this.grpMessage == null ) {
+ this.grpMessage = new Group(this.compoRightTop, SWT.NONE);
+ this.grpMessage.setBackground(GROUP_BACKGROUND_COLOR);
+ this.grpMessage.setFont(GROUP_TITLE_FONT);
+ this.grpMessage.setText("Please wait ... ");
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ fd.bottom = new FormAttachment(100);
+ this.grpMessage.setLayoutData(fd);
+ this.grpMessage.setLayout(new FormLayout());
+
+ this.lblMessage = new CLabel(this.grpMessage, SWT.CENTER);
+ this.lblMessage.setAlignment(SWT.CENTER);
+ this.lblMessage.setBackground(GROUP_BACKGROUND_COLOR);
+ this.lblMessage.setFont(TITLE_FONT);
+ fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ fd.bottom = new FormAttachment(100);
+ this.lblMessage.setLayoutData(fd);
+ refreshDisplay();
+ }
+
+ this.grpMessage.setVisible(true);
+
+ if (this.grpProgressBar != null )
+ this.grpProgressBar.setVisible(false);
+
+ if ( this.grpDatabase != null )
+ this.grpDatabase.setVisible(false);
+
+ this.compoRightTop.layout();
+
+ this.lblMessage.setBackground(background);
+
+ String msg = message.replace("\n\n", "\n");
+ if ( background == RED_COLOR )
+ logger.error(DBGui.class, msg);
+ else
+ logger.info(DBGui.class, msg);
+
+ this.lblMessage.setText(msg);
+
+ this.grpMessage.moveAbove(null);
+
+ refreshDisplay();
+ }
+
+
+ public void closeMessage() {
+ if ( (this.grpMessage != null) && !this.grpMessage.isDisposed() ) {
+ this.grpMessage.setVisible(false);
+
+ if (this.grpProgressBar != null && (this.grpProgressBar.getData("visible") != null) )
+ this.grpProgressBar.setVisible((boolean)this.grpProgressBar.getData("visible"));
+
+ if ( this.grpDatabase != null && (this.grpDatabase.getData("visible") != null) )
+ this.grpDatabase.setVisible((boolean)this.grpDatabase.getData("visible"));
+
+ this.compoRightTop.layout();
+ refreshDisplay();
+ }
+ }
+
+ /**
+ * Method used to close graphical objects if needed
+ */
+ public void close() {
+ this.dialog.dispose();
+ this.dialog = null;
+
+ restoreCursors();
+ }
+
+ public void commitAndCloseConnection() throws SQLException {
+ if ( this.connection != null ) {
+ // in case some transactions have been started, we commit them
+ this.connection.commit();
+
+ this.connection.close();
+ this.connection = null;
+ }
+ }
+
+ public void rollbackAndCloseConnection() throws SQLException {
+ if ( this.connection != null ) {
+ // in case some transactions have been started, we roll them back
+ this.connection.rollback();
+
+ this.connection.close();
+ this.connection = null;
+ }
+ }
+
+ public boolean isDisposed() {
+ return this.dialog==null ? true : this.dialog.isDisposed();
+ }
+
+ protected Boolean fillInCompareTable(Tree tree, EObject memoryObject, int memoryObjectversion) {
+ return fillInCompareTable(tree, null, memoryObject, memoryObjectversion);
+ }
+
+ @SuppressWarnings("unchecked")
+ protected Boolean fillInCompareTable(Tree tree, TreeItem treeItem, EObject memoryObject, int memoryObjectversion) {
+ assert ( memoryObject!=null );
+ DBMetadata dbMetadata = DBMetadata.getDBMetadata(memoryObject);
+
+ logger.debug(DBGui.class, "Showing up memory and database versions of component "+dbMetadata.getDebugName());
+
+ // we get the database version of the component
+ HashMap databaseObject;
+ try {
+ databaseObject = this.connection.getObjectFromDatabase(memoryObject, memoryObjectversion);
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "Failed to get component "+dbMetadata.getDebugName()+" from the database.", err);
+ return null;
+ }
+
+ boolean areIdentical = true;
+
+ if ( treeItem == null ) { // the root component
+ tree.removeAll();
+ refreshDisplay();
+
+ TreeItem item = new TreeItem(tree, SWT.NONE);
+ item.setText(new String[] {"Version", String.valueOf(dbMetadata.getInitialVersion().getVersion()), String.valueOf(databaseObject.get("version"))});
+
+ if ( (String)databaseObject.get("created_by") != null ) {
+ item = new TreeItem(tree, SWT.NONE);
+ item.setText(new String[] {"Created by", System.getProperty("user.name"), (String)databaseObject.get("created_by")});
+ }
+
+ if ( databaseObject.get("created_on") != null ) {
+ item = new TreeItem(tree, SWT.NONE);
+ if ( dbMetadata.getDatabaseVersion().getTimestamp() != null )
+ item.setText(new String[] {"Created on", new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(dbMetadata.getInitialVersion().getTimestamp().getTime()), new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(databaseObject.get("created_on"))});
+ else
+ item.setText(new String[] {"Created on", "", new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(databaseObject.get("created_on"))});
+ }
+ }
+
+ areIdentical &= areIdentical &= addItemToCompareTable(tree, treeItem, "Class", memoryObject.getClass().getSimpleName(), (String)databaseObject.get("class"));
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Name", ((INameable)memoryObject).getName(), (String)databaseObject.get("name"));
+
+ if ( memoryObject instanceof IDocumentable )
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Documentation", ((IDocumentable)memoryObject).getDocumentation(), (String)databaseObject.get("documentation"));
+
+ if ( memoryObject instanceof IJunction )
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Type", ((IJunction)memoryObject).getType(), (String)databaseObject.get("type"));
+
+ if ( memoryObject instanceof IArchimateRelationship ) {
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Source id", ((IArchimateRelationship)memoryObject).getSource().getId(), (String)databaseObject.get("source_id"));
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Target id", ((IArchimateRelationship)memoryObject).getTarget().getId(), (String)databaseObject.get("target_id"));
+ if ( memoryObject instanceof IInfluenceRelationship )
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Strength", ((IInfluenceRelationship)memoryObject).getStrength(), (String)databaseObject.get("strength"));
+ if ( memoryObject instanceof IAccessRelationship )
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Access type", String.valueOf(((IAccessRelationship)memoryObject).getAccessType()), String.valueOf((int)databaseObject.get("access_type")));
+ }
+
+ // TODO: get folders subfolders and elements from the database in order to compare them
+ if ( memoryObject instanceof IFolder )
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Folder type", ((IFolder)memoryObject).getType().getLiteral(), FolderType.get((int)databaseObject.get("type")).getLiteral());
+
+ if ( memoryObject instanceof IArchimateDiagramModel )
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Viewpoint", ((IArchimateDiagramModel)memoryObject).getViewpoint(), (String)databaseObject.get("viewpoint"));
+
+ if ( memoryObject instanceof IDiagramModel )
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Router type", String.valueOf(((IDiagramModel)memoryObject).getConnectionRouterType()), databaseObject.get("connection_router_type")==null ? null : String.valueOf((int)databaseObject.get("connection_router_type")));
+
+ if ( memoryObject instanceof IBorderObject )
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Border color", ((IBorderObject)memoryObject).getBorderColor(), (String)databaseObject.get("border_color"));
+
+ if ( memoryObject instanceof IDiagramModelNote )
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Border type", String.valueOf(((IDiagramModelNote)memoryObject).getBorderType()), databaseObject.get("border_type")==null ? null : String.valueOf((int)databaseObject.get("border_type")));
+
+ if ( memoryObject instanceof IConnectable ) {
+ // TODO: get source and target connections from database and compare then to component's ones
+ /*
+ for ( IDiagramModelConnection conn: ((IConnectable)component).getSourceConnections() )
+ areIdentical &= addItemToCompareTable(table, level, "source connections", conn.getId(), (String)hashResult.get("xxxxx"));
+ for ( IDiagramModelConnection conn: ((IConnectable)component).getTargetConnections() )
+ areIdentical &= addItemToCompareTable(table, level, "target connections", conn.getId(), (String)hashResult.get("xxxxx"));
+ */
+ }
+
+ if ( memoryObject instanceof IDiagramModelArchimateObject )
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Type", String.valueOf(((IDiagramModelArchimateObject)memoryObject).getType()), databaseObject.get("type")==null ? null : String.valueOf((int)databaseObject.get("type")));
+
+ if ( memoryObject instanceof IDiagramModelImageProvider )
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Image path", ((IDiagramModelImageProvider)memoryObject).getImagePath(), (String)databaseObject.get("image_path"));
+
+ if ( memoryObject instanceof IDiagramModelObject ) {
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Fill color", ((IDiagramModelObject)memoryObject).getFillColor(), (String)databaseObject.get("fill_color"));
+ IBounds bounds = ((IDiagramModelObject)memoryObject).getBounds();
+ areIdentical &= addItemToCompareTable(tree, treeItem, "X", String.valueOf(bounds.getX()), databaseObject.get("x") == null ? null : String.valueOf((int)databaseObject.get("x")));
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Y", String.valueOf(bounds.getY()), databaseObject.get("y")==null ? null : String.valueOf((int)databaseObject.get("y")));
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Width" ,String.valueOf(bounds.getWidth()), databaseObject.get("width")==null ? null : String.valueOf((int)databaseObject.get("width")));
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Height", String.valueOf(bounds.getHeight()), databaseObject.get("height")==null ? null : String.valueOf((int)databaseObject.get("height")));
+ }
+
+ if ( memoryObject instanceof IDiagramModelArchimateComponent )
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Archimate concept", ((IDiagramModelArchimateComponent)memoryObject).getArchimateConcept().getId(), (String)databaseObject.get("element_id"));
+
+ if ( memoryObject instanceof IDiagramModelArchimateConnection )
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Archimate concept", ((IDiagramModelArchimateConnection)memoryObject).getArchimateConcept().getId(), (String)databaseObject.get("element_id"));
+
+ if ( memoryObject instanceof IFontAttribute ) {
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Font", ((IFontAttribute)memoryObject).getFont(), (String)databaseObject.get("font"));
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Font color", ((IFontAttribute)memoryObject).getFontColor(), (String)databaseObject.get("font_color"));
+ }
+
+ if ( memoryObject instanceof ILineObject ) {
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Line width", String.valueOf(((ILineObject)memoryObject).getLineWidth()), databaseObject.get("line_width")==null ? null : String.valueOf((int)databaseObject.get("line_width")));
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Line color", ((ILineObject)memoryObject).getLineColor(), (String)databaseObject.get("line_color"));
+ }
+
+ if ( memoryObject instanceof ILockable ) {
+ // the database can contain a boolean, a char (oracle) or an integer (sqlite, mysql, mssql, postgres) depending on the database brand
+ String isLockedInDatabase = null;
+ if ( databaseObject.get("is_locked") != null ) {
+ if ( databaseObject.get("is_locked") instanceof Boolean )
+ isLockedInDatabase = String.valueOf((boolean)databaseObject.get("is_locked"));
+
+ if ( databaseObject.get("is_locked") instanceof Integer )
+ isLockedInDatabase = ((int)databaseObject.get("is_locked") == 0) ? "false" : "true";
+
+ if ( databaseObject.get("is_locked") instanceof String )
+ isLockedInDatabase = (Integer.valueOf((String)databaseObject.get("is_locked")) == 0) ? "false" : "true";
+ }
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Locked", String.valueOf(((ILockable)memoryObject).isLocked()), isLockedInDatabase);
+ }
+
+ if ( memoryObject instanceof ISketchModel )
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Background", String.valueOf(((ISketchModel)memoryObject).getBackground()), databaseObject.get("background")==null ? null : String.valueOf((int)databaseObject.get("background")));
+
+ if ( memoryObject instanceof ITextAlignment )
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Text alignment", String.valueOf(((ITextAlignment)memoryObject).getTextAlignment()), databaseObject.get("text_alignment")==null ? null : String.valueOf((int)databaseObject.get("text_alignment")));
+
+ if ( memoryObject instanceof ITextPosition )
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Text position", String.valueOf(((ITextPosition)memoryObject).getTextPosition()), databaseObject.get("text_position")==null ? null : String.valueOf((int)databaseObject.get("text_position")));
+
+ if ( memoryObject instanceof ITextContent )
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Content", ((ITextContent)memoryObject).getContent(), (String)databaseObject.get("content"));
+
+ if ( dbMetadata.getImagePosition() != null )
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Image position", String.valueOf(dbMetadata.getImagePosition()), databaseObject.get("image_position")==null ? null : String.valueOf((int)databaseObject.get("image_position")));
+
+ if ( memoryObject instanceof INotesContent )
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Notes", ((INotesContent)memoryObject).getNotes(), (String)databaseObject.get("notes"));
+
+ if ( memoryObject instanceof IDiagramModelConnection ) {
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Type", String.valueOf(((IDiagramModelConnection)memoryObject).getType()), databaseObject.get("type")==null ? null : String.valueOf((int)databaseObject.get("type"))); // we do not use getText as it is deprecated
+ areIdentical &= addItemToCompareTable(tree, treeItem, "Text position", String.valueOf(((IDiagramModelConnection)memoryObject).getTextPosition()), databaseObject.get("text_position")==null ? null : String.valueOf((int)databaseObject.get("text_position")));
+
+ // we show up the bendpoints only if they both exist
+ if ( databaseObject.containsKey("bendpoints") ) {
+ if ( (((IDiagramModelConnection)memoryObject).getBendpoints().size() != 0) || (((ArrayList)databaseObject.get("bendpoints")).size() != 0) ) {
+ TreeItem bendpointsTreeItem;
+ if ( treeItem == null )
+ bendpointsTreeItem = new TreeItem(tree, SWT.NONE);
+ else
+ bendpointsTreeItem = new TreeItem(treeItem, SWT.NONE);
+ bendpointsTreeItem.setText("Bendpoints");
+ bendpointsTreeItem.setExpanded(false);
+
+ // we get a list of component's bendpoints
+ Integer[][] componentBendpoints = new Integer[((IDiagramModelConnection)memoryObject).getBendpoints().size()][4];
+ for (int i = 0; i < ((IDiagramModelConnection)memoryObject).getBendpoints().size(); ++i) {
+ componentBendpoints[i] = new Integer[] { ((IDiagramModelConnection)memoryObject).getBendpoints().get(i).getStartX(), ((IDiagramModelConnection)memoryObject).getBendpoints().get(i).getStartY(), ((IDiagramModelConnection)memoryObject).getBendpoints().get(i).getEndX(), ((IDiagramModelConnection)memoryObject).getBendpoints().get(i).getEndY() };
+ }
+ //Arrays.sort(componentBendpoints, this.integerComparator);www
+
+ // we get a list of properties from the database
+ Integer[][] databaseBendpoints = new Integer[((ArrayList)databaseObject.get("bendpoints")).size()][4];
+ int i = 0;
+ for (DBBendpoint bp: (ArrayList)databaseObject.get("bendpoints") ) {
+ componentBendpoints[i] = new Integer[] { bp.getStartX(), bp.getStartY(), bp.getEndX(), bp.getEndY() };
+ ++i;
+ }
+ //Arrays.sort(databaseBendpoints, this.integerComparator);
+
+ int indexComponent = 0;
+ int indexDatabase = 0;
+ while ( (indexComponent < componentBendpoints.length) || (indexDatabase < databaseBendpoints.length) ) {
+ TreeItem subTreeItem = new TreeItem(bendpointsTreeItem, SWT.NONE);
+ subTreeItem.setText("Bendpoint "+Math.max(indexComponent, indexDatabase)+1);
+ subTreeItem.setExpanded(false);
+ if ( indexComponent >= componentBendpoints.length ) { // only the database has got the property
+ areIdentical &= addItemToCompareTable(tree, subTreeItem, "Start X", null, String.valueOf(databaseBendpoints[indexDatabase][0]));
+ areIdentical &= addItemToCompareTable(tree, subTreeItem, "Start Y", null, String.valueOf(databaseBendpoints[indexDatabase][1]));
+ areIdentical &= addItemToCompareTable(tree, subTreeItem, "End X", null, String.valueOf(databaseBendpoints[indexDatabase][2]));
+ areIdentical &= addItemToCompareTable(tree, subTreeItem, "End Y", null, String.valueOf(databaseBendpoints[indexDatabase][3]));
+ ++indexDatabase;
+ } else if ( indexDatabase >= databaseBendpoints.length ) { // only the component has got the property
+ areIdentical &= addItemToCompareTable(tree, subTreeItem, "Start X", String.valueOf(componentBendpoints[indexComponent][0]), null);
+ areIdentical &= addItemToCompareTable(tree, subTreeItem, "Start Y", String.valueOf(componentBendpoints[indexComponent][1]), null);
+ areIdentical &= addItemToCompareTable(tree, subTreeItem, "End X", String.valueOf(componentBendpoints[indexComponent][2]), null);
+ areIdentical &= addItemToCompareTable(tree, subTreeItem, "End Y", String.valueOf(componentBendpoints[indexComponent][3]), null);
+ ++indexComponent;
+ } else {
+ areIdentical &= addItemToCompareTable(tree, subTreeItem, "Start X", String.valueOf(componentBendpoints[indexComponent][0]), String.valueOf(databaseBendpoints[indexDatabase][0]));
+ areIdentical &= addItemToCompareTable(tree, subTreeItem, "Start Y", String.valueOf(componentBendpoints[indexComponent][1]), String.valueOf(databaseBendpoints[indexDatabase][1]));
+ areIdentical &= addItemToCompareTable(tree, subTreeItem, "End X", String.valueOf(componentBendpoints[indexComponent][2]), String.valueOf(databaseBendpoints[indexDatabase][2]));
+ areIdentical &= addItemToCompareTable(tree, subTreeItem, "End Y", String.valueOf(componentBendpoints[indexComponent][3]), String.valueOf(databaseBendpoints[indexDatabase][3]));
+ ++indexComponent;
+ ++indexDatabase;
+ }
+ }
+ }
+ }
+ }
+
+ // we show up the properties if both exist
+ if ( databaseObject.containsKey("properties") ) {
+ if ( memoryObject instanceof IProperties && ((IProperties)memoryObject).getProperties().size() != 0) {
+ TreeItem propertiesTreeItem;
+ if ( treeItem == null )
+ propertiesTreeItem = new TreeItem(tree, SWT.NONE);
+ else
+ propertiesTreeItem = new TreeItem(treeItem, SWT.NONE);
+ propertiesTreeItem.setText("Properties");
+ propertiesTreeItem.setExpanded(true);
+
+ // we get a sorted list of component's properties
+ ArrayList componentProperties = new ArrayList();
+ for (int i = 0; i < ((IProperties)memoryObject).getProperties().size(); ++i) {
+ componentProperties.add(new DBProperty(((IProperties)memoryObject).getProperties().get(i).getKey(), ((IProperties)memoryObject).getProperties().get(i).getValue()));
+ }
+ Collections.sort(componentProperties, this.propertyComparator);
+
+ // we get a sorted list of properties from the database
+ ArrayList databaseProperties = (ArrayList)databaseObject.get("properties");
+ Collections.sort(databaseProperties, this.propertyComparator);
+
+ Collator collator = Collator.getInstance();
+ int indexComponent = 0;
+ int indexDatabase = 0;
+ int compare;
+ while ( (indexComponent < componentProperties.size()) || (indexDatabase < databaseProperties.size()) ) {
+ if ( indexComponent >= componentProperties.size() )
+ compare = 1;
+ else {
+ if ( indexDatabase >= databaseProperties.size() )
+ compare = -1;
+ else
+ compare = collator.compare(componentProperties.get(indexComponent).getKey(), databaseProperties.get(indexDatabase).getKey());
+ }
+
+ if ( compare == 0 ) { // both have got the same property
+ areIdentical &= addItemToCompareTable(tree, propertiesTreeItem, componentProperties.get(indexComponent).getKey(), componentProperties.get(indexComponent).getValue(), databaseProperties.get(indexDatabase).getValue());
+ ++indexComponent;
+ ++indexDatabase;
+ } else if ( compare < 0 ) { // only the component has got the property
+ areIdentical &= addItemToCompareTable(tree, propertiesTreeItem, componentProperties.get(indexComponent).getKey(), componentProperties.get(indexComponent).getValue(), null);
+ ++indexComponent;
+ } else { // only the database has got the property
+ areIdentical &= addItemToCompareTable(tree, propertiesTreeItem, componentProperties.get(indexDatabase).getKey(), null, databaseProperties.get(indexDatabase).getValue());
+ ++indexDatabase;
+ }
+ }
+ }
+ }
+
+ refreshDisplay();
+ return areIdentical;
+ }
+
+ Comparator propertyComparator = new Comparator() {
+ @Override
+ public int compare(final DBProperty row1, final DBProperty row2) {
+ return Collator.getInstance().compare(row1.getKey(),row2.getKey());
+ }
+ };
+
+ Comparator integerComparator = new Comparator() {
+ @Override
+ public int compare(final Integer[] row1, final Integer[] row2) {
+ return Collator.getInstance().compare(row1[0],row2[0]);
+ }
+ };
+
+
+ /**
+ * Helper function to fill in the compareTable
+ * @return true if col2 and col3 are equals, false if they differ
+ */
+ private static boolean addItemToCompareTable(Tree tree, TreeItem treeItem, String col1, String col2, String col3) {
+ TreeItem subTreeItem;
+ boolean isIdentical;
+
+ if ( treeItem != null )
+ subTreeItem = new TreeItem(treeItem, SWT.NULL);
+ else
+ subTreeItem = new TreeItem(tree, SWT.NONE);
+
+ subTreeItem.setText(new String[] {col1, col2, col3 });
+ if ( !DBPlugin.areEqual(col2, col3) ) {
+ if ( treeItem != null )
+ treeItem.setBackground(DBGui.LIGHT_RED_COLOR);
+ subTreeItem.setBackground(DBGui.LIGHT_RED_COLOR);
+ isIdentical = false;
+ } else
+ isIdentical = true;
+
+ refreshDisplay();
+ return isIdentical;
+ }
+
+ public byte[] createImage(IDiagramModel view, int scalePercent, int margin) {
+ byte[] imageContent = null;
+ DBMetadata dbMetadata = DBMetadata.getDBMetadata(view);
+
+ String oldLabel = getProgressBarLabel();
+ logger.debug(DBGui.class, "Creating screenshot of view \""+view.getName()+"\"");
+
+ try ( ByteArrayOutputStream out = new ByteArrayOutputStream() ) {
+ try ( DataOutputStream writeOut = new DataOutputStream(out) ) {
+ ImageLoader saver = new ImageLoader();
+ ModelReferencedImage viewImage = DiagramUtils.createModelReferencedImage(view, scalePercent/100.0, margin);
+ Image image = viewImage.getImage();
+
+ saver.data = new ImageData[] { image.getImageData(ImageFactory.getDeviceZoom()) };
+ image.dispose();
+
+ saver.save(writeOut, SWT.IMAGE_PNG);
+ imageContent = out.toByteArray();
+
+ org.eclipse.draw2d.geometry.Rectangle bounds = viewImage.getBounds();
+ bounds.performScale(ImageFactory.getDeviceZoom() / 100); // Account for device zoom level
+
+ dbMetadata.getScreenshot().setScreenshotBytes(imageContent);
+ dbMetadata.getScreenshot().setScaleFactor(scalePercent);
+ dbMetadata.getScreenshot().setBorderWidth(margin);
+ dbMetadata.getScreenshot().setBounds(bounds);
+ } catch (IOException err) {
+ logger.error(DBGui.class, "Failed to close DataOutputStream", err);
+ }
+ } catch (IOException err) {
+ logger.error(DBGui.class, "Failed to close ByteArrayOutputStream", err);
+ }
+
+ setProgressBarLabel(oldLabel);
+
+ return imageContent;
+ }
+
+ /**
+ * Refreshes the display
+ */
+ public static void refreshDisplay() {
+ while ( DBGui.display.readAndDispatch() ) {
+ // nothing to do
+ }
+ }
+
+ public static void incrementText(Text txt) {
+ if ( txt != null ) {
+ try {
+ txt.setText(toString(toInt(txt.getText())+1));
+ } catch (@SuppressWarnings("unused") Exception ign) {
+ // ignore
+ }
+ }
+ }
+
+ public static void decrementText(Text txt) {
+ if ( txt != null ) {
+ try {
+ txt.setText(toString(toInt(txt.getText())-1));
+ } catch (@SuppressWarnings("unused") Exception ign) {
+ // ignore
+ }
+ }
+ }
+
+ public static String toString(int value) {
+ if ( (value == 0) && !DBPlugin.INSTANCE.getPreferenceStore().getBoolean("showZeroValues") )
+ return "";
+ return String.valueOf(value);
+ }
+
+ public static int toInt(String value) {
+ if ( DBPlugin.isEmpty(value) )
+ return 0;
+ return Integer.valueOf(value);
+ }
+
+ protected DBDatabaseConnection getDatabaseConnection() {
+ return this.connection;
+ }
+}
\ No newline at end of file
diff --git a/sources/src/org/archicontribs/database/GUI/DBGuiAdminDatabase.java b/sources/src/org/archicontribs/database/GUI/DBGuiAdminDatabase.java
new file mode 100644
index 00000000..e38c274b
--- /dev/null
+++ b/sources/src/org/archicontribs/database/GUI/DBGuiAdminDatabase.java
@@ -0,0 +1,570 @@
+/**
+ * This program and the accompanying materials
+ * are made available under the terms of the License
+ * which accompanies this distribution in the file LICENSE.txt
+ */
+
+package org.archicontribs.database.GUI;
+
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.text.SimpleDateFormat;
+import java.util.Hashtable;
+import java.util.List;
+import org.apache.log4j.Level;
+import org.archicontribs.database.DBDatabaseEntry;
+import org.archicontribs.database.DBLogger;
+import org.archicontribs.database.DBPlugin;
+import org.archicontribs.database.connection.DBDatabaseImportConnection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.layout.FormLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * This class manages the GUI for the database administration procedures
+ *
+ * @author Herve Jouin
+ */
+public class DBGuiAdminDatabase extends DBGui {
+ @SuppressWarnings("hiding")
+ protected static final DBLogger logger = new DBLogger(DBGuiAdminDatabase.class);
+
+ DBDatabaseImportConnection importConnection;
+
+ Table tblModels;
+ Table tblModelVersions;
+ Text txtFilterModels;
+
+ private Group grpModels;
+ private Group grpModelVersions;
+ private Group grpActions;
+
+ private Label lblModelName;
+ Text txtModelName;
+ private Label lblPurpose;
+ Text txtPurpose;
+ private Label lblReleaseNote;
+ Text txtReleaseNote;
+
+ Button btnCheckStructure;
+ Button btnCheckContent;
+ Button btnDeleteModel;
+ //Button btnDeleteVersion;
+
+
+ /**
+ * Creates the GUI to import a model
+ * @param databaseImportconnection
+ * @param entries
+ * @param title Title of the window
+ * @throws Exception
+ */
+ public DBGuiAdminDatabase(DBDatabaseImportConnection databaseImportconnection, List entries, String title) throws Exception {
+ super(title);
+
+ this.importConnection = databaseImportconnection;
+
+ if ( logger.isDebugEnabled() ) logger.debug("Setting up GUI for administering the \""+databaseImportconnection.getDatabaseEntry().getName()+"\" database (plugin version "+DBPlugin.pluginVersion.toString()+").");
+
+ createAction(ACTION.One, "1 - Admin database");
+ setActiveAction(ACTION.One);
+
+ // We deactivate the btnDoAction button
+ setBtnAction(null, null);
+
+ // We activate the Eclipse Help framework
+ //TODO: setHelpHref("adminDatabase.html");
+
+ // we hide the compoRightTop that is no use here and move the compoRightBottom up
+ this.compoRightTop.setVisible(false);
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(0, 10);
+ fd.left = new FormAttachment(0, 10);
+ fd.right = new FormAttachment(100, -10);
+ fd.bottom = new FormAttachment(100, -100);
+ this.compoRightBottom.setLayoutData(fd);
+
+ createGrpModel();
+ createGrpActions();
+
+ // we set the comboDatabase entries and select the database
+ this.comboDatabaseEntries = entries;
+ int index = 0;
+ for (DBDatabaseEntry databaseEntry: this.comboDatabaseEntries) {
+ this.comboDatabases.add(databaseEntry.getName());
+ if ( databaseEntry.getName().equals(databaseImportconnection.getDatabaseEntry().getName()) )
+ this.comboDatabases.select(index);
+ ++index;
+ }
+ databaseSelected();
+ }
+
+ @Override
+ protected void databaseSelectedCleanup() {
+ if ( this.tblModels != null ) {
+ this.tblModels.removeAll();
+ }
+ if ( this.tblModelVersions != null ) {
+ this.tblModelVersions.removeAll();
+ }
+ }
+
+ /**
+ * Called when a database is selected in the comboDatabases and that the connection to this database succeeded.
+ * @param ignore (unused)
+ */
+ @SuppressWarnings("resource")
+ @Override
+ protected void connectedToDatabase(boolean ignore) {
+ this.importConnection = new DBDatabaseImportConnection(getDatabaseConnection());
+
+ this.compoRightBottom.setVisible(true);
+ this.compoRightBottom.layout();
+
+ this.tblModels.removeAll();
+
+ this.txtFilterModels.notifyListeners(SWT.Modify, new Event()); // refreshes the list of models in the database
+
+ this.tblModels.layout();
+ this.tblModels.setVisible(true);
+ this.tblModels.setLinesVisible(true);
+ this.tblModels.setRedraw(true);
+ if (logger.isTraceEnabled() ) logger.trace(" found "+this.tblModels.getItemCount()+" model"+(this.tblModels.getItemCount()>1?"s":"")+" in total");
+
+ if ( this.tblModels.getItemCount() != 0 ) {
+ this.btnDeleteModel.setEnabled(true);
+ this.tblModels.setSelection(0);
+ this.tblModels.notifyListeners(SWT.Selection, new Event()); // calls database.getModelVersions()
+ } else
+ this.btnDeleteModel.setEnabled(false);
+ }
+
+
+ protected void createGrpModel() {
+ this.grpModels = new Group(this.compoRightBottom, SWT.SHADOW_ETCHED_IN);
+ this.grpModels.setBackground(GROUP_BACKGROUND_COLOR);
+ this.grpModels.setFont(GROUP_TITLE_FONT);
+ this.grpModels.setText("Models: ");
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(50, -5);
+ fd.bottom = new FormAttachment(100);
+ this.grpModels.setLayoutData(fd);
+ this.grpModels.setLayout(new FormLayout());
+
+ Label lblListModels = new Label(this.grpModels, SWT.NONE);
+ lblListModels.setBackground(GROUP_BACKGROUND_COLOR);
+ lblListModels.setText("Filter:");
+ fd = new FormData();
+ fd.top = new FormAttachment(0, getDefaultMargin());
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ lblListModels.setLayoutData(fd);
+
+ this.txtFilterModels = new Text(this.grpModels, SWT.BORDER);
+ this.txtFilterModels.setToolTipText("You may use '%' as wildcard.");
+ this.txtFilterModels.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ DBGuiAdminDatabase.this.tblModels.removeAll();
+ DBGuiAdminDatabase.this.tblModelVersions.removeAll();
+ try {
+ for (Hashtable model : DBGuiAdminDatabase.this.importConnection.getModels("%"+DBGuiAdminDatabase.this.txtFilterModels.getText()+"%")) {
+ TableItem tableItem = new TableItem(DBGuiAdminDatabase.this.tblModels, SWT.BORDER);
+ tableItem.setText((String)model.get("name"));
+ tableItem.setData("id", model.get("id"));
+ }
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "Failed to get the list of models in the database.", err);
+ }
+ }
+ });
+ fd = new FormData();
+ fd.top = new FormAttachment(lblListModels, 0, SWT.CENTER);
+ fd.left = new FormAttachment(lblListModels, 5);
+ fd.right = new FormAttachment(100, -getDefaultMargin());
+ this.txtFilterModels.setLayoutData(fd);
+
+
+
+ this.tblModels = new Table(this.grpModels, SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL | SWT.H_SCROLL);
+ this.tblModels.setLinesVisible(true);
+ this.tblModels.setBackground(TABLE_BACKGROUND_COLOR);
+ this.tblModels.addListener(SWT.Selection, new Listener() {
+ @Override
+ public void handleEvent(Event e) {
+ DBGuiAdminDatabase.this.tblModelVersions.removeAll();
+
+ try {
+ for (Hashtable version : DBGuiAdminDatabase.this.importConnection.getModelVersions((String) DBGuiAdminDatabase.this.tblModels.getSelection()[0].getData("id")) ) {
+ if ( DBGuiAdminDatabase.this.tblModelVersions.getItemCount() == 0 ) {
+ // if the first line, then we add the "latest version"
+ TableItem tableItem = new TableItem(DBGuiAdminDatabase.this.tblModelVersions, SWT.NULL);
+ tableItem.setText(1, "(latest version)");
+ tableItem.setData("name", version.get("name"));
+ tableItem.setData("note", version.get("note"));
+ tableItem.setData("purpose", version.get("purpose"));
+ }
+
+ TableItem tableItem = new TableItem(DBGuiAdminDatabase.this.tblModelVersions, SWT.NULL);
+ tableItem.setText(0, (String)version.get("version"));
+ tableItem.setText(1, new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format((Timestamp)version.get("created_on")));
+ tableItem.setText(2, (String)version.get("created_by"));
+ tableItem.setData("name", version.get("name"));
+ tableItem.setData("note", version.get("note"));
+ tableItem.setData("purpose", version.get("purpose"));
+ }
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "Failed to get model's versions from the database", err);
+ }
+
+ if ( DBGuiAdminDatabase.this.tblModelVersions.getItemCount() != 0 ) {
+ DBGuiAdminDatabase.this.tblModelVersions.setSelection(0);
+ DBGuiAdminDatabase.this.tblModelVersions.notifyListeners(SWT.Selection, new Event()); // calls database.getModelVersions()
+ }
+ }
+ });
+ fd = new FormData();
+ fd.top = new FormAttachment(lblListModels, getDefaultMargin());
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ fd.right = new FormAttachment(100, -getDefaultMargin());
+ fd.bottom = new FormAttachment(100, -getDefaultMargin());
+ this.tblModels.setLayoutData(fd);
+
+ TableColumn colModelName = new TableColumn(this.tblModels, SWT.NONE);
+ colModelName.setText("Model name");
+ colModelName.setWidth(265);
+
+ this.grpModelVersions = new Group(this.compoRightBottom, SWT.SHADOW_ETCHED_IN);
+ this.grpModelVersions.setBackground(GROUP_BACKGROUND_COLOR);
+ this.grpModelVersions.setFont(GROUP_TITLE_FONT);
+ this.grpModelVersions.setText("Versions of selected model: ");
+ fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(50, 5);
+ fd.right = new FormAttachment(100);
+ fd.bottom = new FormAttachment(100);
+ this.grpModelVersions.setLayoutData(fd);
+ this.grpModelVersions.setLayout(new FormLayout());
+
+ this.tblModelVersions = new Table(this.grpModelVersions, SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL);
+ this.tblModelVersions.setBackground(TABLE_BACKGROUND_COLOR);
+ this.tblModelVersions.setLinesVisible(true);
+ this.tblModelVersions.setHeaderVisible(true);
+ this.tblModelVersions.addListener(SWT.Selection, new Listener() {
+ @Override
+ public void handleEvent(Event e) {
+ if ( (DBGuiAdminDatabase.this.tblModelVersions.getSelection() != null) && (DBGuiAdminDatabase.this.tblModelVersions.getSelection().length > 0) && (DBGuiAdminDatabase.this.tblModelVersions.getSelection()[0] != null) ) {
+ DBGuiAdminDatabase.this.txtReleaseNote.setText((String) DBGuiAdminDatabase.this.tblModelVersions.getSelection()[0].getData("note"));
+ DBGuiAdminDatabase.this.txtPurpose.setText((String) DBGuiAdminDatabase.this.tblModelVersions.getSelection()[0].getData("purpose"));
+ DBGuiAdminDatabase.this.txtModelName.setText((String) DBGuiAdminDatabase.this.tblModelVersions.getSelection()[0].getData("name"));
+ DBGuiAdminDatabase.this.btnDoAction.setEnabled(true);
+ } else {
+ DBGuiAdminDatabase.this.btnDoAction.setEnabled(false);
+ }
+ }
+ });
+ this.tblModelVersions.addListener(SWT.MouseDoubleClick, new Listener() {
+ @Override
+ public void handleEvent(Event e) {
+ if ( DBGuiAdminDatabase.this.btnDoAction.getEnabled() )
+ DBGuiAdminDatabase.this.btnDoAction.notifyListeners(SWT.Selection, new Event());
+ }
+ });
+ fd = new FormData();
+ fd.top = new FormAttachment(0, getDefaultMargin());
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ fd.right = new FormAttachment(100, -getDefaultMargin());
+ fd.bottom = new FormAttachment(50);
+ this.tblModelVersions.setLayoutData(fd);
+
+ TableColumn colVersion = new TableColumn(this.tblModelVersions, SWT.NONE);
+ colVersion.setText("#");
+ colVersion.setWidth(40);
+
+ TableColumn colCreatedOn = new TableColumn(this.tblModelVersions, SWT.NONE);
+ colCreatedOn.setText("Date");
+ colCreatedOn.setWidth(120);
+
+ TableColumn colCreatedBy = new TableColumn(this.tblModelVersions, SWT.NONE);
+ colCreatedBy.setText("Author");
+ colCreatedBy.setWidth(150);
+
+ this.lblModelName = new Label(this.grpModelVersions, SWT.NONE);
+ this.lblModelName.setBackground(GROUP_BACKGROUND_COLOR);
+ this.lblModelName.setText("Model name:");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.tblModelVersions, getDefaultMargin());
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ this.lblModelName.setLayoutData(fd);
+
+ this.txtModelName = new Text(this.grpModelVersions, SWT.BORDER);
+ this.txtModelName.setBackground(GROUP_BACKGROUND_COLOR);
+ this.txtModelName.setEnabled(false);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.lblModelName);
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ fd.right = new FormAttachment(100, -getDefaultMargin());
+ this.txtModelName.setLayoutData(fd);
+
+ this.lblPurpose = new Label(this.grpModelVersions, SWT.NONE);
+ this.lblPurpose.setBackground(GROUP_BACKGROUND_COLOR);
+ this.lblPurpose.setText("Purpose:");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.txtModelName, getDefaultMargin());
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ this.lblPurpose.setLayoutData(fd);
+
+ this.txtPurpose = new Text(this.grpModelVersions, SWT.BORDER);
+ this.txtPurpose.setBackground(GROUP_BACKGROUND_COLOR);
+ this.txtPurpose.setEnabled(false);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.lblPurpose);
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ fd.right = new FormAttachment(100, -getDefaultMargin());
+ fd.bottom = new FormAttachment(80, -5);
+ this.txtPurpose.setLayoutData(fd);
+
+ this.lblReleaseNote = new Label(this.grpModelVersions, SWT.NONE);
+ this.lblReleaseNote.setBackground(GROUP_BACKGROUND_COLOR);
+ this.lblReleaseNote.setText("Release note:");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.txtPurpose, getDefaultMargin());
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ this.lblReleaseNote.setLayoutData(fd);
+
+ this.txtReleaseNote = new Text(this.grpModelVersions, SWT.BORDER);
+ this.txtReleaseNote.setBackground(GROUP_BACKGROUND_COLOR);
+ this.txtReleaseNote.setEnabled(false);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.lblReleaseNote);
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ fd.right = new FormAttachment(100, -getDefaultMargin());
+ fd.bottom = new FormAttachment(100, -getDefaultMargin());
+ this.txtReleaseNote.setLayoutData(fd);
+ }
+
+ protected void createGrpActions() {
+ Composite compoBottom = new Composite(this.compoRight, SWT.NONE);
+ compoBottom.setBackground(COMPO_BACKGROUND_COLOR);
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(this.compoRightBottom, 10);
+ fd.bottom = new FormAttachment(100, -10);
+ fd.left = new FormAttachment(0, 10);
+ fd.right = new FormAttachment(100, -10);
+ compoBottom.setLayoutData(fd);
+ compoBottom.setLayout(new FormLayout());
+
+ this.grpActions = new Group(compoBottom, SWT.SHADOW_ETCHED_IN);
+ this.grpActions.setBackground(GROUP_BACKGROUND_COLOR);
+ this.grpActions.setFont(GROUP_TITLE_FONT);
+ this.grpActions.setText("Actions: ");
+ fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ fd.bottom = new FormAttachment(100);
+ this.grpActions.setLayoutData(fd);
+
+ RowLayout rowLayout = new RowLayout();
+ rowLayout.justify = true;
+ this.grpActions.setLayout(rowLayout);
+
+ this.btnCheckStructure = new Button(this.grpActions, SWT.NONE);
+ this.btnCheckStructure.setText("Check structure");
+ this.btnCheckStructure.setToolTipText("Checks that the database has got the right structure.");
+ this.btnCheckStructure.addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent e) { checkStructureCallback(); }
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); }
+ });
+
+ this.btnCheckContent = new Button(this.grpActions, SWT.NONE);
+ this.btnCheckContent.setText("Check content");
+ this.btnCheckContent.setToolTipText("Checks the database content and show up all the errors found.");
+ this.btnCheckContent.addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent e) { checkContentCallback(); }
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); }
+ });
+
+ this.btnDeleteModel = new Button(this.grpActions, SWT.NONE);
+ this.btnDeleteModel.setText("Delete model");
+ this.btnDeleteModel.setToolTipText("Completely delete a whole model and all the components that are not shared with another model\n(shared components will be kept)\n\nBeware, components versions my be recalculated.");
+ this.btnDeleteModel.addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent e) { deleteModelCallback(); }
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); }
+ });
+
+ //this.btnDeleteVersion = new Button(this.grpActions, SWT.NONE);
+ //this.btnDeleteVersion.setText("Delete version");
+ //this.btnDeleteVersion.setToolTipText("Delete the selected version of the model and all the components that are specific to this version.\n(shared components will be kept)\n\nBeware, components versions my be recalculated.");
+ //this.btnDeleteVersion.addSelectionListener(new SelectionListener() {
+ // @Override
+ // public void widgetSelected(SelectionEvent e) { deleteVersionCallback(); }
+ // @Override
+ // public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); }
+ //});
+ }
+
+ /**
+ * Called when the "check structure" button has been pressed
+ */
+ void checkStructureCallback() {
+ try {
+ this.importConnection.checkDatabaseStructure(this);
+ } catch (@SuppressWarnings("unused") Exception ign) {
+ // messages are shown in the checkDatabase method
+ return;
+ }
+ }
+
+
+ /**
+ * Called when the "check content" button has been pressed
+ */
+ void checkContentCallback() {
+ // we remove duplicate rows in view_objects_in_views and view_connections_in views to fix bug of plugin version 2.2
+
+ try {
+ // we start a new transaction
+ this.importConnection.setAutoCommit(false);
+ } catch (SQLException err) {
+ DBGui.popup(Level.ERROR, "Failed to start a new transaction.", err);
+ return;
+ }
+
+ String schemaPrefix = this.importConnection.getDatabaseEntry().getSchemaPrefix();
+ String duplicateObjectsStatus = "";
+ String duplicateConnectionsStatus = "";
+
+ logger.info("Removing view_objects_in_views duplicates ...");
+ try {
+ String table = schemaPrefix+"views_objects_in_view";
+ String request = "DELETE FROM "+table+" WHERE EXISTS (SELECT * FROM "+table+" t2 WHERE "+table+".object_id = t2.object_id AND "+table+".object_version = t2.object_version AND "+table+".view_id = t2.view_id AND "+table+".view_version = t2.view_version AND "+table+".oiv_id > t2.oiv_id)";
+ if ( logger.isTraceSQLEnabled() ) logger.trace(" --> "+request);
+
+ int deletedRows = this.importConnection.executeRequest(request);
+ switch (deletedRows) {
+ case 0: duplicateObjectsStatus = "No duplicate row found in the \"views_objects_in_view\" table."; break;
+ case 1: duplicateObjectsStatus = "1 duplicate row removed from the \"views_objects_in_view\" table."; break;
+ default: duplicateObjectsStatus = deletedRows+" duplicate rows removed from the \"views_objects_in_view\" table.";
+ }
+ } catch (SQLException err) {
+ try {
+ this.importConnection.rollback();
+ this.importConnection.setAutoCommit(true);
+ } catch (SQLException err2) {
+ DBGui.popup(Level.ERROR, "Failed to remove view_objects_in_views duplicates.", err);
+ DBGui.popup(Level.FATAL, "Failed to roll back the transaction. We suggest you close Archi and verify your database manually.", err2);
+ return;
+ }
+
+ DBGui.popup(Level.ERROR, "Failed to remove view_objects_in_views duplicates. The transaction has been rolled back.", err);
+ return;
+ }
+
+ logger.info("Removing view_connections_in_views duplicates ...");
+ try {
+ String table = schemaPrefix+"views_connections_in_view";
+ String request = "DELETE FROM "+table+" WHERE EXISTS (SELECT * FROM "+table+" t2 WHERE "+table+".connection_id = t2.connection_id AND "+table+".connection_version = t2.connection_version AND "+table+".view_id = t2.view_id AND "+table+".view_version = t2.view_version AND "+table+".civ_id > t2.civ_id)";
+
+ if ( logger.isTraceSQLEnabled() ) logger.trace(" --> "+request);
+
+ int deletedRows = this.importConnection.executeRequest(request);
+ switch (deletedRows) {
+ case 0: duplicateConnectionsStatus = "No duplicate row found in the \"views_connections_in_view\" table."; break;
+ case 1: duplicateConnectionsStatus = "1 duplicate row removed from the \"views_connections_in_view\" table."; break;
+ default: duplicateConnectionsStatus = deletedRows+" duplicate rows removed from the \"views_connections_in_view\" table.";
+ }
+ } catch (SQLException err) {
+ try {
+ this.importConnection.rollback();
+ this.importConnection.setAutoCommit(true);
+ } catch (SQLException err2) {
+ DBGui.popup(Level.ERROR, "Failed to remove view_connections_in_views duplicates.", err);
+ DBGui.popup(Level.FATAL, "Failed to roll back the transaction. We suggest you close Archi and verify your database manually.", err2);
+ return;
+ }
+
+ DBGui.popup(Level.ERROR, "Failed to remove view_connections_in_views duplicates. The transaction has been rolled back.", err);
+ return;
+ }
+
+ try {
+ this.importConnection.commit();
+ this.importConnection.setAutoCommit(true);
+ } catch (SQLException err) {
+ DBGui.popup(Level.FATAL, "Failed to commit the transaction. We suggest you close Archi and verify your database manually.", err);
+ return;
+ }
+
+ DBGui.popup(Level.INFO, duplicateObjectsStatus+"\n"+duplicateConnectionsStatus+"\n\nDatabase content successfully checked.");
+ }
+
+ /**
+ * Called when the "delete model" button has been pressed
+ */
+ void deleteModelCallback() {
+ String modelId = (String) DBGuiAdminDatabase.this.tblModels.getSelection()[0].getData("id");
+ String modelName = DBGuiAdminDatabase.this.tblModels.getSelection()[0].getText();
+
+ if ( modelId == null ) {
+ DBGui.popup(Level.ERROR, "Failed to get model ID.");
+ return;
+ }
+
+ if (DBGui.question("You are about to delete the model \""+modelName+"\" from the database.\n\nThis will delete the model as a container. However, the model content (elements, relationships, views, ...) will remain in the database so they can be imported from the database into other models.\n\nPlease note that this action cannot be undone.\n\nDo you confirm the deletion ?") ) {
+ try {
+ int deletedRows = this.importConnection.executeRequest("DELETE FROM "+this.importConnection.getDatabaseEntry().getSchemaPrefix()+"models WHERE id = ?", modelId);
+
+ if (deletedRows == 0)
+ DBGui.popup(Level.WARN,"That's weird, no model with ID \""+modelId+"\" has been found in the database.");
+ else {
+ connectedToDatabase(false);
+ DBGui.popup(Level.INFO, String.valueOf(deletedRows)+" version"+((deletedRows == 1)?"":"s")+" of the model \""+modelName+"\" "+((deletedRows == 1)?"has":"have")+" been deleted from the database.");
+ }
+ } catch (SQLException err) {
+ try {
+ this.importConnection.rollback();
+ this.importConnection.setAutoCommit(true);
+ } catch (SQLException err2) {
+ DBGui.popup(Level.ERROR, "Failed to delete model from the database.", err);
+ DBGui.popup(Level.FATAL, "Failed to roll back the transaction. We suggest you close Archi and verify your database manually.", err2);
+ return;
+ }
+ DBGui.popup(Level.ERROR, "Failed to delete model from the database. The transaction has been rolled back.", err);
+ }
+
+ } else
+ DBGui.popup(Level.INFO, "Delete canceled by user.");
+ }
+
+ ///**
+ // * Called when the "delete version" button has been pressed
+ // */
+ //@SuppressWarnings("static-method")
+ //void deleteVersionCallback() {
+ // DBGui.popup(Level.INFO, "Not yet implemented.");
+ //}
+}
diff --git a/sources/src/org/archicontribs/database/GUI/DBGuiComponentHistory.java b/sources/src/org/archicontribs/database/GUI/DBGuiComponentHistory.java
new file mode 100644
index 00000000..d86d975c
--- /dev/null
+++ b/sources/src/org/archicontribs/database/GUI/DBGuiComponentHistory.java
@@ -0,0 +1,342 @@
+/**
+ * This program and the accompanying materials
+ * are made available under the terms of the License
+ * which accompanies this distribution in the file LICENSE.txt
+ */
+
+package org.archicontribs.database.GUI;
+
+import java.sql.Timestamp;
+import java.util.Calendar;
+
+import org.apache.log4j.Level;
+import org.archicontribs.database.DBLogger;
+import org.archicontribs.database.DBPlugin;
+import org.archicontribs.database.connection.DBDatabaseExportConnection;
+import org.archicontribs.database.connection.DBDatabaseImportConnection;
+import org.archicontribs.database.connection.DBSelect;
+import org.archicontribs.database.data.DBImportMode;
+import org.archicontribs.database.model.commands.DBImportElementFromIdCommand;
+import org.archicontribs.database.model.commands.DBImportFolderFromIdCommand;
+import org.archicontribs.database.model.commands.DBImportRelationshipFromIdCommand;
+import org.archicontribs.database.model.commands.DBImportViewFromIdCommand;
+import org.archicontribs.database.model.commands.IDBImportCommand;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.CommandStack;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.layout.FormLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+import org.archicontribs.database.model.DBArchimateModel;
+import org.archicontribs.database.model.DBMetadata;
+
+import com.archimatetool.canvas.model.ICanvasModel;
+import com.archimatetool.model.IArchimateDiagramModel;
+import com.archimatetool.model.IArchimateElement;
+import com.archimatetool.model.IArchimateModelObject;
+import com.archimatetool.model.IArchimateRelationship;
+import com.archimatetool.model.IDiagramModelConnection;
+import com.archimatetool.model.IDiagramModelObject;
+import com.archimatetool.model.IFolder;
+import com.archimatetool.model.ISketchModel;
+
+/**
+ * This class manages the GUI that shows a component history
+ *
+ * @author Herve Jouin
+ */
+public class DBGuiComponentHistory extends DBGui {
+ @SuppressWarnings("hiding")
+ private static final DBLogger logger = new DBLogger(DBGuiComponentHistory.class);
+
+ IArchimateModelObject selectedComponent = null;
+
+ private Label lblVersions;
+
+ Button btnImportDatabaseVersion;
+ Button btnExportModelVersion;
+ Label lblCompareComponents;
+
+ Tree tblContent;
+ Table tblVersions;
+
+ /**
+ * Creates the GUI to show the differences between a component in the model and the database
+ * @param component
+ * @throws Exception
+ */
+ public DBGuiComponentHistory(IArchimateModelObject component) throws Exception {
+ super("Component history");
+ this.selectedComponent = component;
+
+ this.includeNeo4j = false;
+
+ ((DBArchimateModel)this.selectedComponent.getArchimateModel()).countObject(component, true);
+
+ if ( logger.isDebugEnabled() ) logger.debug("Setting up GUI for showing history of "+DBMetadata.getDBMetadata(component).getDebugName()+" (plugin version "+DBPlugin.pluginVersion.toString()+").");
+
+ setCompoRight();
+ this.compoRightBottom.setVisible(true);
+ this.compoRightBottom.layout();
+
+
+ createAction(ACTION.One, "Component history");
+ setActiveAction(ACTION.One);
+
+ getDatabases(false);
+ }
+
+ /**
+ * creates the composites where the user can check the components to export
+ */
+ protected void setCompoRight() {
+ Group grpComponents = new Group(this.compoRightBottom, SWT.NONE);
+ grpComponents.setBackground(GROUP_BACKGROUND_COLOR);
+ grpComponents.setFont(GROUP_TITLE_FONT);
+ grpComponents.setText("History of "+this.selectedComponent.getClass().getSimpleName() + "\"" + this.selectedComponent.getName() + "\"");
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ fd.bottom = new FormAttachment(100, 0);
+ grpComponents.setLayoutData(fd);
+ grpComponents.setLayout(new FormLayout());
+
+ this.lblVersions = new Label(grpComponents, SWT.NONE);
+ this.lblVersions.setBackground(GROUP_BACKGROUND_COLOR);
+ this.lblVersions.setText("Versions:");
+ fd = new FormData();
+ fd.top = new FormAttachment(0, 10);
+ fd.left = new FormAttachment(0, 10);
+ fd.right = new FormAttachment(100, -10);
+ this.lblVersions.setLayoutData(fd);
+
+ this.tblVersions = new Table(grpComponents, SWT.BORDER | SWT.FULL_SELECTION);
+ this.tblVersions.setBackground(TABLE_BACKGROUND_COLOR);
+ this.tblVersions.setHeaderVisible(true);
+ this.tblVersions.setLinesVisible(true);
+ this.tblVersions.addListener(SWT.Selection, new Listener() {
+ @Override
+ public void handleEvent(Event e) {
+ Boolean areIdentical = fillInCompareTable(DBGuiComponentHistory.this.tblContent, DBGuiComponentHistory.this.selectedComponent, Integer.valueOf(DBGuiComponentHistory.this.tblVersions.getSelection()[0].getText(0)));
+ if ( areIdentical == null )
+ DBGuiComponentHistory.this.lblCompareComponents.setText("Versions:");
+ else {
+ if ( areIdentical.booleanValue() )
+ DBGuiComponentHistory.this.lblCompareComponents.setText("Versions are identical");
+ else
+ DBGuiComponentHistory.this.lblCompareComponents.setText("Versions are different (check highlighted lines):");
+ DBGuiComponentHistory.this.btnExportModelVersion.setEnabled(!areIdentical.booleanValue() && DBGuiComponentHistory.this.tblVersions.getSelectionIndex() == 0);
+ DBGuiComponentHistory.this.btnImportDatabaseVersion.setEnabled(!areIdentical.booleanValue());
+ }
+ }
+ });
+ fd = new FormData();
+ fd.top = new FormAttachment(this.lblVersions, 10);
+ fd.left = new FormAttachment(20, 0);
+ fd.right = new FormAttachment(80, 0);
+ fd.bottom = new FormAttachment(30, 0);
+ this.tblVersions.setLayoutData(fd);
+
+ TableColumn colVersion = new TableColumn(this.tblVersions, SWT.NONE);
+ colVersion.setWidth(47);
+ colVersion.setText("Version");
+
+ TableColumn colCreatedBy = new TableColumn(this.tblVersions, SWT.NONE);
+ colCreatedBy.setWidth(121);
+ colCreatedBy.setText("Created by");
+
+ TableColumn colCreatedOn = new TableColumn(this.tblVersions, SWT.NONE);
+ colCreatedOn.setWidth(145);
+ colCreatedOn.setText("Created on");
+
+ this.lblCompareComponents = new Label(grpComponents, SWT.NONE);
+ this.lblCompareComponents.setBackground(GROUP_BACKGROUND_COLOR);
+ this.lblCompareComponents.setText("Versions:");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.tblVersions, 20);
+ fd.left = new FormAttachment(0, 10);
+ fd.right = new FormAttachment(100, -10);
+ this.lblCompareComponents.setLayoutData(fd);
+
+ this.tblContent = new Tree(grpComponents, SWT.BORDER | SWT.FULL_SELECTION | SWT.HIDE_SELECTION);
+ this.tblContent.setBackground(TABLE_BACKGROUND_COLOR);
+ this.tblContent.setHeaderVisible(true);
+ this.tblContent.setLinesVisible(true);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.lblCompareComponents, 10);
+ fd.left = new FormAttachment(0, 10);
+ fd.right = new FormAttachment(100, -10);
+ fd.bottom = new FormAttachment(100, -50);
+ this.tblContent.setLayoutData(fd);
+
+ TreeColumn colItem = new TreeColumn(this.tblContent, SWT.NONE);
+ colItem.setWidth(120);
+ colItem.setText("Items");
+
+ TreeColumn colYourVersion = new TreeColumn(this.tblContent, SWT.NONE);
+ colYourVersion.setWidth(220);
+ colYourVersion.setText("Your version");
+
+ TreeColumn colDatabaseVersion = new TreeColumn(this.tblContent, SWT.NONE);
+ colDatabaseVersion.setWidth(220);
+ colDatabaseVersion.setText("Database version");
+
+ this.btnImportDatabaseVersion = new Button(grpComponents, SWT.NONE);
+ this.btnImportDatabaseVersion.setImage(IMPORT_FROM_DATABASE_IMAGE);
+ this.btnImportDatabaseVersion.setText("Import database version");
+ this.btnImportDatabaseVersion.setEnabled(false);
+ this.btnImportDatabaseVersion.addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ try (DBDatabaseImportConnection importConnection = new DBDatabaseImportConnection(getDatabaseConnection())) {
+ IArchimateModelObject importedComponent = DBGuiComponentHistory.this.selectedComponent;
+ DBArchimateModel importedModel = (DBArchimateModel)importedComponent.getArchimateModel();
+ IFolder parentFolder = (IFolder)importedComponent.eContainer();
+ String id = importedComponent.getId();
+ int version = Integer.valueOf(DBGuiComponentHistory.this.tblVersions.getSelection()[0].getText(0)).intValue();
+ IDBImportCommand command = null;
+
+ if ( importedComponent instanceof IArchimateElement )
+ command = new DBImportElementFromIdCommand(importConnection, importedModel, null, parentFolder, id, version, DBImportMode.forceSharedMode, true);
+ else if ( importedComponent instanceof IArchimateRelationship )
+ command = new DBImportRelationshipFromIdCommand(importConnection, importedModel, null, parentFolder, id, version, DBImportMode.forceSharedMode);
+ else if ( importedComponent instanceof IFolder )
+ command = new DBImportFolderFromIdCommand(importConnection, importedModel, parentFolder, id, version, DBImportMode.forceSharedMode);
+ else if ( importedComponent instanceof IArchimateDiagramModel || importedComponent instanceof ICanvasModel || importedComponent instanceof ISketchModel )
+ command = new DBImportViewFromIdCommand(importConnection, importedModel, parentFolder, id, version, DBImportMode.forceSharedMode, true);
+ else
+ throw new Exception("Cannot import components of class "+importedComponent.getClass().getSimpleName());
+
+ if ( command.getException() != null )
+ throw command.getException();
+ command.execute();
+ if ( command.getException() != null )
+ throw command.getException();
+ ((CommandStack)importedModel.getAdapter(CommandStack.class)).execute((Command) command);
+
+ popup(Level.INFO, "The current version of the component has been replaced by the selected version from the database.");
+
+ connectedToDatabase(true);
+
+ } catch (Exception err) {
+ popup(Level.ERROR, "Failed to import component.", err);
+ }
+ }
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); }
+ });
+ fd = new FormData();
+ fd.top = new FormAttachment(this.tblContent, 10);
+ fd.right = new FormAttachment(100, -10);
+ this.btnImportDatabaseVersion.setLayoutData(fd);
+
+ this.btnExportModelVersion = new Button(grpComponents, SWT.NONE);
+ this.btnExportModelVersion.setImage(EXPORT_TO_DATABASE_IMAGE);
+ this.btnExportModelVersion.setText("Export your version to the database");
+ this.btnExportModelVersion.setEnabled(false);
+ this.btnExportModelVersion.addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ try (DBDatabaseExportConnection exportConnection = new DBDatabaseExportConnection(getDatabaseConnection())) {
+ ((DBArchimateModel)DBGuiComponentHistory.this.selectedComponent.getArchimateModel()).getCurrentVersion().setTimestamp(new Timestamp(Calendar.getInstance().getTime().getTime()));
+ exportConnection.exportEObject(DBGuiComponentHistory.this.selectedComponent);
+
+ popup(Level.INFO, "The component has been updated in the database.");
+ connectedToDatabase(true);
+ } catch (Exception err) {
+ popup(Level.ERROR, "Failed to export component.", err);
+ }
+ }
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); }
+ });
+ fd = new FormData();
+ fd.top = new FormAttachment(this.tblContent, 10);
+ fd.right = new FormAttachment(this.btnImportDatabaseVersion, -10);
+ this.btnExportModelVersion.setLayoutData(fd);
+ }
+
+ /**
+ * Called when a database is selected in the comboDatabases and that the connection to this database succeeded.
+ */
+ @Override
+ protected void connectedToDatabase(boolean forceCheck) {
+ this.dialog.setCursor(CURSOR_ARROW);
+
+ try (DBDatabaseExportConnection exportConnection = new DBDatabaseExportConnection(getDatabaseConnection()) ) {
+ exportConnection.getVersionFromDatabase(this.selectedComponent);
+ } catch (Exception e) {
+ popup(Level.FATAL, "Cannot get version of selected component from the database.", e);
+ return ;
+ }
+
+ // if everything goes well, then we search for all the versions of the component
+ if ( logger.isDebugEnabled() ) logger.debug("Searching for all versions of the component");
+
+ this.tblVersions.removeAll();
+ this.tblContent.removeAll();
+ this.btnImportDatabaseVersion.setEnabled(false);
+ this.btnExportModelVersion.setEnabled(false);
+
+ String tableName = null;
+ if ( this.selectedComponent instanceof IArchimateElement )
+ tableName = "elements";
+ else if ( this.selectedComponent instanceof IArchimateRelationship )
+ tableName = "relationships";
+ else if ( this.selectedComponent instanceof IArchimateDiagramModel || this.selectedComponent instanceof ICanvasModel || this.selectedComponent instanceof ISketchModel )
+ tableName = "views";
+ else if ( this.selectedComponent instanceof IFolder )
+ tableName = "folders";
+ else if ( this.selectedComponent instanceof IDiagramModelObject )
+ tableName = "views_objects";
+ else if ( this.selectedComponent instanceof IDiagramModelConnection )
+ tableName = "views_connections";
+ else {
+ popup(Level.FATAL, "Cannot get history for components of class "+this.selectedComponent.getClass().getSimpleName());
+ return ;
+ }
+
+ try ( DBSelect result = new DBSelect(getDatabaseConnection().getDatabaseEntry().getName(), getDatabaseConnection().getConnection(),"SELECT version, created_by, created_on FROM "+this.selectedDatabase.getSchemaPrefix()+tableName+" where id = ? ORDER BY version DESC", this.selectedComponent.getId()) ) {
+ while ( result.next() ) {
+ TableItem tableItem = new TableItem(this.tblVersions, SWT.NULL);
+ tableItem.setText(0, String.valueOf(result.getInt("version")));
+ tableItem.setText(1, result.getString("created_by"));
+ tableItem.setText(2, result.getTimestamp("created_on").toString());
+ }
+ } catch (Exception err) {
+ this.tblVersions.removeAll();
+ popup(Level.FATAL, "Failed to search component versions in the database.", err);
+ }
+
+ if ( this.tblVersions.getItemCount() > 1 ) {
+ this.lblVersions.setText(this.tblVersions.getItemCount()+" versions have been found in the database:");
+ } else {
+ this.lblVersions.setText(this.tblVersions.getItemCount()+" version has been found in the database:");
+ }
+
+ if ( this.tblVersions.getItemCount() != 0 ) {
+ this.tblVersions.select(0);
+ this.tblVersions.notifyListeners(SWT.Selection, new Event());
+ }
+ }
+
+ @Override
+ protected void notConnectedToDatabase() {
+ this.lblVersions.setText("");
+ this.tblContent.removeAll();
+ this.tblVersions.removeAll();
+ }
+}
diff --git a/sources/src/org/archicontribs/database/GUI/DBGuiExportModel.java b/sources/src/org/archicontribs/database/GUI/DBGuiExportModel.java
new file mode 100644
index 00000000..adaa1678
--- /dev/null
+++ b/sources/src/org/archicontribs/database/GUI/DBGuiExportModel.java
@@ -0,0 +1,3025 @@
+/**
+ * This program and the accompanying materials
+ * are made available under the terms of the License
+ * which accompanies this distribution in the file LICENSE.txt
+ */
+
+package org.archicontribs.database.GUI;
+
+import java.lang.reflect.Method;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.text.SimpleDateFormat;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.log4j.Level;
+import org.archicontribs.database.DBLogger;
+import org.archicontribs.database.DBPlugin;
+import org.archicontribs.database.DBPlugin.CONFLICT_CHOICE;
+import org.archicontribs.database.connection.DBDatabaseExportConnection;
+import org.archicontribs.database.connection.DBDatabaseImportConnection;
+import org.archicontribs.database.data.DBChecksum;
+import org.archicontribs.database.data.DBCompoundCommand;
+import org.archicontribs.database.data.DBImportMode;
+import org.archicontribs.database.model.DBArchimateModel;
+import org.archicontribs.database.model.DBMetadata;
+import org.archicontribs.database.model.DBMetadata.DATABASE_STATUS;
+import org.archicontribs.database.model.commands.DBDeleteDiagramConnectionCommand;
+import org.archicontribs.database.model.commands.DBDeleteDiagramObjectCommand;
+import org.archicontribs.database.model.commands.DBImportElementFromIdCommand;
+import org.archicontribs.database.model.commands.DBImportFolderFromIdCommand;
+import org.archicontribs.database.model.commands.DBImportRelationshipFromIdCommand;
+import org.archicontribs.database.model.commands.DBImportViewConnectionFromIdCommand;
+import org.archicontribs.database.model.commands.DBImportViewFromIdCommand;
+import org.archicontribs.database.model.commands.DBImportViewObjectFromIdCommand;
+import org.archicontribs.database.model.commands.DBResolveConnectionsCommand;
+import org.archicontribs.database.model.commands.DBResolveRelationshipsCommand;
+import org.archicontribs.database.model.commands.DBSetFolderToLastKnownCommand;
+import org.archicontribs.database.model.commands.IDBCommand;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gef.commands.CommandStack;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.layout.FormLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+
+import com.archimatetool.editor.model.IArchiveManager;
+import com.archimatetool.editor.model.commands.DeleteArchimateElementCommand;
+import com.archimatetool.editor.model.commands.DeleteArchimateRelationshipCommand;
+import com.archimatetool.editor.model.commands.DeleteDiagramModelCommand;
+import com.archimatetool.editor.model.commands.DeleteFolderCommand;
+import com.archimatetool.model.IArchimateElement;
+import com.archimatetool.model.IArchimateRelationship;
+import com.archimatetool.model.IDiagramModel;
+import com.archimatetool.model.IDiagramModelConnection;
+import com.archimatetool.model.IDiagramModelObject;
+import com.archimatetool.model.IFolder;
+import com.archimatetool.model.IIdentifier;
+import com.archimatetool.model.IProfile;
+
+/**
+ * This class holds the methods requires to export a model in a database
+ *
+ * @author Herve Jouin
+ */
+public class DBGuiExportModel extends DBGui {
+ @SuppressWarnings("hiding")
+ private static final DBLogger logger = new DBLogger(DBGuiExportModel.class);
+
+ DBArchimateModel exportedModel = null;
+
+ Group grpComponents;
+ Group grpModelVersions;
+
+ HashMap newDatabaseComponents;
+
+ private CommandStack stack;
+ DBDatabaseExportConnection exportConnection;
+
+ private final String ZERO = toString(0);
+
+ /**
+ * Creates the GUI to export components and model
+ * @param model to export
+ * @param title of the dialog
+ * @throws Exception
+ */
+ public DBGuiExportModel(DBArchimateModel model, String title) throws Exception {
+ // We call the DBGui constructor that will create the underlying form and expose the compoRight, compoRightUp and compoRightBottom composites
+ super(title);
+ // We reference the exported model
+ this.exportedModel = model;
+ this.includeNeo4j = true;
+
+ if ( logger.isDebugEnabled() ) logger.debug("Setting up GUI for exporting model \""+this.exportedModel.getName()+"\" (plugin version "+DBPlugin.pluginVersion.toString()+").");
+
+ createGrpComponents();
+ createGrpModel();
+ this.compoRightBottom.setVisible(true);
+ this.compoRightBottom.layout();
+
+ createAction(ACTION.One, "1 - Confirm export");
+ createAction(ACTION.Two, "2 - Export components");
+ createAction(ACTION.Three, "3 - Status");
+
+ // we show an arrow in front of the first action
+ setActiveAction(ACTION.One);
+
+ // if the user select the "Export" button --> call the exportComponents() method
+ setBtnAction("Export", new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ export();
+ }
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); }
+ });
+ this.btnDoAction.setEnabled(false);
+
+ // We rename the close button to "Cancel"
+ this.btnClose.setText("Cancel");
+
+ // We activate the Eclipse Help framework
+ setHelpHref("exportModel.html");
+
+ // we get the model'sstack that is used for undo / redo
+ this.stack = (CommandStack)this.exportedModel.getAdapter(CommandStack.class);
+ }
+
+ @Override
+ public void run() {
+ super.run();
+
+ try {
+ this.exportedModel.countAllObjects();
+ } catch (Exception err) {
+ popup(Level.ERROR, "Failed to count model's components", err);
+ return;
+ } finally {
+ closeMessage();
+ }
+
+ if ( logger.isDebugEnabled() ) logger.debug("The model has got "+this.exportedModel.getAllElements().size()+" elements and "+this.exportedModel.getAllRelationships().size()+" relationships and "+this.exportedModel.getAllFolders().size()+" folders and "+this.exportedModel.getAllViews().size()+" views and "+this.exportedModel.getAllViewObjects().size()+" objects and "+this.exportedModel.getAllViewConnections().size()+" connections.");
+
+ this.txtTotalProfiles.setText(toString(this.exportedModel.getProfiles().size()));
+ this.txtTotalElements.setText(toString(this.exportedModel.getAllElements().size()));
+ this.txtTotalRelationships.setText(toString(this.exportedModel.getAllRelationships().size()));
+ this.txtTotalFolders.setText(toString(this.exportedModel.getAllFolders().size()));
+ this.txtTotalViews.setText(toString(this.exportedModel.getAllViews().size()));
+ this.txtTotalViewObjects.setText(toString(this.exportedModel.getAllViewObjects().size()));
+ this.txtTotalViewConnections.setText(toString(this.exportedModel.getAllViewConnections().size()));
+ this.txtTotalImages.setText(toString(this.exportedModel.getAllImagePaths().size()));
+
+ try {
+ getDatabases(true, this.exportedModel.getImportDatabaseId(), null);
+ } catch (Exception err) {
+ popup(Level.ERROR, "Failed to get the databases.", err);
+ return;
+ }
+ }
+
+ /**
+ * Creates a group displaying details about the the model in the database (list of existing versions)
+ */
+ private void createGrpModel() {
+ this.grpModelVersions = new Group(this.compoRightBottom, SWT.NONE);
+ this.grpModelVersions.setBackground(GROUP_BACKGROUND_COLOR);
+ this.grpModelVersions.setText("Your model versions: ");
+ this.grpModelVersions.setFont(GROUP_TITLE_FONT);
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ fd.bottom = new FormAttachment(this.grpComponents, -getDefaultMargin());
+ this.grpModelVersions.setLayoutData(fd);
+ this.grpModelVersions.setLayout(new FormLayout());
+
+ this.tblModelVersions = new Table(this.grpModelVersions, SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL);
+ this.tblModelVersions.setBackground(TABLE_BACKGROUND_COLOR);
+ this.tblModelVersions.setLinesVisible(true);
+ this.tblModelVersions.setHeaderVisible(true);
+ this.tblModelVersions.addListener(SWT.Selection, new Listener() {
+ @Override
+ public void handleEvent(Event e) {
+ boolean canExport = (DBGuiExportModel.this.tblModelVersions.getSelection() != null) && (DBGuiExportModel.this.tblModelVersions.getSelection().length > 0) && (DBGuiExportModel.this.tblModelVersions.getSelection()[0] != null);
+
+ DBGuiExportModel.this.btnDoAction.setEnabled(canExport);
+ DBGuiExportModel.this.btnCompareModelToDatabase.setEnabled(canExport);
+
+ if ( canExport ) {
+ boolean canChangeMetaData = ((DBGuiExportModel.this.exportConnection != null) && (DBGuiExportModel.this.tblModelVersions.getSelection()[0] == DBGuiExportModel.this.tblModelVersions.getItem(0)));
+
+ DBGuiExportModel.this.txtReleaseNote.setEnabled(canChangeMetaData);
+ DBGuiExportModel.this.txtPurpose.setEnabled(canChangeMetaData);
+ DBGuiExportModel.this.txtModelName.setEnabled(canChangeMetaData);
+ DBGuiExportModel.this.btnDoAction.setEnabled(canChangeMetaData);
+ DBGuiExportModel.this.btnCompareModelToDatabase.setEnabled(canChangeMetaData);
+
+ DBGuiExportModel.this.txtReleaseNote.setText((String) DBGuiExportModel.this.tblModelVersions.getSelection()[0].getData("note"));
+ DBGuiExportModel.this.txtPurpose.setText((String) DBGuiExportModel.this.tblModelVersions.getSelection()[0].getData("purpose"));
+ DBGuiExportModel.this.txtModelName.setText((String) DBGuiExportModel.this.tblModelVersions.getSelection()[0].getData("name"));
+ }
+ }
+ });
+ fd = new FormData();
+ fd.top = new FormAttachment(0, getDefaultMargin());
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ fd.right = new FormAttachment(40, -getDefaultMargin());
+ fd.bottom = new FormAttachment(100, -getDefaultMargin());
+ this.tblModelVersions.setLayoutData(fd);
+
+ TableColumn colVersion = new TableColumn(this.tblModelVersions, SWT.NONE);
+ colVersion.setText("#");
+ colVersion.setWidth(40);
+
+ TableColumn colCreatedOn = new TableColumn(this.tblModelVersions, SWT.NONE);
+ colCreatedOn.setText("Created on");
+ colCreatedOn.setWidth(120);
+
+ TableColumn colCreatedBy = new TableColumn(this.tblModelVersions, SWT.NONE);
+ colCreatedBy.setText("Created by");
+ colCreatedBy.setWidth(125);
+
+ Label lblModelName = new Label(this.grpModelVersions, SWT.NONE);
+ lblModelName.setBackground(GROUP_BACKGROUND_COLOR);
+ lblModelName.setText("Model name:");
+ fd = new FormData();
+ fd.top = new FormAttachment(0, getDefaultMargin());
+ fd.left = new FormAttachment(40, 0);
+ lblModelName.setLayoutData(fd);
+
+ this.txtModelName = new Text(this.grpModelVersions, SWT.BORDER);
+ this.txtModelName.setText(this.exportedModel.getName());
+ this.txtModelName.setEnabled(false);
+ fd = new FormData();
+ fd.top = new FormAttachment(lblModelName, 0, SWT.CENTER);
+ fd.left = new FormAttachment(lblModelName, getDefaultMargin());
+ fd.right = new FormAttachment(100, -getDefaultMargin());
+ this.txtModelName.setLayoutData(fd);
+
+ Label lblPurpose = new Label(this.grpModelVersions, SWT.NONE);
+ lblPurpose.setBackground(GROUP_BACKGROUND_COLOR);
+ lblPurpose.setText("Purpose:");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.txtModelName, getDefaultMargin());
+ fd.left = new FormAttachment(lblModelName, 0, SWT.LEFT);
+ lblPurpose.setLayoutData(fd);
+
+ this.txtPurpose = new Text(this.grpModelVersions, (DBPlugin.isWindowsOperatingSystem() ? SWT.WRAP : SWT.MULTI) | SWT.BORDER | SWT.V_SCROLL);
+ this.txtPurpose.setText(this.exportedModel.getPurpose());
+ this.txtPurpose.setEnabled(false);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.txtModelName, 5);
+ fd.left = new FormAttachment(this.txtModelName, 0, SWT.LEFT);
+ fd.right = new FormAttachment(100, -getDefaultMargin());
+ fd.bottom = new FormAttachment(55, -5);
+ this.txtPurpose.setLayoutData(fd);
+
+ Label lblReleaseNote = new Label(this.grpModelVersions, SWT.NONE);
+ lblReleaseNote.setBackground(GROUP_BACKGROUND_COLOR);
+ lblReleaseNote.setText("Release note:");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.txtPurpose, getDefaultMargin());
+ fd.left = new FormAttachment(lblPurpose, 0, SWT.LEFT);
+ lblReleaseNote.setLayoutData(fd);
+
+ this.txtReleaseNote = new Text(this.grpModelVersions, (DBPlugin.isWindowsOperatingSystem() ? SWT.WRAP : SWT.MULTI) | SWT.BORDER | SWT.V_SCROLL);
+ //txtReleaseNote.setBackground(GROUP_BACKGROUND_COLOR);
+ this.txtReleaseNote.setEnabled(false);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.txtPurpose, 5);
+ fd.left = new FormAttachment(this.txtModelName, 0, SWT.LEFT);
+ fd.right = new FormAttachment(100, -getDefaultMargin());
+ fd.bottom = new FormAttachment(100, -getDefaultMargin());
+ this.txtReleaseNote.setLayoutData(fd);
+ }
+
+ /**
+ * Creates a group displaying details about the exported model's components:
+ * - total number
+ * - number sync'ed with the database
+ * - number that do not exist in the database
+ * - number that exist in the database but with different values.
+ */
+ private void createGrpComponents() {
+ this.grpComponents = new Group(this.compoRightBottom, SWT.SHADOW_ETCHED_IN);
+ this.grpComponents.setBackground(GROUP_BACKGROUND_COLOR);
+ this.grpComponents.setFont(GROUP_TITLE_FONT);
+ this.grpComponents.setText("Your model's components: ");
+
+ // we calculate the required height
+ int requiredHeight = 11 * (getDefaultLabelHeight() + getDefaultMargin()) + 2 * getDefaultMargin();
+
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(100, -requiredHeight);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ fd.bottom = new FormAttachment(100);
+ this.grpComponents.setLayoutData(fd);
+ this.grpComponents.setLayout(new FormLayout());
+
+ Label lblProfiles = new Label(this.grpComponents, SWT.NONE);
+ lblProfiles.setBackground(GROUP_BACKGROUND_COLOR);
+ lblProfiles.setText("Specializations:");
+ fd = new FormData();
+ fd.top = new FormAttachment(0, 2*getDefaultLabelHeight()+getDefaultMargin());
+ fd.left = new FormAttachment(0, 30);
+ lblProfiles.setLayoutData(fd);
+
+ Label lblElements = new Label(this.grpComponents, SWT.NONE);
+ lblElements.setBackground(GROUP_BACKGROUND_COLOR);
+ lblElements.setText("Elements:");
+ fd = new FormData();
+ fd.top = new FormAttachment(lblProfiles, getDefaultMargin());
+ fd.left = new FormAttachment(0, 30);
+ lblElements.setLayoutData(fd);
+
+ Label lblRelationships = new Label(this.grpComponents, SWT.NONE);
+ lblRelationships.setBackground(GROUP_BACKGROUND_COLOR);
+ lblRelationships.setText("Relationships:");
+ fd = new FormData();
+ fd.top = new FormAttachment(lblElements, getDefaultMargin());
+ fd.left = new FormAttachment(0, 30);
+ lblRelationships.setLayoutData(fd);
+
+ Label lblFolders = new Label(this.grpComponents, SWT.NONE);
+ lblFolders.setBackground(GROUP_BACKGROUND_COLOR);
+ lblFolders.setText("Folders:");
+ fd = new FormData();
+ fd.top = new FormAttachment(lblRelationships, getDefaultMargin());
+ fd.left = new FormAttachment(0, 30);
+ lblFolders.setLayoutData(fd);
+
+ Label lblViews = new Label(this.grpComponents, SWT.NONE);
+ lblViews.setBackground(GROUP_BACKGROUND_COLOR);
+ lblViews.setText("Views:");
+ fd = new FormData();
+ fd.top = new FormAttachment(lblFolders, getDefaultMargin());
+ fd.left = new FormAttachment(0, 30);
+ lblViews.setLayoutData(fd);
+
+ Label lblViewObjects = new Label(this.grpComponents, SWT.NONE);
+ lblViewObjects.setBackground(GROUP_BACKGROUND_COLOR);
+ lblViewObjects.setText("Objects:");
+ fd = new FormData();
+ fd.top = new FormAttachment(lblViews, getDefaultMargin());
+ fd.left = new FormAttachment(0, 30);
+ lblViewObjects.setLayoutData(fd);
+
+ Label lblViewConnections = new Label(this.grpComponents, SWT.NONE);
+ lblViewConnections.setBackground(GROUP_BACKGROUND_COLOR);
+ lblViewConnections.setText("Connections:");
+ fd = new FormData();
+ fd.top = new FormAttachment(lblViewObjects, getDefaultMargin());
+ fd.left = new FormAttachment(0, 30);
+ lblViewConnections.setLayoutData(fd);
+
+ Label lblImages = new Label(this.grpComponents, SWT.NONE);
+ lblImages.setBackground(GROUP_BACKGROUND_COLOR);
+ lblImages.setText("Images:");
+ fd = new FormData();
+ fd.top = new FormAttachment(lblViewConnections, getDefaultMargin());
+ fd.left = new FormAttachment(0, 30);
+ lblImages.setLayoutData(fd);
+
+ /* * * * * */
+
+ this.lblTotal = new Label(this.grpComponents, SWT.CENTER);
+ this.lblTotal.setBackground(GROUP_BACKGROUND_COLOR);
+ this.lblTotal.setText("Total");
+ fd = new FormData();
+ fd.top = new FormAttachment(0, getDefaultLabelHeight());
+ fd.left = new FormAttachment(20, 0);
+ fd.right = new FormAttachment(28, 0);
+ this.lblTotal.setLayoutData(fd);
+
+ this.lblModel = new Label(this.grpComponents, SWT.CENTER);
+ this.lblModel.setBackground(GROUP_BACKGROUND_COLOR);
+ this.lblModel.setText("Archi");
+ fd = new FormData();
+ fd.top = new FormAttachment(0, -5);
+ fd.left = new FormAttachment(33, 0);
+ fd.right = new FormAttachment(57, 0);
+ this.lblModel.setLayoutData(fd);
+
+ this.lblModelNew = new Label(this.grpComponents, SWT.CENTER);
+ this.lblModelNew.setBackground(GROUP_BACKGROUND_COLOR);
+ this.lblModelNew.setText("New");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.lblTotal, 0, SWT.TOP);
+ fd.left = new FormAttachment(33, 0);
+ fd.right = new FormAttachment(41, -2);
+ this.lblModelNew.setLayoutData(fd);
+
+ this.lblModelUpdated = new Label(this.grpComponents, SWT.CENTER);
+ this.lblModelUpdated.setBackground(GROUP_BACKGROUND_COLOR);
+ this.lblModelUpdated.setText("Updated");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.lblTotal, 0, SWT.TOP);
+ fd.left = new FormAttachment(41, 1);
+ fd.right = new FormAttachment(49, -1);
+ this.lblModelUpdated.setLayoutData(fd);
+
+ this.lblModelDeleted = new Label(this.grpComponents, SWT.CENTER);
+ this.lblModelDeleted.setBackground(GROUP_BACKGROUND_COLOR);
+ this.lblModelDeleted.setText("Deleted");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.lblTotal, 0, SWT.TOP);
+ fd.left = new FormAttachment(49, 2);
+ fd.right = new FormAttachment(57, 0);
+ this.lblModelDeleted.setLayoutData(fd);
+
+ this.modelHorizontalSeparator = new Label(this.grpComponents, SWT.HORIZONTAL | SWT.SEPARATOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.lblModel, 2);
+ fd.left = new FormAttachment(this.lblModelNew, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblModelDeleted, 0, SWT.RIGHT);
+ this.modelHorizontalSeparator.setLayoutData(fd);
+
+ this.modelVerticalSeparatorLeft = new Label(this.grpComponents, SWT.VERTICAL | SWT.SEPARATOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.modelHorizontalSeparator, -4, SWT.TOP);
+ fd.bottom = new FormAttachment(this.modelHorizontalSeparator, 4, SWT.BOTTOM);
+ fd.left = new FormAttachment(this.modelHorizontalSeparator);
+ this.modelVerticalSeparatorLeft.setLayoutData(fd);
+
+ this.modelVerticalSeparatorRight = new Label(this.grpComponents, SWT.VERTICAL | SWT.SEPARATOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.modelHorizontalSeparator, -4, SWT.TOP);
+ fd.bottom = new FormAttachment(this.modelHorizontalSeparator, 4, SWT.BOTTOM);
+ fd.right = new FormAttachment(this.modelHorizontalSeparator);
+ this.modelVerticalSeparatorRight.setLayoutData(fd);
+
+ this.lblDatabase = new Label(this.grpComponents, SWT.CENTER);
+ this.lblDatabase.setBackground(GROUP_BACKGROUND_COLOR);
+ this.lblDatabase.setText("Database");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.lblModel, 0, SWT.TOP);
+ fd.left = new FormAttachment(62, 0);
+ fd.right = new FormAttachment(86, 0);
+ this.lblDatabase.setLayoutData(fd);
+
+ this.lblDatabaseNew = new Label(this.grpComponents, SWT.CENTER);
+ this.lblDatabaseNew.setBackground(GROUP_BACKGROUND_COLOR);
+ this.lblDatabaseNew.setText("New");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.lblTotal, 0, SWT.TOP);
+ fd.left = new FormAttachment(62, 0);
+ fd.right = new FormAttachment(70, -2);
+ this.lblDatabaseNew.setLayoutData(fd);
+
+ this.lblDatabaseUpdated = new Label(this.grpComponents, SWT.CENTER);
+ this.lblDatabaseUpdated.setBackground(GROUP_BACKGROUND_COLOR);
+ this.lblDatabaseUpdated.setText("Updated");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.lblTotal, 0, SWT.TOP);
+ fd.left = new FormAttachment(70, 1);
+ fd.right = new FormAttachment(78, -2);
+ this.lblDatabaseUpdated.setLayoutData(fd);
+
+ this.lblDatabaseDeleted = new Label(this.grpComponents, SWT.CENTER);
+ this.lblDatabaseDeleted.setBackground(GROUP_BACKGROUND_COLOR);
+ this.lblDatabaseDeleted.setText("Deleted");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.lblTotal, 0, SWT.TOP);
+ fd.left = new FormAttachment(78, 1);
+ fd.right = new FormAttachment(86, 0);
+ this.lblDatabaseDeleted.setLayoutData(fd);
+
+ this.databaseHorizontalSeparator = new Label(this.grpComponents, SWT.HORIZONTAL | SWT.SEPARATOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.lblDatabase, 2);
+ fd.left = new FormAttachment(this.lblDatabaseNew, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblDatabaseDeleted, 0, SWT.RIGHT);
+ this.databaseHorizontalSeparator.setLayoutData(fd);
+
+ this.databaseVerticalSeparatorLeft = new Label(this.grpComponents, SWT.VERTICAL | SWT.SEPARATOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.databaseHorizontalSeparator, -4, SWT.TOP);
+ fd.bottom = new FormAttachment(this.databaseHorizontalSeparator, 4, SWT.BOTTOM);
+ fd.left = new FormAttachment(this.databaseHorizontalSeparator);
+ this.databaseVerticalSeparatorLeft.setLayoutData(fd);
+
+ this.databaseVerticalSeparatorRight = new Label(this.grpComponents, SWT.VERTICAL | SWT.SEPARATOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.databaseHorizontalSeparator, -4, SWT.TOP);
+ fd.bottom = new FormAttachment(this.databaseHorizontalSeparator, 4, SWT.BOTTOM);
+ fd.right = new FormAttachment(this.databaseHorizontalSeparator);
+ this.databaseVerticalSeparatorRight.setLayoutData(fd);
+
+ this.lblConflicts = new Label(this.grpComponents, SWT.CENTER);
+ this.lblConflicts.setBackground(GROUP_BACKGROUND_COLOR);
+ this.lblConflicts.setText("Conflicts");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.lblTotal, 0, SWT.TOP);
+ fd.left = new FormAttachment(91, 0);
+ fd.right = new FormAttachment(99, 0);
+ this.lblConflicts.setLayoutData(fd);
+
+ /* * * * * */
+
+ this.txtTotalProfiles = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtTotalProfiles.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblProfiles, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblTotal, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblTotal, 0, SWT.RIGHT);
+ this.txtTotalProfiles.setLayoutData(fd);
+
+ this.txtNewProfilesInModel = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtNewProfilesInModel.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblProfiles, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblModelNew, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblModelNew, 0, SWT.RIGHT);
+ this.txtNewProfilesInModel.setLayoutData(fd);
+
+ this.txtUpdatedProfilesInModel = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtUpdatedProfilesInModel.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblProfiles, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblModelUpdated, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblModelUpdated, 0, SWT.RIGHT);
+ this.txtUpdatedProfilesInModel.setLayoutData(fd);
+
+ this.txtDeletedProfilesInModel = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtDeletedProfilesInModel.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblProfiles, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblModelDeleted, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblModelDeleted, 0, SWT.RIGHT);
+ this.txtDeletedProfilesInModel.setLayoutData(fd);
+
+ this.txtNewProfilesInDatabase = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtNewProfilesInDatabase.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblProfiles, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblDatabaseNew, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblDatabaseNew, 0, SWT.RIGHT);
+ this.txtNewProfilesInDatabase.setLayoutData(fd);
+
+ this.txtUpdatedProfilesInDatabase = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtUpdatedProfilesInDatabase.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblProfiles, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblDatabaseUpdated, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblDatabaseUpdated, 0, SWT.RIGHT);
+ this.txtUpdatedProfilesInDatabase.setLayoutData(fd);
+
+ this.txtDeletedProfilesInDatabase = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtDeletedProfilesInDatabase.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblProfiles, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblDatabaseDeleted, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblDatabaseDeleted, 0, SWT.RIGHT);
+ this.txtDeletedProfilesInDatabase.setLayoutData(fd);
+
+ this.txtConflictingProfiles = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtConflictingProfiles.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblProfiles, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblConflicts, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblConflicts, 0, SWT.RIGHT);
+ this.txtConflictingProfiles.setLayoutData(fd);
+
+ /* * * * * */
+
+ this.txtTotalElements = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtTotalElements.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblElements, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblTotal, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblTotal, 0, SWT.RIGHT);
+ this.txtTotalElements.setLayoutData(fd);
+
+ this.txtNewElementsInModel = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtNewElementsInModel.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblElements, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblModelNew, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblModelNew, 0, SWT.RIGHT);
+ this.txtNewElementsInModel.setLayoutData(fd);
+
+ this.txtUpdatedElementsInModel = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtUpdatedElementsInModel.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblElements, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblModelUpdated, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblModelUpdated, 0, SWT.RIGHT);
+ this.txtUpdatedElementsInModel.setLayoutData(fd);
+
+ this.txtDeletedElementsInModel = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtDeletedElementsInModel.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblElements, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblModelDeleted, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblModelDeleted, 0, SWT.RIGHT);
+ this.txtDeletedElementsInModel.setLayoutData(fd);
+
+ this.txtNewElementsInDatabase = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtNewElementsInDatabase.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblElements, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblDatabaseNew, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblDatabaseNew, 0, SWT.RIGHT);
+ this.txtNewElementsInDatabase.setLayoutData(fd);
+
+ this.txtUpdatedElementsInDatabase = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtUpdatedElementsInDatabase.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblElements, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblDatabaseUpdated, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblDatabaseUpdated, 0, SWT.RIGHT);
+ this.txtUpdatedElementsInDatabase.setLayoutData(fd);
+
+ this.txtDeletedElementsInDatabase = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtDeletedElementsInDatabase.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblElements, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblDatabaseDeleted, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblDatabaseDeleted, 0, SWT.RIGHT);
+ this.txtDeletedElementsInDatabase.setLayoutData(fd);
+
+ this.txtConflictingElements = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtConflictingElements.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblElements, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblConflicts, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblConflicts, 0, SWT.RIGHT);
+ this.txtConflictingElements.setLayoutData(fd);
+
+ /* * * * * */
+
+ this.txtTotalRelationships = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtTotalRelationships.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblRelationships, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblTotal, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblTotal, 0, SWT.RIGHT);
+ this.txtTotalRelationships.setLayoutData(fd);
+
+ this.txtNewRelationshipsInModel = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtNewRelationshipsInModel.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblRelationships, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblModelNew, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblModelNew, 0, SWT.RIGHT);
+ this.txtNewRelationshipsInModel.setLayoutData(fd);
+
+ this.txtUpdatedRelationshipsInModel = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtUpdatedRelationshipsInModel.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblRelationships, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblModelUpdated, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblModelUpdated, 0, SWT.RIGHT);
+ this.txtUpdatedRelationshipsInModel.setLayoutData(fd);
+
+ this.txtDeletedRelationshipsInModel = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtDeletedRelationshipsInModel.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblRelationships, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblModelDeleted, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblModelDeleted, 0, SWT.RIGHT);
+ this.txtDeletedRelationshipsInModel.setLayoutData(fd);
+
+ this.txtNewRelationshipsInDatabase = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtNewRelationshipsInDatabase.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblRelationships, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblDatabaseNew, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblDatabaseNew, 0, SWT.RIGHT);
+ this.txtNewRelationshipsInDatabase.setLayoutData(fd);
+
+ this.txtUpdatedRelationshipsInDatabase = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtUpdatedRelationshipsInDatabase.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblRelationships, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblDatabaseUpdated, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblDatabaseUpdated, 0, SWT.RIGHT);
+ this.txtUpdatedRelationshipsInDatabase.setLayoutData(fd);
+
+ this.txtDeletedRelationshipsInDatabase = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtDeletedRelationshipsInDatabase.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblRelationships, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblDatabaseDeleted, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblDatabaseDeleted, 0, SWT.RIGHT);
+ this.txtDeletedRelationshipsInDatabase.setLayoutData(fd);
+
+ this.txtConflictingRelationships = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtConflictingRelationships.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblRelationships, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblConflicts, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblConflicts, 0, SWT.RIGHT);
+ this.txtConflictingRelationships.setLayoutData(fd);
+
+ /* * * * * */
+
+ this.txtTotalFolders = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtTotalFolders.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblFolders, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblTotal, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblTotal, 0, SWT.RIGHT);
+ this.txtTotalFolders.setLayoutData(fd);
+
+ this.txtNewFoldersInModel = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtNewFoldersInModel.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblFolders, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblModelNew, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblModelNew, 0, SWT.RIGHT);
+ this.txtNewFoldersInModel.setLayoutData(fd);
+
+ this.txtUpdatedFoldersInModel = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtUpdatedFoldersInModel.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblFolders, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblModelUpdated, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblModelUpdated, 0, SWT.RIGHT);
+ this.txtUpdatedFoldersInModel.setLayoutData(fd);
+
+ this.txtDeletedFoldersInModel = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtDeletedFoldersInModel.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblFolders, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblModelDeleted, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblModelDeleted, 0, SWT.RIGHT);
+ this.txtDeletedFoldersInModel.setLayoutData(fd);
+
+ this.txtNewFoldersInDatabase = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtNewFoldersInDatabase.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblFolders, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblDatabaseNew, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblDatabaseNew, 0, SWT.RIGHT);
+ this.txtNewFoldersInDatabase.setLayoutData(fd);
+
+ this.txtUpdatedFoldersInDatabase = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtUpdatedFoldersInDatabase.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblFolders, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblDatabaseUpdated, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblDatabaseUpdated, 0, SWT.RIGHT);
+ this.txtUpdatedFoldersInDatabase.setLayoutData(fd);
+
+ this.txtDeletedFoldersInDatabase = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtDeletedFoldersInDatabase.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblFolders, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblDatabaseDeleted, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblDatabaseDeleted, 0, SWT.RIGHT);
+ this.txtDeletedFoldersInDatabase.setLayoutData(fd);
+
+ this.txtConflictingFolders = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtConflictingFolders.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblFolders, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblConflicts, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblConflicts, 0, SWT.RIGHT);
+ this.txtConflictingFolders.setLayoutData(fd);
+
+ /* * * * * */
+
+ this.txtTotalViews = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtTotalViews.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViews, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblTotal, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblTotal, 0, SWT.RIGHT);
+ this.txtTotalViews.setLayoutData(fd);
+
+ this.txtNewViewsInModel = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtNewViewsInModel.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViews, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblModelNew, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblModelNew, 0, SWT.RIGHT);
+ this.txtNewViewsInModel.setLayoutData(fd);
+
+ this.txtUpdatedViewsInModel = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtUpdatedViewsInModel.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViews, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblModelUpdated, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblModelUpdated, 0, SWT.RIGHT);
+ this.txtUpdatedViewsInModel.setLayoutData(fd);
+
+ this.txtDeletedViewsInModel = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtDeletedViewsInModel.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViews, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblModelDeleted, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblModelDeleted, 0, SWT.RIGHT);
+ this.txtDeletedViewsInModel.setLayoutData(fd);
+
+ this.txtNewViewsInDatabase = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtNewViewsInDatabase.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViews, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblDatabaseNew, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblDatabaseNew, 0, SWT.RIGHT);
+ this.txtNewViewsInDatabase.setLayoutData(fd);
+
+ this.txtUpdatedViewsInDatabase = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtUpdatedViewsInDatabase.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViews, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblDatabaseUpdated, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblDatabaseUpdated, 0, SWT.RIGHT);
+ this.txtUpdatedViewsInDatabase.setLayoutData(fd);
+
+ this.txtDeletedViewsInDatabase = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtDeletedViewsInDatabase.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViews, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblDatabaseDeleted, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblDatabaseDeleted, 0, SWT.RIGHT);
+ this.txtDeletedViewsInDatabase.setLayoutData(fd);
+
+ this.txtConflictingViews = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtConflictingViews.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViews, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblConflicts, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblConflicts, 0, SWT.RIGHT);
+ this.txtConflictingViews.setLayoutData(fd);
+
+ /* * * * * */
+
+ this.txtTotalViewObjects = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtTotalViewObjects.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViewObjects, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblTotal, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblTotal, 0, SWT.RIGHT);
+ this.txtTotalViewObjects.setLayoutData(fd);
+
+ this.txtNewViewObjectsInModel = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtNewViewObjectsInModel.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViewObjects, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblModelNew, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblModelNew, 0, SWT.RIGHT);
+ this.txtNewViewObjectsInModel.setLayoutData(fd);
+
+ this.txtUpdatedViewObjectsInModel = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtUpdatedViewObjectsInModel.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViewObjects, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblModelUpdated, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblModelUpdated, 0, SWT.RIGHT);
+ this.txtUpdatedViewObjectsInModel.setLayoutData(fd);
+
+ this.txtDeletedViewObjectsInModel = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtDeletedViewObjectsInModel.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViewObjects, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblModelDeleted, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblModelDeleted, 0, SWT.RIGHT);
+ this.txtDeletedViewObjectsInModel.setLayoutData(fd);
+
+ this.txtNewViewObjectsInDatabase = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtNewViewObjectsInDatabase.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViewObjects, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblDatabaseNew, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblDatabaseNew, 0, SWT.RIGHT);
+ this.txtNewViewObjectsInDatabase.setLayoutData(fd);
+
+ this.txtUpdatedViewObjectsInDatabase = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtUpdatedViewObjectsInDatabase.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViewObjects, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblDatabaseUpdated, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblDatabaseUpdated, 0, SWT.RIGHT);
+ this.txtUpdatedViewObjectsInDatabase.setLayoutData(fd);
+
+ this.txtDeletedViewObjectsInDatabase = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtDeletedViewObjectsInDatabase.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViewObjects, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblDatabaseDeleted, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblDatabaseDeleted, 0, SWT.RIGHT);
+ this.txtDeletedViewObjectsInDatabase.setLayoutData(fd);
+
+ this.txtConflictingViewObjects = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtConflictingViewObjects.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViewObjects, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblConflicts, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblConflicts, 0, SWT.RIGHT);
+ this.txtConflictingViewObjects.setLayoutData(fd);
+
+ /* * * * * */
+
+ this.txtTotalViewConnections = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtTotalViewConnections.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViewConnections, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblTotal, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblTotal, 0, SWT.RIGHT);
+ this.txtTotalViewConnections.setLayoutData(fd);
+
+ this.txtNewViewConnectionsInModel = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtNewViewConnectionsInModel.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViewConnections, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblModelNew, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblModelNew, 0, SWT.RIGHT);
+ this.txtNewViewConnectionsInModel.setLayoutData(fd);
+
+ this.txtUpdatedViewConnectionsInModel = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtUpdatedViewConnectionsInModel.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViewConnections, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblModelUpdated, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblModelUpdated, 0, SWT.RIGHT);
+ this.txtUpdatedViewConnectionsInModel.setLayoutData(fd);
+
+ this.txtDeletedViewConnectionsInModel = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtDeletedViewConnectionsInModel.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViewConnections, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblModelDeleted, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblModelDeleted, 0, SWT.RIGHT);
+ this.txtDeletedViewConnectionsInModel.setLayoutData(fd);
+
+ this.txtNewViewConnectionsInDatabase = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtNewViewConnectionsInDatabase.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViewConnections, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblDatabaseNew, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblDatabaseNew, 0, SWT.RIGHT);
+ this.txtNewViewConnectionsInDatabase.setLayoutData(fd);
+
+ this.txtUpdatedViewConnectionsInDatabase = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtUpdatedViewConnectionsInDatabase.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViewConnections, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblDatabaseUpdated, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblDatabaseUpdated, 0, SWT.RIGHT);
+ this.txtUpdatedViewConnectionsInDatabase.setLayoutData(fd);
+
+ this.txtDeletedViewConnectionsInDatabase = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtDeletedViewConnectionsInDatabase.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViewConnections, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblDatabaseDeleted, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblDatabaseDeleted, 0, SWT.RIGHT);
+ this.txtDeletedViewConnectionsInDatabase.setLayoutData(fd);
+
+ this.txtConflictingViewConnections = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtConflictingViewConnections.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViewConnections, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblConflicts, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblConflicts, 0, SWT.RIGHT);
+ this.txtConflictingViewConnections.setLayoutData(fd);
+
+ /* * * * * */
+
+ this.txtTotalImages = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtTotalImages.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblImages, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblTotal, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblTotal, 0, SWT.RIGHT);
+ this.txtTotalImages.setLayoutData(fd);
+
+ this.txtNewImagesInModel = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtNewImagesInModel.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblImages, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblModelNew, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblModelNew, 0, SWT.RIGHT);
+ this.txtNewImagesInModel.setLayoutData(fd);
+
+ this.txtNewImagesInDatabase = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtNewImagesInDatabase.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblImages, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblDatabaseNew, 0, SWT.LEFT);
+ fd.right = new FormAttachment(this.lblDatabaseNew, 0, SWT.RIGHT);
+ this.txtNewImagesInDatabase.setLayoutData(fd);
+
+ /* * * * * */
+ this.btnCompareModelToDatabase = new Button(this.grpComponents, SWT.PUSH);
+ this.btnCompareModelToDatabase.setText("Compare model to the database");
+ fd = new FormData();
+ fd.right = new FormAttachment(100, -5);
+ fd.bottom = new FormAttachment(100, -5);
+ this.btnCompareModelToDatabase.setLayoutData(fd);
+ this.btnCompareModelToDatabase.addSelectionListener(new SelectionListener() {
+ @Override public void widgetSelected(SelectionEvent e) {
+ boolean upToDate = false;
+ DBGuiExportModel.this.btnDoAction.setEnabled(false);
+ DBGuiExportModel.this.btnCompareModelToDatabase.setEnabled(false);
+ try {
+ upToDate = DBGuiExportModel.this.compareModelToDatabase(true);
+ } catch (Exception err) {
+ popup(Level.ERROR, "Failed to compare the model to the database.", err);
+ }
+ DBGuiExportModel.this.btnCompareModelToDatabase.setEnabled(true);
+ if ( upToDate ) {
+ popup(Level.INFO, "Your database is already up to date.");
+ DBGuiExportModel.this.btnClose.setText("Close");
+ DBGuiExportModel.this.btnDoAction.setEnabled(false);
+ } else
+ DBGuiExportModel.this.btnDoAction.setEnabled(true);
+ }
+ @Override public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); }
+ });
+ }
+
+ /**
+ * This method is called each time a database is selected and a connection has been established to it.
+ *
+ * It enables the export button and starts the export if the "automatic start" is specified in the plugin preferences
+ */
+ @Override
+ protected void connectedToDatabase(boolean forceCheckDatabase) {
+ this.exportConnection = new DBDatabaseExportConnection(getDatabaseConnection());
+
+ boolean isNeo4j = DBPlugin.areEqual(this.selectedDatabase.getDriver().toLowerCase(), "neo4j");
+
+ this.lblModelNew.setText(isNeo4j ? "Exported" : "New");
+
+ this.modelHorizontalSeparator.setVisible(!isNeo4j);
+ this.modelVerticalSeparatorRight.setVisible(!isNeo4j);
+ this.modelVerticalSeparatorRight.setVisible(!isNeo4j);
+
+ this.databaseHorizontalSeparator.setVisible(!isNeo4j);
+ this.databaseVerticalSeparatorRight.setVisible(!isNeo4j);
+ this.databaseVerticalSeparatorRight.setVisible(!isNeo4j);
+
+ // we hide the comparison between the model and the database in case of a neo4j database
+ this.lblModel.setVisible(!isNeo4j);
+ this.lblModelDeleted.setVisible(!isNeo4j);
+ this.lblModelUpdated.setVisible(!isNeo4j);
+ this.txtUpdatedElementsInModel.setVisible(!isNeo4j);
+ this.txtDeletedElementsInModel.setVisible(!isNeo4j);
+ this.txtUpdatedRelationshipsInModel.setVisible(!isNeo4j);
+ this.txtDeletedRelationshipsInModel.setVisible(!isNeo4j);
+ this.txtNewFoldersInModel.setVisible(!isNeo4j);
+ this.txtUpdatedFoldersInModel.setVisible(!isNeo4j);
+ this.txtDeletedFoldersInModel.setVisible(!isNeo4j);
+ this.txtNewViewsInModel.setVisible(!isNeo4j);
+ this.txtUpdatedViewsInModel.setVisible(!isNeo4j);
+ this.txtDeletedViewsInModel.setVisible(!isNeo4j);
+ this.txtNewViewObjectsInModel.setVisible(!isNeo4j);
+ this.txtUpdatedViewObjectsInModel.setVisible(!isNeo4j);
+ this.txtDeletedViewObjectsInModel.setVisible(!isNeo4j);
+ this.txtNewViewConnectionsInModel.setVisible(!isNeo4j);
+ this.txtUpdatedViewConnectionsInModel.setVisible(!isNeo4j);
+ this.txtDeletedViewConnectionsInModel.setVisible(!isNeo4j);
+ this.txtNewImagesInModel.setVisible(!isNeo4j);
+
+ this.lblDatabase.setVisible(!isNeo4j);
+ this.lblDatabaseNew.setVisible(!isNeo4j);
+ this.lblDatabaseDeleted.setVisible(!isNeo4j);
+ this.lblDatabaseUpdated.setVisible(!isNeo4j);
+ this.lblConflicts.setVisible(!isNeo4j);
+ this.txtNewElementsInDatabase.setVisible(!isNeo4j);
+ this.txtUpdatedElementsInDatabase.setVisible(!isNeo4j);
+ this.txtDeletedElementsInDatabase.setVisible(!isNeo4j);
+ this.txtConflictingElements.setVisible(!isNeo4j);
+ this.txtNewRelationshipsInDatabase.setVisible(!isNeo4j);
+ this.txtUpdatedRelationshipsInDatabase.setVisible(!isNeo4j);
+ this.txtDeletedRelationshipsInDatabase.setVisible(!isNeo4j);
+ this.txtConflictingRelationships.setVisible(!isNeo4j);
+ this.txtNewFoldersInDatabase.setVisible(!isNeo4j);
+ this.txtUpdatedFoldersInDatabase.setVisible(!isNeo4j);
+ this.txtDeletedFoldersInDatabase.setVisible(!isNeo4j);
+ this.txtConflictingFolders.setVisible(!isNeo4j);
+ this.txtNewViewsInDatabase.setVisible(!isNeo4j);
+ this.txtUpdatedViewsInDatabase.setVisible(!isNeo4j);
+ this.txtDeletedViewsInDatabase.setVisible(!isNeo4j);
+ this.txtConflictingViews.setVisible(!isNeo4j);
+ this.txtNewViewObjectsInDatabase.setVisible(!isNeo4j);
+ this.txtUpdatedViewObjectsInDatabase.setVisible(!isNeo4j);
+ this.txtDeletedViewObjectsInDatabase.setVisible(!isNeo4j);
+ this.txtConflictingViewObjects.setVisible(!isNeo4j);
+ this.txtNewViewConnectionsInDatabase.setVisible(!isNeo4j);
+ this.txtUpdatedViewConnectionsInDatabase.setVisible(!isNeo4j);
+ this.txtDeletedViewConnectionsInDatabase.setVisible(!isNeo4j);
+ this.txtConflictingViewConnections.setVisible(!isNeo4j);
+ this.txtNewImagesInDatabase.setVisible(!isNeo4j);
+
+ DBGuiExportModel.this.tblModelVersions.removeAll();
+
+ // if the first line, then we add the "latest version"
+ TableItem tableItem = new TableItem(DBGuiExportModel.this.tblModelVersions, SWT.NULL);
+ tableItem.setText(1, "Now");
+ tableItem.setData("name", this.exportedModel.getName());
+ tableItem.setData("note", "");
+ tableItem.setData("purpose", this.exportedModel.getPurpose());
+ DBGuiExportModel.this.tblModelVersions.setSelection(tableItem);
+ DBGuiExportModel.this.tblModelVersions.notifyListeners(SWT.Selection, new Event()); // activates the name, note and purpose texts
+
+ // if we're not in a Neo4J database, then we get the latest version and checksum of the model's components in the database
+ try {
+ if ( !isNeo4j ) {
+ for (Hashtable version : DBGuiExportModel.this.exportConnection.getModelVersions(this.exportedModel.getId()) ) {
+ tableItem = new TableItem(DBGuiExportModel.this.tblModelVersions, SWT.NULL);
+ tableItem.setText(0, (String)version.get("version"));
+ tableItem.setText(1, new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format((Timestamp)version.get("created_on")));
+ tableItem.setText(2, (String)version.get("created_by"));
+ tableItem.setData("name", version.get("name"));
+ tableItem.setData("note", version.get("note"));
+ tableItem.setData("purpose", version.get("purpose"));
+ }
+ }
+ } catch (Exception err) {
+ popup(Level.FATAL, "Failed to check existing components in database", err);
+ setActiveAction(STATUS.Error);
+ return;
+ }
+
+ this.btnCompareModelToDatabase.setVisible(!isNeo4j);
+
+ if ( DBPlugin.INSTANCE.getPreferenceStore().getBoolean("exportWithDefaultValues") ) {
+ // if the exportWithDefaultValues preference is set, then we automatically start the export
+ logger.debug("Automatically start export as specified in preferences.");
+ this.btnDoAction.setEnabled(true);
+ this.btnDoAction.notifyListeners(SWT.Selection, new Event());
+ return;
+ }
+
+ if ( !isNeo4j && DBPlugin.INSTANCE.getPreferenceStore().getBoolean("compareBeforeExport") ) {
+ // if the compareBeforeExport is set
+ boolean upToDate = false;
+ this.btnDoAction.setEnabled(false);
+ this.btnCompareModelToDatabase.setEnabled(false);
+ try {
+ upToDate = compareModelToDatabase(true);
+ } catch (Exception err) {
+ popup(Level.ERROR, "Failed to compare the model to the database.", err);
+ }
+
+ this.btnCompareModelToDatabase.setEnabled(true);
+ closeMessage();
+ if ( upToDate ) {
+ popup(Level.INFO, "Your database is already up to date.");
+ DBGuiExportModel.this.btnClose.setText("Close");
+ this.btnDoAction.setEnabled(false);
+ } else
+ this.btnDoAction.setEnabled(true);
+ } else {
+ if ( logger.isDebugEnabled() ) logger.debug("Enabling the \"Export\" button.");
+ this.btnDoAction.setEnabled(true);
+ this.btnCompareModelToDatabase.setEnabled(true);
+ }
+ }
+
+ /**
+ * This method is called each time a connection to the database fails.
+ *
+ * It disables the export button
+ */
+ @Override
+ protected void notConnectedToDatabase() {
+ if ( logger.isDebugEnabled() ) logger.debug("Disabling the \"Export\" button.");
+ this.btnDoAction.setEnabled(false);
+ this.btnCompareModelToDatabase.setEnabled(false);
+
+ // we hide the comparison between the model and the database in case of a neo4j database
+ boolean isNeo4j = DBPlugin.areEqual(this.selectedDatabase.getDriver().toLowerCase(), "neo4j");
+ this.lblModel.setVisible(!isNeo4j);
+ this.lblModelNew.setVisible(!isNeo4j);
+ this.lblModelDeleted.setVisible(!isNeo4j);
+ this.lblModelUpdated.setVisible(!isNeo4j);
+ this.txtNewProfilesInModel.setVisible(!isNeo4j);
+ this.txtUpdatedProfilesInModel.setVisible(!isNeo4j);
+ this.txtDeletedProfilesInModel.setVisible(!isNeo4j);
+ this.txtNewRelationshipsInModel.setVisible(!isNeo4j);
+ this.txtNewElementsInModel.setVisible(!isNeo4j);
+ this.txtUpdatedElementsInModel.setVisible(!isNeo4j);
+ this.txtDeletedElementsInModel.setVisible(!isNeo4j);
+ this.txtNewRelationshipsInModel.setVisible(!isNeo4j);
+ this.txtUpdatedRelationshipsInModel.setVisible(!isNeo4j);
+ this.txtDeletedRelationshipsInModel.setVisible(!isNeo4j);
+ this.txtNewFoldersInModel.setVisible(!isNeo4j);
+ this.txtUpdatedFoldersInModel.setVisible(!isNeo4j);
+ this.txtDeletedFoldersInModel.setVisible(!isNeo4j);
+ this.txtNewViewsInModel.setVisible(!isNeo4j);
+ this.txtUpdatedViewsInModel.setVisible(!isNeo4j);
+ this.txtDeletedViewsInModel.setVisible(!isNeo4j);
+ this.txtNewViewObjectsInModel.setVisible(!isNeo4j);
+ this.txtUpdatedViewObjectsInModel.setVisible(!isNeo4j);
+ this.txtDeletedViewObjectsInModel.setVisible(!isNeo4j);
+ this.txtNewViewConnectionsInModel.setVisible(!isNeo4j);
+ this.txtUpdatedViewConnectionsInModel.setVisible(!isNeo4j);
+ this.txtDeletedViewConnectionsInModel.setVisible(!isNeo4j);
+ this.txtNewImagesInModel.setVisible(!isNeo4j);
+
+
+ // we hide the database and conflict columns if Neo4J
+ this.lblDatabase.setVisible(!isNeo4j);
+ this.lblDatabaseNew.setVisible(!isNeo4j);
+ this.lblDatabaseDeleted.setVisible(!isNeo4j);
+ this.lblDatabaseUpdated.setVisible(!isNeo4j);
+ this.lblConflicts.setVisible(!isNeo4j);
+ this.txtNewProfilesInDatabase.setVisible(!isNeo4j);
+ this.txtUpdatedProfilesInDatabase.setVisible(!isNeo4j);
+ this.txtDeletedProfilesInDatabase.setVisible(!isNeo4j);
+ this.txtConflictingProfiles.setVisible(!isNeo4j);
+ this.txtNewElementsInDatabase.setVisible(!isNeo4j);
+ this.txtUpdatedElementsInDatabase.setVisible(!isNeo4j);
+ this.txtDeletedElementsInDatabase.setVisible(!isNeo4j);
+ this.txtConflictingElements.setVisible(!isNeo4j);
+ this.txtNewRelationshipsInDatabase.setVisible(!isNeo4j);
+ this.txtUpdatedRelationshipsInDatabase.setVisible(!isNeo4j);
+ this.txtDeletedRelationshipsInDatabase.setVisible(!isNeo4j);
+ this.txtConflictingRelationships.setVisible(!isNeo4j);
+ this.txtNewFoldersInDatabase.setVisible(!isNeo4j);
+ this.txtUpdatedFoldersInDatabase.setVisible(!isNeo4j);
+ this.txtDeletedFoldersInDatabase.setVisible(!isNeo4j);
+ this.txtConflictingFolders.setVisible(!isNeo4j);
+ this.txtNewViewsInDatabase.setVisible(!isNeo4j);
+ this.txtUpdatedViewsInDatabase.setVisible(!isNeo4j);
+ this.txtDeletedViewsInDatabase.setVisible(!isNeo4j);
+ this.txtConflictingViews.setVisible(!isNeo4j);
+ this.txtNewViewObjectsInDatabase.setVisible(!isNeo4j);
+ this.txtUpdatedViewObjectsInDatabase.setVisible(!isNeo4j);
+ this.txtDeletedViewObjectsInDatabase.setVisible(!isNeo4j);
+ this.txtConflictingViewObjects.setVisible(!isNeo4j);
+ this.txtNewViewConnectionsInDatabase.setVisible(!isNeo4j);
+ this.txtUpdatedViewConnectionsInDatabase.setVisible(!isNeo4j);
+ this.txtDeletedViewConnectionsInDatabase.setVisible(!isNeo4j);
+ this.txtConflictingViewConnections.setVisible(!isNeo4j);
+ this.txtNewImagesInDatabase.setVisible(!isNeo4j);
+
+ this.txtNewProfilesInModel.setText(this.ZERO); this.txtUpdatedProfilesInModel.setText(this.ZERO); this.txtNewProfilesInDatabase.setText(this.ZERO); this.txtUpdatedProfilesInDatabase.setText(this.ZERO); this.txtConflictingProfiles.setText(this.ZERO);
+ this.txtNewElementsInModel.setText(this.ZERO); this.txtUpdatedElementsInModel.setText(this.ZERO); this.txtNewElementsInDatabase.setText(this.ZERO); this.txtUpdatedElementsInDatabase.setText(this.ZERO); this.txtConflictingElements.setText(this.ZERO);
+ this.txtNewRelationshipsInModel.setText(this.ZERO); this.txtUpdatedRelationshipsInModel.setText(this.ZERO); this.txtNewRelationshipsInDatabase.setText(this.ZERO); this.txtUpdatedRelationshipsInDatabase.setText(this.ZERO); this.txtConflictingRelationships.setText(this.ZERO);
+ this.txtNewFoldersInModel.setText(this.ZERO); this.txtUpdatedFoldersInModel.setText(this.ZERO); this.txtNewFoldersInDatabase.setText(this.ZERO); this.txtUpdatedFoldersInDatabase.setText(this.ZERO); this.txtConflictingFolders.setText(this.ZERO);
+ this.txtNewViewsInModel.setText(this.ZERO); this.txtUpdatedViewsInModel.setText(this.ZERO); this.txtNewViewsInDatabase.setText(this.ZERO); this.txtUpdatedViewsInDatabase.setText(this.ZERO); this.txtConflictingViews.setText(this.ZERO);
+ this.txtNewViewObjectsInModel.setText(this.ZERO); this.txtUpdatedViewObjectsInModel.setText(this.ZERO); this.txtNewViewObjectsInDatabase.setText(this.ZERO); this.txtUpdatedViewObjectsInDatabase.setText(this.ZERO); this.txtConflictingViewObjects.setText(this.ZERO);
+ this.txtNewViewConnectionsInModel.setText(this.ZERO); this.txtUpdatedViewConnectionsInModel.setText(this.ZERO); this.txtNewViewConnectionsInDatabase.setText(this.ZERO); this.txtUpdatedViewConnectionsInDatabase.setText(this.ZERO); this.txtConflictingViewConnections.setText(this.ZERO);
+ }
+
+ /**
+ * Update the text widgets that shows up the new, updated and deleted components
+ *
+ * @return true is the database is up to date, false if the model needs to be exported
+ */
+ protected boolean compareModelToDatabase(boolean updateTextFields) throws Exception {
+ // We do not verify the content of neo4j database, we just export the components
+ if ( DBPlugin.areEqual(this.selectedDatabase.getDriver().toLowerCase(), "neo4j") )
+ return true;
+
+ int progressBarWidth = this.exportedModel.getAllElements().size() + this.exportedModel.getAllRelationships().size() + this.exportedModel.getAllFolders().size() + this.exportedModel.getAllViews().size() + this.exportedModel.getAllViewObjects().size() + this.exportedModel.getAllViewConnections().size();
+ createProgressBar("Comparing the model to the database ...", 1, progressBarWidth);
+
+ try {
+ // we compare the elements, relationships, folders and views
+ this.exportConnection.getAllVersionFromDatabase(this.exportedModel, this);
+ } catch (SQLException err ) {
+ hideProgressBar();
+ popup(Level.FATAL, "Failed to get latest version of components in the database.", err);
+ setActiveAction(STATUS.Error);
+ doShowResult(STATUS.Error, "Error while exporting model.\n"+err.getMessage());
+ return false;
+ }
+
+ // we create the view screenshots if the database is configured to export them
+ hideProgressBar();
+ hideGrpDatabase();
+ createProgressBar("Checking if view screenshots are required", 1, this.exportedModel.getAllViews().size());
+ Iterator> screenshotsIterator = this.exportedModel.getAllViews().entrySet().iterator();
+ while ( screenshotsIterator.hasNext() ) {
+ increaseProgressBar();
+ IDiagramModel view = screenshotsIterator.next().getValue();
+ DBMetadata metadata = this.exportedModel.getDBMetadata(view);
+ if ( this.exportConnection.getDatabaseEntry().isViewSnapshotRequired() ) {
+ if ( (metadata.getScreenshot().getBytes() == null)
+ || (metadata.getScreenshot().getScaleFactor() != this.exportConnection.getDatabaseEntry().getViewsImagesScaleFactor())
+ || (metadata.getScreenshot().getBodrderWidth() != this.exportConnection.getDatabaseEntry().getViewsImagesBorderWidth())
+ ) {
+ setProgressBarLabel("Creating screenshot of view \""+view.getName()+"\"");
+ createImage(view, this.exportConnection.getDatabaseEntry().getViewsImagesScaleFactor(), this.exportConnection.getDatabaseEntry().getViewsImagesBorderWidth());
+ setProgressBarLabel("Checking if view screenshots are required");
+ }
+ metadata.getScreenshot().setScreenshotActive(true);
+ } else
+ metadata.getScreenshot().setScreenshotActive(false);
+
+ // we recalculate the view checksum using the screenshot (or not)
+ this.exportedModel.countObject(view, true);
+ }
+ hideProgressBar();
+ showGrpDatabase();
+ setMessage("Calculating number of new, updated and deleted components.");
+
+ int total = 0;
+
+ int nbNew = 0;
+ int nbNewInDb = 0;
+ int nbUpdated = 0;
+ int nbUpdatedInDb = 0;
+ int nbConflict = 0;
+ int nbDeleted = 0;
+ int nbDeletedInDb = 0;
+ Iterator> profilesIterator = this.exportedModel.getAllProfiles().entrySet().iterator();
+ while (profilesIterator.hasNext()) {
+ IProfile profile = profilesIterator.next().getValue();
+ DBMetadata metadata = this.exportedModel.getDBMetadata(profile);
+ switch ( metadata.getDatabaseStatus() ) {
+ case isNewInModel:
+ ++nbNew;
+ break;
+ case isUpadtedInDatabase:
+ ++nbUpdatedInDb;
+ break;
+ case isUpdatedInModel:
+ ++nbUpdated;
+ break;
+ case isDeletedInDatabase:
+ ++nbDeletedInDb;
+ break;
+ case isConflicting:
+ if ( this.exportedModel.getAllConflicts().get(profile) == null )
+ this.exportedModel.getAllConflicts().put(profile, CONFLICT_CHOICE.askUser);
+ switch ( this.exportedModel.getAllConflicts().get(profile) ) {
+ case doNotExport: // nothing to do
+ break;
+ case exportToDatabase:
+ ++nbUpdated;
+ break;
+ case importFromDatabase:
+ ++nbUpdatedInDb;
+ break;
+ case askUser:
+ default:
+ ++nbConflict;
+ }
+ break;
+ case isSynced:
+ // nothing to do
+ break;
+ case isNewInDatabase:
+ default:
+ // should never be here
+ }
+ }
+ // we distinguish the Profiles new in the database from those deleted from memory
+ for ( DBMetadata metadata: this.exportConnection.getProfilesNotInModel().values() ) {
+ if ( metadata.getInitialVersion().getVersion() != 0 )
+ ++nbDeleted; // if the component did exist in the InitialVersion of the model, then it has been deleted from the model
+ else
+ ++nbNewInDb; // else, the component has been created in the database since the model has been loaded
+
+ }
+ total += nbNew + nbNewInDb + nbUpdated + nbUpdatedInDb + nbDeleted + nbDeletedInDb + nbConflict;
+ if ( updateTextFields ) {
+ this.txtNewProfilesInModel.setText(toString(nbNew));
+ this.txtNewProfilesInDatabase.setText(toString(nbNewInDb));
+ this.txtUpdatedProfilesInModel.setText(toString(nbUpdated));
+ this.txtUpdatedProfilesInDatabase.setText(toString(nbUpdatedInDb));
+ this.txtConflictingProfiles.setText(toString(nbConflict));
+ this.txtDeletedProfilesInModel.setText(toString(nbDeleted));
+ this.txtDeletedProfilesInDatabase.setText(toString(nbDeletedInDb));
+ }
+
+ nbNew = 0;
+ nbNewInDb = 0;
+ nbUpdated = 0;
+ nbUpdatedInDb = 0;
+ nbConflict = 0;
+ nbDeleted = 0;
+ nbDeletedInDb = 0;
+ Iterator> elementsIterator = this.exportedModel.getAllElements().entrySet().iterator();
+ while (elementsIterator.hasNext()) {
+ IArchimateElement element = elementsIterator.next().getValue();
+ DBMetadata metadata = this.exportedModel.getDBMetadata(element);
+ switch ( metadata.getDatabaseStatus() ) {
+ case isNewInModel:
+ ++nbNew;
+ break;
+ case isUpadtedInDatabase:
+ ++nbUpdatedInDb;
+ break;
+ case isUpdatedInModel:
+ ++nbUpdated;
+ break;
+ case isDeletedInDatabase:
+ ++nbDeletedInDb;
+ break;
+ case isConflicting:
+ if ( this.exportedModel.getAllConflicts().get(element) == null )
+ this.exportedModel.getAllConflicts().put(element, CONFLICT_CHOICE.askUser);
+ switch ( this.exportedModel.getAllConflicts().get(element) ) {
+ case doNotExport: // nothing to do
+ break;
+ case exportToDatabase:
+ ++nbUpdated;
+ break;
+ case importFromDatabase:
+ ++nbUpdatedInDb;
+ break;
+ case askUser:
+ default:
+ ++nbConflict;
+ }
+ break;
+ case isSynced:
+ // nothing to do
+ break;
+ case isNewInDatabase:
+ default:
+ // should never be here
+ }
+ }
+ // we distinguish the elements new in the database from those deleted from memory
+ for ( DBMetadata metadata: this.exportConnection.getElementsNotInModel().values() ) {
+ if ( metadata.getInitialVersion().getVersion() != 0 )
+ ++nbDeleted; // if the component did exist in the InitialVersion of the model, then it has been deleted from the model
+ else
+ ++nbNewInDb; // else, the component has been created in the database since the model has been loaded
+
+ }
+ total += nbNew + nbNewInDb + nbUpdated + nbUpdatedInDb + nbDeleted + nbDeletedInDb + nbConflict;
+ if ( updateTextFields ) {
+ this.txtNewElementsInModel.setText(toString(nbNew));
+ this.txtNewElementsInDatabase.setText(toString(nbNewInDb));
+ this.txtUpdatedElementsInModel.setText(toString(nbUpdated));
+ this.txtUpdatedElementsInDatabase.setText(toString(nbUpdatedInDb));
+ this.txtConflictingElements.setText(toString(nbConflict));
+ this.txtDeletedElementsInModel.setText(toString(nbDeleted));
+ this.txtDeletedElementsInDatabase.setText(toString(nbDeletedInDb));
+ }
+
+ nbNew = 0;
+ nbNewInDb = 0;
+ nbUpdated = 0;
+ nbUpdatedInDb = 0;
+ nbConflict = 0;
+ nbDeleted = 0;
+ nbDeletedInDb = 0;
+ Iterator> relationshipsIterator = this.exportedModel.getAllRelationships().entrySet().iterator();
+ while (relationshipsIterator.hasNext()) {
+ IArchimateRelationship relationship = relationshipsIterator.next().getValue();
+ DBMetadata metadata = this.exportedModel.getDBMetadata(relationship);
+ switch ( metadata.getDatabaseStatus() ) {
+ case isNewInModel:
+ ++nbNew;
+ break;
+ case isUpadtedInDatabase:
+ ++nbUpdatedInDb;
+ break;
+ case isUpdatedInModel:
+ ++nbUpdated;
+ break;
+ case isDeletedInDatabase:
+ ++nbDeletedInDb;
+ break;
+ case isConflicting:
+ if ( this.exportedModel.getAllConflicts().get(relationship) == null )
+ this.exportedModel.getAllConflicts().put(relationship, CONFLICT_CHOICE.askUser);
+ switch ( this.exportedModel.getAllConflicts().get(relationship) ) {
+ case doNotExport: // nothing to do
+ break;
+ case exportToDatabase:
+ ++nbUpdated;
+ break;
+ case importFromDatabase:
+ ++nbUpdatedInDb;
+ break;
+ case askUser:
+ default: // askUSer
+ ++nbConflict;
+ }
+ break;
+ case isSynced:
+ // nothing to do
+ break;
+ case isNewInDatabase:
+ default:
+ // should never be here
+ }
+ }
+ // we distinguish the relationships new in the database from those deleted from memory
+ for ( DBMetadata metadata: this.exportConnection.getRelationshipsNotInModel().values() ) {
+ if ( metadata.getInitialVersion().getVersion() != 0 )
+ ++nbDeleted; // if the component did exist in the InitialVersion of the model, then it has been deleted from the model
+ else
+ ++nbNewInDb; // else, the component has been created in the database since the model has been loaded
+ }
+ total += nbNew + nbNewInDb + nbUpdated + nbUpdatedInDb + nbDeleted + nbDeletedInDb + nbConflict;
+ if( updateTextFields ) {
+ this.txtNewRelationshipsInModel.setText(toString(nbNew));
+ this.txtNewRelationshipsInDatabase.setText(toString(nbNewInDb));
+ this.txtUpdatedRelationshipsInModel.setText(toString(nbUpdated));
+ this.txtUpdatedRelationshipsInDatabase.setText(toString(nbUpdatedInDb));
+ this.txtConflictingRelationships.setText(toString(nbConflict));
+ this.txtDeletedRelationshipsInModel.setText(toString(nbDeleted));
+ this.txtDeletedRelationshipsInDatabase.setText(toString(nbDeletedInDb));
+ }
+
+ nbNew = 0;
+ nbNewInDb = 0;
+ nbUpdated = 0;
+ nbUpdatedInDb = 0;
+ nbConflict = 0;
+ nbDeleted = 0;
+ nbDeletedInDb = 0;
+ Iterator> folderIterator = this.exportedModel.getAllFolders().entrySet().iterator();
+ while (folderIterator.hasNext()) {
+ IFolder folder = folderIterator.next().getValue();
+ DBMetadata metadata = this.exportedModel.getDBMetadata(folder);
+ switch ( metadata.getDatabaseStatus() ) {
+ case isNewInModel:
+ ++nbNew;
+ break;
+ case isUpadtedInDatabase:
+ ++nbUpdatedInDb;
+ break;
+ case isUpdatedInModel:
+ ++nbUpdated;
+ break;
+ case isDeletedInDatabase:
+ ++nbDeletedInDb;
+ break;
+ case isConflicting:
+ // There is no conflict for folders: conflicts are managed with their content
+ // If a folder has been updated both in the model and the database, then we export a new version
+ ++nbUpdated;
+ break;
+ case isSynced:
+ // nothing to do
+ break;
+ case isNewInDatabase:
+ default:
+ // should never be here
+ }
+ }
+ // we distinguish the folders new in the database from those deleted from memory
+ for ( DBMetadata metadata: this.exportConnection.getFoldersNotInModel().values() ) {
+ if ( metadata.getInitialVersion().getVersion() != 0 )
+ ++nbDeleted; // if the component did exist in the InitialVersion of the model, then it has been deleted from the model
+ else
+ ++nbNewInDb; // else, the component has been created in the database since the model has been loaded
+ }
+ total += nbNew + nbNewInDb + nbUpdated + nbUpdatedInDb + nbDeleted + nbDeletedInDb + nbConflict;
+ if ( updateTextFields ) {
+ this.txtNewFoldersInModel.setText(toString(nbNew));
+ this.txtNewFoldersInDatabase.setText(toString(nbNewInDb));
+ this.txtUpdatedFoldersInModel.setText(toString(nbUpdated));
+ this.txtUpdatedFoldersInDatabase.setText(toString(nbUpdatedInDb));
+ this.txtConflictingFolders.setText(toString(nbConflict));
+ this.txtDeletedFoldersInModel.setText(toString(nbDeleted));
+ this.txtDeletedFoldersInDatabase.setText(toString(nbDeletedInDb));
+ }
+
+ nbNew = 0;
+ nbNewInDb = 0;
+ nbUpdated = 0;
+ nbUpdatedInDb = 0;
+ nbConflict = 0;
+ nbDeleted = 0;
+ nbDeletedInDb = 0;
+ Iterator> viewsIterator = this.exportedModel.getAllViews().entrySet().iterator();
+ while (viewsIterator.hasNext()) {
+ IDiagramModel view = viewsIterator.next().getValue();
+ DBMetadata metadata = this.exportedModel.getDBMetadata(view);
+ switch ( metadata.getDatabaseStatus() ) {
+ case isNewInModel:
+ ++nbNew;
+ break;
+ case isUpadtedInDatabase:
+ ++nbUpdatedInDb;
+ break;
+ case isUpdatedInModel:
+ ++nbUpdated;
+ break;
+ case isDeletedInDatabase:
+ ++nbDeletedInDb;
+ break;
+ case isConflicting:
+ if ( this.exportedModel.getAllConflicts().get(view) == null )
+ this.exportedModel.getAllConflicts().put(view, CONFLICT_CHOICE.askUser);
+ switch ( this.exportedModel.getAllConflicts().get(view) ) {
+ case doNotExport: // nothing to do
+ break;
+ case exportToDatabase:
+ ++nbUpdated;
+ break;
+ case importFromDatabase:
+ ++nbUpdatedInDb;
+ break;
+ case askUser:
+ default: // askUSer
+ ++nbConflict;
+ }
+ break;
+ case isSynced:
+ // nothing to do
+ break;
+ case isNewInDatabase:
+ default:
+ // should never be here
+ }
+ }
+ // we distinguish the views new in the database from those deleted from memory
+ for ( DBMetadata metadata: this.exportConnection.getViewsNotInModel().values() ) {
+ if ( metadata.getInitialVersion().getVersion() != 0 )
+ ++nbDeleted; // if the component did exist in the InitialVersion of the model, then it has been deleted from the model
+ else
+ ++nbNewInDb; // else, the component has been created in the database since the model has been loaded
+ }
+ total += nbNew + nbNewInDb + nbUpdated + nbUpdatedInDb + nbDeleted + nbDeletedInDb + nbConflict;
+ if ( updateTextFields ) {
+ this.txtNewViewsInModel.setText(toString(nbNew));
+ this.txtNewViewsInDatabase.setText(toString(nbNewInDb));
+ this.txtUpdatedViewsInModel.setText(toString(nbUpdated));
+ this.txtUpdatedViewsInDatabase.setText(toString(nbUpdatedInDb));
+ this.txtConflictingViews.setText(toString(nbConflict));
+ this.txtDeletedViewsInModel.setText(toString(nbDeleted));
+ this.txtDeletedViewsInDatabase.setText(toString(nbDeletedInDb));
+ }
+
+ nbNew = 0;
+ nbNewInDb = 0;
+ nbUpdated = 0;
+ nbUpdatedInDb = 0;
+ nbConflict = 0;
+ nbDeleted = 0;
+ nbDeletedInDb = 0;
+ Iterator> viewObjectsIterator = this.exportedModel.getAllViewObjects().entrySet().iterator();
+ while (viewObjectsIterator.hasNext()) {
+ IDiagramModelObject viewObject = viewObjectsIterator.next().getValue();
+ DBMetadata metadata = this.exportedModel.getDBMetadata(viewObject);
+ switch ( metadata.getDatabaseStatus() ) {
+ case isNewInModel:
+ ++nbNew;
+ break;
+ case isUpadtedInDatabase:
+ ++nbUpdatedInDb;
+ break;
+ case isUpdatedInModel:
+ ++nbUpdated;
+ break;
+ case isDeletedInDatabase:
+ ++nbDeletedInDb;
+ break;
+ case isConflicting:
+ if ( this.exportedModel.getAllConflicts().get(viewObject) == null )
+ this.exportedModel.getAllConflicts().put(viewObject, CONFLICT_CHOICE.askUser);
+ switch ( this.exportedModel.getAllConflicts().get(viewObject) ) {
+ case doNotExport: // nothing to do
+ break;
+ case exportToDatabase:
+ ++nbUpdated;
+ break;
+ case importFromDatabase:
+ ++nbUpdatedInDb;
+ break;
+ case askUser:
+ default: // askUSer
+ ++nbConflict;
+ }
+ break;
+ case isSynced:
+ // nothing to do
+ break;
+ case isNewInDatabase:
+ default:
+ // should never be here
+ }
+ }
+ // we distinguish the viewObjects new in the database from those deleted from memory
+ for ( DBMetadata metadata: this.exportConnection.getViewObjectsNotInModel().values() ) {
+ if ( metadata.getInitialVersion().getVersion() != 0 )
+ ++nbDeleted; // if the component did exist in the InitialVersion of the model, then it has been deleted from the model
+ else
+ ++nbNewInDb; // else, the component has been created in the database since the model has been loaded
+ }
+ total += nbNew + nbNewInDb + nbUpdated + nbUpdatedInDb + nbDeleted + nbDeletedInDb + nbConflict;
+ if ( updateTextFields ) {
+ this.txtNewViewObjectsInModel.setText(toString(nbNew));
+ this.txtNewViewObjectsInDatabase.setText(toString(nbNewInDb));
+ this.txtUpdatedViewObjectsInModel.setText(toString(nbUpdated));
+ this.txtUpdatedViewObjectsInDatabase.setText(toString(nbUpdatedInDb));
+ this.txtConflictingViewObjects.setText(toString(nbConflict));
+ this.txtDeletedViewObjectsInModel.setText(toString(nbDeleted));
+ this.txtDeletedViewObjectsInDatabase.setText(toString(nbDeletedInDb));
+ }
+
+ nbNew = 0;
+ nbNewInDb = 0;
+ nbUpdated = 0;
+ nbUpdatedInDb = 0;
+ nbConflict = 0;
+ nbDeleted = 0;
+ nbDeletedInDb = 0;
+ Iterator> viewConnectionsIterator = this.exportedModel.getAllViewConnections().entrySet().iterator();
+ while (viewConnectionsIterator.hasNext()) {
+ IDiagramModelConnection viewConnection = viewConnectionsIterator.next().getValue();
+ DBMetadata metadata = this.exportedModel.getDBMetadata(viewConnection);
+ switch ( metadata.getDatabaseStatus() ) {
+ case isNewInModel:
+ ++nbNew;
+ break;
+ case isUpadtedInDatabase:
+ ++nbUpdatedInDb;
+ break;
+ case isUpdatedInModel:
+ ++nbUpdated;
+ break;
+ case isDeletedInDatabase:
+ ++nbDeletedInDb;
+ break;
+ case isConflicting:
+ if ( this.exportedModel.getAllConflicts().get(viewConnection) == null )
+ this.exportedModel.getAllConflicts().put(viewConnection, CONFLICT_CHOICE.askUser);
+ switch ( this.exportedModel.getAllConflicts().get(viewConnection) ) {
+ case doNotExport: // nothing to do
+ break;
+ case exportToDatabase:
+ ++nbUpdated;
+ break;
+ case importFromDatabase:
+ ++nbUpdatedInDb;
+ break;
+ case askUser:
+ default: // askUSer
+ ++nbConflict;
+ }
+ break;
+ case isSynced:
+ // nothing to do
+ break;
+ case isNewInDatabase:
+ default:
+ // should never be here
+ }
+ }
+ // we distinguish the ViewConnections new in the database from those deleted from memory
+ for ( DBMetadata metadata: this.exportConnection.getViewConnectionsNotInModel().values() ) {
+ if ( metadata.getInitialVersion().getVersion() != 0 )
+ ++nbDeleted; // if the component did exist in the InitialVersion of the model, then it has been deleted from the model
+ else
+ ++nbNewInDb; // else, the component has been created in the database since the model has been loaded
+ }
+ total += nbNew + nbNewInDb + nbUpdated + nbUpdatedInDb + nbDeleted + nbDeletedInDb + nbConflict;
+ if ( updateTextFields ) {
+ this.txtNewViewConnectionsInModel.setText(toString(nbNew));
+ this.txtNewViewConnectionsInDatabase.setText(toString(nbNewInDb));
+ this.txtUpdatedViewConnectionsInModel.setText(toString(nbUpdated));
+ this.txtUpdatedViewConnectionsInDatabase.setText(toString(nbUpdatedInDb));
+ this.txtConflictingViewConnections.setText(toString(nbConflict));
+ this.txtDeletedViewConnectionsInModel.setText(toString(nbDeleted));
+ this.txtDeletedViewConnectionsInDatabase.setText(toString(nbDeletedInDb));
+ }
+
+ if ( updateTextFields ) {
+ this.txtNewImagesInModel.setText(toString(this.exportConnection.getImagesNotInDatabase().size()));
+ this.txtNewImagesInDatabase.setText(toString(this.exportConnection.getImagesNotInModel().size()));
+
+ // we log the values uniquely if the updateTextFields has been requestes, else the values are zero
+ logger.info(String.format(" <------ In model ------> <----- In database ---->"));
+ logger.info(String.format(" Total New Updated Deleted New Updated Deleted Conflict"));
+ logger.info(String.format(" Elements: %6d %6d %6d %6d %6d %6d %6d %6d", this.exportedModel.getAllElements().size(), toInt(this.txtNewElementsInModel.getText()), toInt(this.txtUpdatedElementsInModel.getText()), toInt(this.txtDeletedElementsInModel.getText()), toInt(this.txtNewElementsInDatabase.getText()), toInt(this.txtUpdatedElementsInDatabase.getText()), toInt(this.txtDeletedElementsInDatabase.getText()), toInt(this.txtConflictingElements.getText())) );
+ logger.info(String.format(" Relationships: %6d %6d %6d %6d %6d %6d %6d %6d", this.exportedModel.getAllRelationships().size(), toInt(this.txtNewRelationshipsInModel.getText()), toInt(this.txtUpdatedRelationshipsInModel.getText()), toInt(this.txtDeletedRelationshipsInModel.getText()), toInt(this.txtNewRelationshipsInDatabase.getText()), toInt(this.txtUpdatedRelationshipsInDatabase.getText()), toInt(this.txtDeletedRelationshipsInDatabase.getText()), toInt(this.txtConflictingRelationships.getText())) );
+ if ( !DBPlugin.areEqual(this.selectedDatabase.getDriver().toLowerCase(), "neo4j") ) {
+ logger.info(String.format(" Folders: %6d %6d %6d %6d %6d %6d %6d %6d", this.exportedModel.getAllFolders().size(), toInt(this.txtNewFoldersInModel.getText()), toInt(this.txtUpdatedFoldersInModel.getText()), toInt(this.txtDeletedFoldersInModel.getText()), toInt(this.txtNewFoldersInDatabase.getText()), toInt(this.txtUpdatedFoldersInDatabase.getText()), toInt(this.txtDeletedFoldersInDatabase.getText()), toInt(this.txtConflictingFolders.getText())) );
+ logger.info(String.format(" views: %6d %6d %6d %6d %6d %6d %6d %6d", this.exportedModel.getAllViews().size(), toInt(this.txtNewViewsInModel.getText()), toInt(this.txtUpdatedViewsInModel.getText()), toInt(this.txtDeletedViewsInModel.getText()), toInt(this.txtNewViewsInDatabase.getText()), toInt(this.txtUpdatedViewsInDatabase.getText()), toInt(this.txtDeletedViewsInDatabase.getText()), toInt(this.txtConflictingViews.getText())) );
+ logger.info(String.format(" Objects: %6d %6d %6d %6d %6d %6d %6d %6d", this.exportedModel.getAllViewObjects().size(), toInt(this.txtNewViewObjectsInModel.getText()), toInt(this.txtUpdatedViewObjectsInModel.getText()), toInt(this.txtDeletedViewObjectsInModel.getText()), toInt(this.txtNewViewObjectsInDatabase.getText()), toInt(this.txtUpdatedViewObjectsInDatabase.getText()), toInt(this.txtDeletedViewObjectsInDatabase.getText()), toInt(this.txtConflictingViewObjects.getText())) );
+ logger.info(String.format(" Connections: %6d %6d %6d %6d %6d %6d %6d %6d", this.exportedModel.getAllViewConnections().size(), toInt(this.txtNewViewConnectionsInModel.getText()), toInt(this.txtUpdatedViewConnectionsInModel.getText()), toInt(this.txtDeletedViewConnectionsInModel.getText()), toInt(this.txtNewViewConnectionsInDatabase.getText()), toInt(this.txtUpdatedViewConnectionsInDatabase.getText()), toInt(this.txtDeletedViewConnectionsInDatabase.getText()), toInt(this.txtConflictingViewConnections.getText())) );
+ logger.info(String.format(" images: %6d %6d %16s %6d", ((IArchiveManager)this.exportedModel.getAdapter(IArchiveManager.class)).getLoadedImagePaths().size(), toInt(this.txtNewImagesInModel.getText()), "", toInt(this.txtNewImagesInDatabase.getText())) );
+ }
+ }
+
+ closeMessage();
+
+ if ( total == 0 ) {
+ logger.info("The model does not need to be exported to the database.");
+ return true;
+ }
+
+ logger.info("The model needs to be exported to the database.");
+
+ return false;
+ }
+
+ /**
+ * Loop on model components and call doExportEObject to export them
+ *
+ * This method is called when the user clicks on the "Export" button
+ */
+ protected void export() {
+ logger.info("Exporting model: ");
+
+ // we disable the export button to avoid a second click
+ this.btnDoAction.setEnabled(false);
+ this.btnCompareModelToDatabase.setEnabled(false);
+
+ // We show up a small arrow in front of the second action "export components"
+ setActiveAction(STATUS.Ok);
+ setActiveAction(ACTION.Two);
+ disableOption();
+
+ // then we disable the name, purpose and release note text fields
+ this.txtModelName.setEnabled(false);
+ this.txtPurpose.setEnabled(false);
+ this.txtReleaseNote.setEnabled(false);
+
+ // we force the modelVersion and component groups to be visible (in case we come from the conflict resolution)
+ this.grpComponents.setVisible(true);
+ this.grpModelVersions.setVisible(true);
+
+ // commands that can be undone in case the export fails or is cancelled by the user
+ DBCompoundCommand undoableCommands = new DBCompoundCommand("Sync model with database");
+
+ boolean isNeo4JDatabase = DBPlugin.areEqual(this.selectedDatabase.getDriver().toLowerCase(), "neo4j");
+
+ String errorMessage = "Exporting model to the database"; // the error message that will be printed in case an exception is raised.
+ try {
+ //////////////////////////// PREPARATION PHASE : we calculate the model's checksum
+ logger.info("Calculating model's checksum.");
+ errorMessage = "Failed to calculate the model's checksum.";
+
+ if ( !DBPlugin.areEqual(this.exportedModel.getName(), this.txtModelName.getText()) )
+ this.exportedModel.setName(this.txtModelName.getText());
+
+ if ( !DBPlugin.areEqual(this.exportedModel.getPurpose(), this.txtPurpose.getText()) )
+ this.exportedModel.setPurpose(this.txtPurpose.getText());
+
+ this.exportedModel.getCurrentVersion().setChecksum(DBChecksum.calculateChecksum(this.exportedModel, this.txtReleaseNote.getText()));
+
+ // we reset the counters as they will be updated during the import and export process
+ this.txtTotalElements.setText(this.ZERO); this.txtNewElementsInModel.setText(this.ZERO); this.txtUpdatedElementsInModel.setText(this.ZERO); this.txtDeletedElementsInModel.setText(this.ZERO); this.txtNewElementsInDatabase.setText(this.ZERO); this.txtUpdatedElementsInDatabase.setText(this.ZERO); this.txtDeletedElementsInDatabase.setText(this.ZERO); this.txtConflictingElements.setText(this.ZERO);
+ this.txtTotalRelationships.setText(this.ZERO); this.txtNewRelationshipsInModel.setText(this.ZERO); this.txtUpdatedRelationshipsInModel.setText(this.ZERO); this.txtDeletedRelationshipsInModel.setText(this.ZERO); this.txtNewRelationshipsInDatabase.setText(this.ZERO); this.txtUpdatedRelationshipsInDatabase.setText(this.ZERO); this.txtDeletedRelationshipsInDatabase.setText(this.ZERO); this.txtConflictingRelationships.setText(this.ZERO);
+ this.txtTotalFolders.setText(this.ZERO); this.txtNewFoldersInModel.setText(this.ZERO); this.txtUpdatedFoldersInModel.setText(this.ZERO); this.txtDeletedFoldersInModel.setText(this.ZERO); this.txtNewFoldersInDatabase.setText(this.ZERO); this.txtUpdatedFoldersInDatabase.setText(this.ZERO); this.txtDeletedFoldersInDatabase.setText(this.ZERO); this.txtConflictingFolders.setText(this.ZERO);
+ this.txtTotalViews.setText(this.ZERO); this.txtNewViewsInModel.setText(this.ZERO); this.txtUpdatedViewsInModel.setText(this.ZERO); this.txtDeletedViewsInModel.setText(this.ZERO); this.txtNewViewsInDatabase.setText(this.ZERO); this.txtUpdatedViewsInDatabase.setText(this.ZERO); this.txtDeletedViewsInDatabase.setText(this.ZERO); this.txtConflictingViews.setText(this.ZERO);
+ this.txtTotalViewObjects.setText(this.ZERO); this.txtNewViewObjectsInModel.setText(this.ZERO); this.txtUpdatedViewObjectsInModel.setText(this.ZERO); this.txtDeletedViewObjectsInModel.setText(this.ZERO); this.txtNewViewObjectsInDatabase.setText(this.ZERO); this.txtUpdatedViewObjectsInDatabase.setText(this.ZERO); this.txtDeletedViewObjectsInDatabase.setText(this.ZERO); this.txtConflictingViewObjects.setText(this.ZERO);
+ this.txtTotalViewConnections.setText(this.ZERO); this.txtNewViewConnectionsInModel.setText(this.ZERO); this.txtUpdatedViewConnectionsInModel.setText(this.ZERO); this.txtDeletedViewConnectionsInModel.setText(this.ZERO); this.txtNewViewConnectionsInDatabase.setText(this.ZERO); this.txtUpdatedViewConnectionsInDatabase.setText(this.ZERO); this.txtDeletedViewConnectionsInDatabase.setText(this.ZERO); this.txtConflictingViewConnections.setText(this.ZERO);
+ this.txtTotalImages.setText(this.ZERO); this.txtNewImagesInModel.setText(this.ZERO); this.txtNewImagesInDatabase.setText(this.ZERO);
+
+
+ //////////////////////////// PHASE 1 : we compare the model to the database
+
+ if ( !isNeo4JDatabase ) {
+ if ( compareModelToDatabase(false) ) {
+ setActiveAction(STATUS.Ok);
+ doShowResult(STATUS.Ok, "Nothing has been exported as the database is already up to date.");
+ return;
+ }
+ }
+
+ //////////////////////////// PHASE 2 : we detect the conflicts and ask the user to resolve them
+
+ if ( !isNeo4JDatabase ) {
+ setMessage("Checking for conflicts ...");
+ errorMessage = "Can't show up the list of conflicting components.";
+
+ hideGrpDatabase();
+ createGrpConflict();
+
+ Iterator> elementsIterator = this.exportedModel.getAllElements().entrySet().iterator();
+ while ( elementsIterator.hasNext() ) {
+ IArchimateElement element = elementsIterator.next().getValue();
+ if ( this.exportedModel.getDBMetadata(element).getDatabaseStatus() == DATABASE_STATUS.isConflicting ) {
+ if ( this.exportedModel.getAllConflicts().get(element) != null ) {
+ this.exportedModel.getAllConflicts().put(element, CONFLICT_CHOICE.askUser);
+ TableItem item = new TableItem(this.tblListConflicts, SWT.NONE);
+ item.setText(element.getId());
+ item.setData(element);
+ }
+ }
+ }
+
+ Iterator> relationshipsIterator = this.exportedModel.getAllRelationships().entrySet().iterator();
+ while ( relationshipsIterator.hasNext() ) {
+ IArchimateRelationship relationship = relationshipsIterator.next().getValue();
+ if ( this.exportedModel.getDBMetadata(relationship).getDatabaseStatus() == DATABASE_STATUS.isConflicting ) {
+ if ( this.exportedModel.getAllConflicts().get(relationship) != null ) {
+ this.exportedModel.getAllConflicts().put(relationship, CONFLICT_CHOICE.askUser);
+ TableItem item = new TableItem(this.tblListConflicts, SWT.NONE);
+ item.setText(relationship.getId());
+ item.setData(relationship);
+ }
+ }
+ }
+
+ Iterator> viewsIterator = this.exportedModel.getAllViews().entrySet().iterator();
+ while ( viewsIterator.hasNext() ) {
+ IDiagramModel view = viewsIterator.next().getValue();
+ if ( this.exportedModel.getDBMetadata(view).getDatabaseStatus() == DATABASE_STATUS.isConflicting ) {
+ if ( this.exportedModel.getAllConflicts().get(view) != null ) {
+ this.exportedModel.getAllConflicts().put(view, CONFLICT_CHOICE.askUser);
+ TableItem item = new TableItem(this.tblListConflicts, SWT.NONE);
+ item.setText(view.getId());
+ item.setData(view);
+ }
+ }
+ }
+
+ Iterator> viewObjectsIterator = this.exportedModel.getAllViewObjects().entrySet().iterator();
+ while ( viewObjectsIterator.hasNext() ) {
+ IDiagramModelObject viewObject = viewObjectsIterator.next().getValue();
+ if ( this.exportedModel.getDBMetadata(viewObject).getDatabaseStatus() == DATABASE_STATUS.isConflicting ) {
+ if ( this.exportedModel.getAllConflicts().get(viewObject) != null ) {
+ this.exportedModel.getAllConflicts().put(viewObject, CONFLICT_CHOICE.askUser);
+ TableItem item = new TableItem(this.tblListConflicts, SWT.NONE);
+ item.setText(viewObject.getId());
+ item.setData(viewObject);
+ }
+ }
+ }
+
+ Iterator> viewConnectionsIterator = this.exportedModel.getAllViewConnections().entrySet().iterator();
+ while ( viewConnectionsIterator.hasNext() ) {
+ IDiagramModelConnection viewConnection = viewConnectionsIterator.next().getValue();
+ if ( this.exportedModel.getDBMetadata(viewConnection).getDatabaseStatus() == DATABASE_STATUS.isConflicting ) {
+ if ( this.exportedModel.getAllConflicts().get(viewConnection) != null ) {
+ this.exportedModel.getAllConflicts().put(viewConnection, CONFLICT_CHOICE.askUser);
+ TableItem item = new TableItem(this.tblListConflicts, SWT.NONE);
+ item.setText(viewConnection.getId());
+ item.setData(viewConnection);
+ }
+ }
+ }
+
+ // If there are some conflicts to resolve, then we show the grpConflict group
+ //TODO: ameliorate the conflict resolution by keeping all the conflicts in the tblListConflict but add a column with the resolution choosen by the user
+ //TODO: in that case, the export could be effectively done when all the tableItems hve got a solution distinct from askUser
+ if ( this.tblListConflicts.getItemCount() > 0 ) {
+ this.tblListConflicts.setSelection(0);
+
+ this.tblListConflicts.notifyListeners(SWT.Selection, new Event()); // shows up the tblListConflicts table and calls fillInCompareTable()
+
+ // when the conflicts are resolved, the export() method will be called again
+ return;
+ }
+ }
+
+ // if we're here, this means that there is no conflict or that all the conflicts have been resolved
+
+ //////////////////////////// PHASE 3 : we remove from the model the components that have been deleted in the database
+ if ( !isNeo4JDatabase ) {
+ setMessage("Removing from the model the elements that have been deleted in the database ...");
+ errorMessage = "Failed to remove from the model the elements that have been deleted in the database.";
+
+ // please be aware that the commands put in the undoableCommand are single operations
+ // ie. when an element is deleted, the command does not delete at the same time the relationships connected to it, not the views objets that references it.
+
+ // we do not use getException() method as Archi commands do not implement it
+
+ Iterator> elementsIterator = this.exportedModel.getAllElements().entrySet().iterator();
+ while ( elementsIterator.hasNext() ) {
+ IArchimateElement element = elementsIterator.next().getValue();
+ if ( this.exportedModel.getDBMetadata(element).getDatabaseStatus() == DATABASE_STATUS.isDeletedInDatabase ) {
+ undoableCommands.add(new DeleteArchimateElementCommand(element));
+ incrementText(this.txtDeletedElementsInDatabase);
+ decrementText(this.txtTotalElements);
+ }
+ }
+
+ Iterator> relationshipsIterator = this.exportedModel.getAllRelationships().entrySet().iterator();
+ while ( relationshipsIterator.hasNext() ) {
+ IArchimateRelationship relationship = relationshipsIterator.next().getValue();
+ if ( this.exportedModel.getDBMetadata(relationship).getDatabaseStatus() == DATABASE_STATUS.isDeletedInDatabase ) {
+ undoableCommands.add(new DeleteArchimateRelationshipCommand(relationship));
+ incrementText(this.txtDeletedRelationshipsInDatabase);
+ decrementText(this.txtTotalRelationships);
+ }
+ }
+
+ Iterator> foldersIterator = this.exportedModel.getAllFolders().entrySet().iterator();
+ while ( foldersIterator.hasNext() ) {
+ IFolder folder = foldersIterator.next().getValue();
+ if ( this.exportedModel.getDBMetadata(folder).getDatabaseStatus() == DATABASE_STATUS.isDeletedInDatabase ) {
+ undoableCommands.add(new DeleteFolderCommand(folder));
+ incrementText(this.txtDeletedFoldersInDatabase);
+ decrementText(this.txtTotalFolders);
+ }
+ }
+
+ Iterator> viewsIterator = this.exportedModel.getAllViews().entrySet().iterator();
+ while ( viewsIterator.hasNext() ) {
+ IDiagramModel view = viewsIterator.next().getValue();
+ if ( this.exportedModel.getDBMetadata(view).getDatabaseStatus() == DATABASE_STATUS.isDeletedInDatabase ) {
+ undoableCommands.add(new DeleteDiagramModelCommand(view));
+ incrementText(this.txtDeletedViewsInDatabase);
+ decrementText(this.txtTotalViews);
+ }
+ }
+
+ Iterator> viewObjectsIterator = this.exportedModel.getAllViewObjects().entrySet().iterator();
+ while ( viewObjectsIterator.hasNext() ) {
+ IDiagramModelObject viewObject = viewObjectsIterator.next().getValue();
+ if ( this.exportedModel.getDBMetadata(viewObject).getDatabaseStatus() == DATABASE_STATUS.isDeletedInDatabase ) {
+ undoableCommands.checkAndAdd(new DBDeleteDiagramObjectCommand(this.exportedModel, viewObject));
+ incrementText(this.txtDeletedViewObjectsInDatabase);
+ decrementText(this.txtTotalViewObjects);
+ }
+ }
+
+ Iterator> viewConnectionsIterator = this.exportedModel.getAllViewConnections().entrySet().iterator();
+ while ( viewConnectionsIterator.hasNext() ) {
+ IDiagramModelConnection viewConnection = viewConnectionsIterator.next().getValue();
+ if ( this.exportedModel.getDBMetadata(viewConnection).getDatabaseStatus() == DATABASE_STATUS.isDeletedInDatabase ) {
+ undoableCommands.checkAndAdd(new DBDeleteDiagramConnectionCommand(this.exportedModel, viewConnection));
+ incrementText(this.txtDeletedViewConnectionsInDatabase);
+ decrementText(this.txtTotalViewConnections);
+ }
+ }
+
+ if ( !undoableCommands.isEmpty() )
+ undoableCommands.execute();
+ }
+
+ //////////////////////////// PHASE 4 : we import new and updated components from the database
+ if ( !isNeo4JDatabase ) {
+ // the commands are run in real time, but they are also added in the undoableCommands compound command because we want to be able to undo them
+ // they all implement the a getException() method that allow to check if an exception has been raised during the import
+
+ // we count the number of new components to import from the database
+ int progressBarWidth = this.exportConnection.getFoldersNotInModel().size() + this.exportConnection.getElementsNotInModel().size() + this.exportConnection.getRelationshipsNotInModel().size() + this.exportConnection.getViewsNotInModel().size() + this.exportConnection.getViewObjectsNotInModel().size() + this.exportConnection.getViewConnectionsNotInModel().size();
+
+ // we add the number of updated components to import from the database
+ Iterator> foldersIterator = this.exportedModel.getAllFolders().entrySet().iterator();
+ while ( foldersIterator.hasNext() ) if ( this.exportedModel.getDBMetadata(foldersIterator.next().getValue()).getDatabaseStatus() == DATABASE_STATUS.isUpadtedInDatabase ) ++progressBarWidth;
+
+ Iterator> elementsIterator = this.exportedModel.getAllElements().entrySet().iterator();
+ while ( elementsIterator.hasNext() ) if ( this.exportedModel.getDBMetadata(elementsIterator.next().getValue()).getDatabaseStatus() == DATABASE_STATUS.isUpadtedInDatabase ) ++progressBarWidth;
+
+ Iterator> relationshipsIterator = this.exportedModel.getAllRelationships().entrySet().iterator();
+ while ( relationshipsIterator.hasNext() ) if ( this.exportedModel.getDBMetadata(relationshipsIterator.next().getValue()).getDatabaseStatus() == DATABASE_STATUS.isUpadtedInDatabase ) ++progressBarWidth;
+
+ Iterator> viewsIterator = this.exportedModel.getAllViews().entrySet().iterator();
+ while ( viewsIterator.hasNext() ) if ( this.exportedModel.getDBMetadata(viewsIterator.next().getValue()).getDatabaseStatus() == DATABASE_STATUS.isUpadtedInDatabase ) ++progressBarWidth;
+
+ Iterator> viewObjectsIterator = this.exportedModel.getAllViewObjects().entrySet().iterator();
+ while ( viewObjectsIterator.hasNext() ) if ( this.exportedModel.getDBMetadata(viewObjectsIterator.next().getValue()).getDatabaseStatus() == DATABASE_STATUS.isUpadtedInDatabase ) ++progressBarWidth;
+
+ Iterator> viewConnectionsIterator = this.exportedModel.getAllViewConnections().entrySet().iterator();
+ while ( viewConnectionsIterator.hasNext() ) if ( this.exportedModel.getDBMetadata(viewConnectionsIterator.next().getValue()).getDatabaseStatus() == DATABASE_STATUS.isUpadtedInDatabase ) ++progressBarWidth;
+
+ // we count the number of conflict that have been resolved by an import from the database
+ Iterator> conflictsIterator = this.exportedModel.getAllConflicts().entrySet().iterator();
+ while ( conflictsIterator.hasNext() ) {
+ CONFLICT_CHOICE choice = conflictsIterator.next().getValue();
+ if ( choice == CONFLICT_CHOICE.importFromDatabase )
+ ++progressBarWidth;
+ }
+
+ if ( progressBarWidth == 0 )
+ logger.info("There is no component to import from the database.");
+ else {
+ createProgressBar("Importing components from the database ...", 0, progressBarWidth);
+ errorMessage = "Failed to import components from the database.";
+
+ try ( DBDatabaseImportConnection importConnection = new DBDatabaseImportConnection(this.exportConnection) ) {
+
+
+ // IMPORT FOLDERS (we import the folders BEFORE the elements, relationships and views because they must exist when the elements, relationships and views are imported)
+ if ( this.exportConnection.getFoldersNotInModel().size() == 0 )
+ logger.info("There is no folder to import.");
+ else {
+ logger.info("Importing new folders ...");
+ setProgressBarLabel("Importing new folders ...");
+ for (String id : this.exportConnection.getFoldersNotInModel().keySet() ) {
+ DBMetadata versionToImport = this.exportConnection.getFoldersNotInModel().get(id);
+ if ( versionToImport.getInitialVersion().getVersion() == 0 ) {
+ if ( logger.isDebugEnabled() ) logger.debug("The folder id "+id+" has been created in the database. We import it from the database.");
+ undoableCommands.checkAndExecute(new DBImportFolderFromIdCommand(importConnection, this.exportedModel, null, id, versionToImport.getLatestDatabaseVersion().getVersion(), DBImportMode.forceSharedMode));
+ incrementText(this.txtNewFoldersInDatabase);
+ incrementText(this.txtTotalFolders);
+ } else {
+ if ( logger.isDebugEnabled() ) logger.debug("The folder id "+id+" is not imported as it has been deleted from the model.");
+ incrementText(this.txtDeletedFoldersInModel);
+ }
+ }
+ }
+
+ // UPDATE FOLDERS
+ foldersIterator = this.exportedModel.getAllFolders().entrySet().iterator();
+ while ( foldersIterator.hasNext() ) {
+ IFolder folder = foldersIterator.next().getValue();
+ if ( this.exportedModel.getDBMetadata(folder).getDatabaseStatus() == DATABASE_STATUS.isUpadtedInDatabase ) {
+ if ( logger.isDebugEnabled() ) logger.debug("The folder id "+folder.getId()+" has been updated in the database. We import the new version from the database.");
+ undoableCommands.checkAndExecute(new DBImportFolderFromIdCommand(importConnection, this.exportedModel, null, folder.getId(), 0, DBImportMode.forceSharedMode));
+ incrementText(this.txtUpdatedFoldersInDatabase);
+ }
+ }
+
+
+ // IMPORT ELEMENTS
+ if ( this.exportConnection.getElementsNotInModel().size() == 0 )
+ logger.info("There is no element to import.");
+ else {
+ logger.info("Importing new elements ...");
+ setProgressBarLabel("Importing new elements ...");
+ for (String id : this.exportConnection.getElementsNotInModel().keySet() ) {
+ DBMetadata versionToImport = this.exportConnection.getElementsNotInModel().get(id);
+ if ( versionToImport.getInitialVersion().getVersion() == 0 ) {
+ if ( logger.isDebugEnabled() ) logger.debug("The element id "+id+" has been created in the database. We import it from the database.");
+ undoableCommands.checkAndExecute(new DBImportElementFromIdCommand(importConnection, this.exportedModel, null, null, id, versionToImport.getLatestDatabaseVersion().getVersion(), DBImportMode.forceSharedMode, false));
+ incrementText(this.txtNewElementsInDatabase);
+ incrementText(this.txtTotalElements);
+ } else {
+ if ( logger.isDebugEnabled() ) logger.debug("The element id "+id+" is not imported as it has been deleted from the model.");
+ incrementText(this.txtDeletedElementsInModel);
+ }
+ }
+ }
+
+ // UPDATE ELEMENTS
+ elementsIterator = this.exportedModel.getAllElements().entrySet().iterator();
+ while ( elementsIterator.hasNext() ) {
+ IArchimateElement element = elementsIterator.next().getValue();
+ if ( this.exportedModel.getDBMetadata(element).getDatabaseStatus() == DATABASE_STATUS.isUpadtedInDatabase ) {
+ if ( logger.isDebugEnabled() ) logger.debug("The element id "+element.getId()+" has been updated in the database. We import the new version from the database.");
+ undoableCommands.checkAndExecute(new DBImportElementFromIdCommand(importConnection, this.exportedModel, null, null, element.getId(), 0, DBImportMode.forceSharedMode, false));
+ incrementText(this.txtUpdatedElementsInDatabase);
+ }
+ }
+
+ // IMPORT RELATIONSHIPS
+ if ( this.exportConnection.getRelationshipsNotInModel().size() == 0 )
+ logger.info("There is no relationship to import.");
+ else {
+ logger.info("Importing new relationships ...");
+ setProgressBarLabel("Importing new relationships ...");
+ for (String id : this.exportConnection.getRelationshipsNotInModel().keySet() ) {
+ DBMetadata versionToImport = this.exportConnection.getRelationshipsNotInModel().get(id);
+ if ( versionToImport.getInitialVersion().getVersion() == 0 ) {
+ if ( logger.isDebugEnabled() ) logger.debug("The relationship id "+id+" has been created in the database. We import it from the database.");
+ undoableCommands.checkAndExecute(new DBImportRelationshipFromIdCommand(importConnection, this.exportedModel, null, null, id, versionToImport.getLatestDatabaseVersion().getVersion(), DBImportMode.forceSharedMode));
+ incrementText(this.txtNewRelationshipsInDatabase);
+ incrementText(this.txtTotalRelationships);
+ } else {
+ if ( logger.isDebugEnabled() ) logger.debug("The relationship id "+id+" is not imported as it has been deleted from the model.");
+ incrementText(this.txtDeletedRelationshipsInModel);
+ }
+ }
+ }
+
+ // UPDATE RELATIONSHIPS
+ relationshipsIterator = this.exportedModel.getAllRelationships().entrySet().iterator();
+ while ( relationshipsIterator.hasNext() ) {
+ IArchimateRelationship relationship = relationshipsIterator.next().getValue();
+ if ( this.exportedModel.getDBMetadata(relationship).getDatabaseStatus() == DATABASE_STATUS.isUpadtedInDatabase ) {
+ if ( logger.isDebugEnabled() ) logger.debug("The relationship id "+relationship.getId()+" has been updated in the database. We import the new version from the database.");
+ undoableCommands.checkAndExecute(new DBImportRelationshipFromIdCommand(importConnection, this.exportedModel, null, null, relationship.getId(), 0, DBImportMode.forceSharedMode));
+ incrementText(this.txtUpdatedRelationshipsInDatabase);
+ }
+ }
+
+ // IMPORT VIEWS
+ if ( this.exportConnection.getViewsNotInModel().size() == 0 )
+ logger.info("There is no view to import.");
+ else {
+ logger.info("Importing new views ...");
+ setProgressBarLabel("Importing new views ...");
+ for (String id : this.exportConnection.getViewsNotInModel().keySet() ) {
+ DBMetadata versionToImport = this.exportConnection.getViewsNotInModel().get(id);
+ if ( versionToImport.getInitialVersion().getVersion() == 0 ) {
+ if ( logger.isDebugEnabled() ) logger.debug("The view id "+id+" has been created in the database. We import it in the model.");
+ undoableCommands.checkAndExecute(new DBImportViewFromIdCommand(importConnection, this.exportedModel, null, id, versionToImport.getLatestDatabaseVersion().getVersion(), DBImportMode.forceSharedMode, false));
+ incrementText(this.txtNewViewsInDatabase);
+ incrementText(this.txtTotalViews);
+ } else {
+ if ( logger.isDebugEnabled() ) logger.debug("The view id "+id+" is not imported as it has been deleted from the model.");
+ incrementText(this.txtDeletedViewsInModel);
+ }
+ }
+ }
+
+ // UPDATE VIEWS
+ viewsIterator = this.exportedModel.getAllViews().entrySet().iterator();
+ while ( viewsIterator.hasNext() ) {
+ IDiagramModel view = viewsIterator.next().getValue();
+ if ( this.exportedModel.getDBMetadata(view).getDatabaseStatus() == DATABASE_STATUS.isUpadtedInDatabase ) {
+ if ( logger.isDebugEnabled() ) logger.debug("The view id "+view.getId()+" has been updated in the database. We import the new version from the database.");
+ undoableCommands.checkAndExecute(new DBImportViewFromIdCommand(importConnection, this.exportedModel, null, view.getId(), 0, DBImportMode.forceSharedMode, false));
+ incrementText(this.txtUpdatedViewsInDatabase);
+ }
+ }
+
+ // IMPORT VIEW OBJECTS
+ if ( this.exportConnection.getViewObjectsNotInModel().size() == 0 )
+ logger.info("There is no view object to import.");
+ else {
+ logger.info("Importing new views objects ...");
+ setProgressBarLabel("Importing new views objects ...");
+ for (String id : this.exportConnection.getViewObjectsNotInModel().keySet() ) {
+ DBMetadata versionToImport = this.exportConnection.getViewObjectsNotInModel().get(id);
+ if ( versionToImport.getInitialVersion().getVersion() == 0 ) {
+ if ( logger.isDebugEnabled() ) logger.debug("The view object id "+id+" has been created in the database. We import it in the model.");
+ undoableCommands.checkAndExecute(new DBImportViewObjectFromIdCommand(importConnection, this.exportedModel, id, versionToImport.getLatestDatabaseVersion().getVersion(), false, DBImportMode.forceSharedMode));
+ incrementText(this.txtNewViewObjectsInDatabase);
+ incrementText(this.txtTotalViewObjects);
+ } else {
+ if ( logger.isDebugEnabled() ) logger.debug("The view object id "+id+" is not imported as it has been deleted from the model.");
+ incrementText(this.txtDeletedViewObjectsInModel);
+ }
+ }
+ }
+
+ // UPDATE VIEW OBJECTS
+ viewObjectsIterator = this.exportedModel.getAllViewObjects().entrySet().iterator();
+ while ( viewObjectsIterator.hasNext() ) {
+ IDiagramModelObject viewObject = viewObjectsIterator.next().getValue();
+ if ( this.exportedModel.getDBMetadata(viewObject).getDatabaseStatus() == DATABASE_STATUS.isUpadtedInDatabase ) {
+ if ( logger.isDebugEnabled() ) logger.debug("The view object id "+viewObject.getId()+" has been updated in the database. We import the new version from the database.");
+ undoableCommands.checkAndExecute(new DBImportViewObjectFromIdCommand(importConnection, this.exportedModel, viewObject.getId(), 0, false, DBImportMode.forceSharedMode));
+ incrementText(this.txtUpdatedViewObjectsInDatabase);
+ }
+ }
+
+ // IMPORT VIEW CONNECTIONS
+ if ( this.exportConnection.getViewConnectionsNotInModel().size() == 0 )
+ logger.info("There is no view connection to import.");
+ else {
+ logger.info("Importing new views connections ...");
+ setProgressBarLabel("Importing new views connections ...");
+ for (String id : this.exportConnection.getViewConnectionsNotInModel().keySet() ) {
+ DBMetadata versionToImport = this.exportConnection.getViewConnectionsNotInModel().get(id);
+ if ( versionToImport.getInitialVersion().getVersion() == 0 ) {
+ if ( logger.isDebugEnabled() ) logger.debug("The view connection id "+id+" has been created in the database. We import it in the model.");
+ undoableCommands.checkAndExecute(new DBImportViewConnectionFromIdCommand(importConnection, this.exportedModel, id, versionToImport.getLatestDatabaseVersion().getVersion(), false, DBImportMode.forceSharedMode));
+ incrementText(this.txtNewViewConnectionsInDatabase);
+ incrementText(this.txtTotalViewConnections);
+ } else {
+ if ( logger.isDebugEnabled() ) logger.debug("The view connection id "+id+" is not imported as it has been deleted from the model.");
+ incrementText(this.txtDeletedViewConnectionsInModel);
+ }
+ }
+ }
+
+ // UPDATE VIEW CONNECTIONS
+ viewConnectionsIterator = this.exportedModel.getAllViewConnections().entrySet().iterator();
+ while ( viewConnectionsIterator.hasNext() ) {
+ IDiagramModelConnection viewConnection = viewConnectionsIterator.next().getValue();
+ if ( this.exportedModel.getDBMetadata(viewConnection).getDatabaseStatus() == DATABASE_STATUS.isUpadtedInDatabase ) {
+ if ( logger.isDebugEnabled() ) logger.debug("The view connection id "+viewConnection.getId()+" has been updated in the database. We import the new version from the database.");
+ undoableCommands.checkAndExecute(new DBImportViewConnectionFromIdCommand(importConnection, this.exportedModel, viewConnection.getId(), 0, false, DBImportMode.forceSharedMode));
+ incrementText(this.txtUpdatedViewConnectionsInDatabase);
+ }
+ }
+
+ conflictsIterator = this.exportedModel.getAllConflicts().entrySet().iterator();
+ while ( conflictsIterator.hasNext() ) {
+ Entry entry = conflictsIterator.next();
+ EObject componentToImport = entry.getKey();
+ CONFLICT_CHOICE choice = entry.getValue();
+
+ if ( choice == CONFLICT_CHOICE.importFromDatabase ) {
+ IDBCommand command = null;
+ String id = ((IIdentifier)componentToImport).getId();
+ DBMetadata metadata = this.exportedModel.getDBMetadata(componentToImport);
+ int latestDatabaseVersion = metadata.getLatestDatabaseVersion().getVersion();
+
+ if ( componentToImport instanceof IArchimateElement ) {
+ command = new DBImportElementFromIdCommand(importConnection, this.exportedModel, null, null, id, latestDatabaseVersion, DBImportMode.forceSharedMode, false);
+ incrementText(this.txtUpdatedElementsInDatabase);
+ } else if ( componentToImport instanceof IArchimateRelationship ) {
+ command = new DBImportRelationshipFromIdCommand(importConnection, this.exportedModel, null, null, id, latestDatabaseVersion, DBImportMode.forceSharedMode);
+ incrementText(this.txtUpdatedRelationshipsInDatabase);
+ } else if ( componentToImport instanceof IDiagramModel) {
+ command = new DBImportViewFromIdCommand(importConnection, this.exportedModel, null, id, latestDatabaseVersion, DBImportMode.forceSharedMode, false);
+ incrementText(this.txtUpdatedViewsInDatabase);
+ } else if ( componentToImport instanceof IDiagramModelObject ) {
+ command = new DBImportViewObjectFromIdCommand(importConnection, this.exportedModel, id, latestDatabaseVersion, false, DBImportMode.forceSharedMode);
+ incrementText(this.txtUpdatedViewObjectsInDatabase);
+ } else if ( componentToImport instanceof IDiagramModelConnection ) {
+ command = new DBImportViewConnectionFromIdCommand(importConnection, this.exportedModel, id, latestDatabaseVersion, false, DBImportMode.forceSharedMode);
+ incrementText(this.txtUpdatedViewConnectionsInDatabase);
+ }
+
+ if ( logger.isDebugEnabled() ) logger.debug("The conflicting "+metadata.getDebugName()+" conflicts with the database, but the conflict resolution has been set to "+CONFLICT_CHOICE.importFromDatabase);
+ undoableCommands.checkAndExecute(command);
+ }
+ }
+
+ // RESOLVE RELATIONSHIPS
+ if ( (this.exportedModel.getAllSourceRelationshipsToResolve().size() != 0) || (this.exportedModel.getAllTargetRelationshipsToResolve().size() != 0) ) {
+ setProgressBarLabel("Resolving relationships ...");
+ undoableCommands.checkAndExecute(new DBResolveRelationshipsCommand(this.exportedModel));
+ }
+
+ // RESOLVE CONNECTIONS
+ if ( (this.exportedModel.getAllSourceConnectionsToResolve().size() != 0) || (this.exportedModel.getAllTargetConnectionsToResolve().size() != 0) ) {
+ setProgressBarLabel("Resolving views connections ...");
+ undoableCommands.checkAndExecute(new DBResolveConnectionsCommand(this.exportedModel));
+ }
+ } finally {
+ hideProgressBar();
+ }
+ }
+ }
+
+ //////////////////////////// PHASE 5 : we move components to new folders if they've been moved in the database
+ if ( !isNeo4JDatabase ) {
+ setMessage("Checking if components have been moved to new folder ...");
+ errorMessage = "Failed to move components to a new folder.";
+
+ try ( DBDatabaseImportConnection importConnection = new DBDatabaseImportConnection(this.exportConnection) ) {
+ DBSetFolderToLastKnownCommand setFolderCommand = new DBSetFolderToLastKnownCommand(this.exportedModel, importConnection);
+ if ( setFolderCommand.getException() != null )
+ throw setFolderCommand.getException();
+ if ( setFolderCommand.needsToBeExecuted() ) {
+ logger.info("Moving components to new folders");
+ undoableCommands.checkAndExecute(setFolderCommand);
+ } else
+ logger.info("There is no component to move to a new folder.");
+ }
+ }
+
+ //////////////////////////// PHASE 6 : we recalculate all the checksums and the "getAll..." maps as all the containers may have changed because of imported and deleted components
+ if ( !isNeo4JDatabase && !undoableCommands.isEmpty() ) {
+ setMessage("Recalculating checksums ");
+ errorMessage = "Failed to recalculate checksums.";
+
+ // recalculate the checksum. This does not update the versions, so the database status remains.
+ this.exportedModel.countAllObjects();
+ }
+
+ ////////////////////////////PHASE 7 : we re-compare the model to the database as the imports may have been sufficient
+ if ( !isNeo4JDatabase && !undoableCommands.isEmpty() ) {
+ if ( compareModelToDatabase(false) ) {
+ setActiveAction(STATUS.Ok);
+ doShowResult(STATUS.Ok, "Your model is now in sync with the database.");
+ // TODO: loop on getAllXXX to fill in the txtTotalXXXX fields
+ return;
+ }
+ }
+
+ //////////////////////////// PHASE 8 : at last, we export a new version of the model to the database
+ int progressBarWidth = this.exportedModel.getAllElements().size() + this.exportedModel.getAllRelationships().size();
+ if ( !isNeo4JDatabase )
+ progressBarWidth += this.exportedModel.getAllFolders().size() + this.exportedModel.getAllViews().size() + this.exportedModel.getAllViewObjects().size() + this.exportedModel.getAllViewConnections().size();
+
+ createProgressBar("Exporting model to the database ...", 0, progressBarWidth);
+ errorMessage = "Failed to export the model to the database";
+
+ // we start a new database transaction
+ this.exportConnection.setAutoCommit(false);
+
+ if ( !isNeo4JDatabase ) {
+ logger.info("Exporting the model itslef ...");
+ this.exportConnection.exportModel(this.exportedModel, this.txtReleaseNote.getText());
+ } else {
+ if ( this.selectedDatabase.shouldEmptyNeo4jDB() ) {
+ errorMessage = "Failed to empty the Neo4J database.";
+ this.exportConnection.emptyNeo4jDB();
+ }
+ }
+
+ // EXPORT PROFILES
+ setProgressBarLabel("Exporting specializations ...");
+ Iterator profilesIterator = this.exportedModel.getProfiles().iterator();
+ while ( profilesIterator.hasNext() ) {
+ EObject componentToExport = profilesIterator.next();
+ if ( isNeo4JDatabase )
+ doExport(componentToExport, this.txtNewProfilesInModel);
+ else {
+ DATABASE_STATUS dbStatus = this.exportedModel.getDBMetadata(componentToExport).getDatabaseStatus();
+ if ( dbStatus == DATABASE_STATUS.isNewInModel )
+ doExport(componentToExport, this.txtNewProfilesInModel);
+ else if ( dbStatus == DATABASE_STATUS.isUpdatedInModel )
+ doExport(componentToExport, this.txtUpdatedProfilesInModel);
+
+ this.exportConnection.assignEObjectToModel(componentToExport);
+ }
+ incrementText(this.txtTotalProfiles);
+ increaseProgressBar();
+ }
+
+ // EXPORT ELEMENTS
+ setProgressBarLabel("Exporting elements ...");
+ Iterator> elementsIterator = this.exportedModel.getAllElements().entrySet().iterator();
+ while ( elementsIterator.hasNext() ) {
+ EObject componentToExport = elementsIterator.next().getValue();
+ if ( isNeo4JDatabase )
+ doExport(componentToExport, this.txtNewElementsInModel);
+ else {
+ DATABASE_STATUS dbStatus = this.exportedModel.getDBMetadata(componentToExport).getDatabaseStatus();
+ if ( dbStatus == DATABASE_STATUS.isNewInModel )
+ doExport(componentToExport, this.txtNewElementsInModel);
+ else if ( dbStatus == DATABASE_STATUS.isUpdatedInModel )
+ doExport(componentToExport, this.txtUpdatedElementsInModel);
+
+ this.exportConnection.assignEObjectToModel(componentToExport);
+ }
+ incrementText(this.txtTotalElements);
+ increaseProgressBar();
+ }
+
+ // EXPORT RELATIONSHIPS
+ setProgressBarLabel("Exporting relationships ...");
+ Iterator> relationshipsIterator = this.exportedModel.getAllRelationships().entrySet().iterator();
+ while ( relationshipsIterator.hasNext() ) {
+ EObject componentToExport = relationshipsIterator.next().getValue();
+ if ( isNeo4JDatabase )
+ doExport(componentToExport, this.txtNewRelationshipsInModel);
+ else {
+ DATABASE_STATUS dbStatus = this.exportedModel.getDBMetadata(componentToExport).getDatabaseStatus();
+ if ( dbStatus == DATABASE_STATUS.isNewInModel )
+ doExport(componentToExport, this.txtNewRelationshipsInModel);
+ else if ( dbStatus == DATABASE_STATUS.isUpdatedInModel )
+ doExport(componentToExport, this.txtUpdatedRelationshipsInModel);
+
+ this.exportConnection.assignEObjectToModel(componentToExport);
+ }
+ incrementText(this.txtTotalRelationships);
+ increaseProgressBar();
+ }
+
+ if ( !isNeo4JDatabase ) {
+ setProgressBarLabel("Exporting folders ...");
+ Iterator> foldersIterator = this.exportedModel.getAllFolders().entrySet().iterator();
+ while ( foldersIterator.hasNext() ) {
+ EObject componentToExport = foldersIterator.next().getValue();
+ DATABASE_STATUS dbStatus = this.exportedModel.getDBMetadata(componentToExport).getDatabaseStatus();
+ if ( dbStatus == DATABASE_STATUS.isNewInModel )
+ doExport(componentToExport, this.txtNewFoldersInModel);
+ else if ( dbStatus == DATABASE_STATUS.isUpdatedInModel )
+ doExport(componentToExport, this.txtUpdatedFoldersInModel);
+
+ this.exportConnection.assignEObjectToModel(componentToExport);
+ incrementText(this.txtTotalFolders);
+ increaseProgressBar();
+ }
+
+ setProgressBarLabel("Exporting views ...");
+ Iterator> viewsIterator = this.exportedModel.getAllViews().entrySet().iterator();
+ while ( viewsIterator.hasNext() ) {
+ EObject componentToExport = viewsIterator.next().getValue();
+ Text txtFieldToIncrement = null;
+ DBMetadata metadata = this.exportedModel.getDBMetadata(componentToExport);
+ DATABASE_STATUS dbStatus = metadata.getDatabaseStatus();
+ if ( dbStatus == DATABASE_STATUS.isNewInModel )
+ txtFieldToIncrement = this.txtNewViewsInModel;
+ else if ( dbStatus == DATABASE_STATUS.isUpdatedInModel )
+ txtFieldToIncrement = this.txtUpdatedViewsInModel;
+
+ if ( txtFieldToIncrement != null ) {
+ if ( metadata.getScreenshot().isScreenshotActive() ) {
+ setProgressBarLabel("Creating screenshot of view \""+metadata.getName()+"\"");
+ createImage((IDiagramModel)componentToExport, this.exportConnection.getDatabaseEntry().getViewsImagesScaleFactor(), this.exportConnection.getDatabaseEntry().getViewsImagesBorderWidth());
+ setProgressBarLabel("Exporting views ...");
+ }
+ doExport(componentToExport, txtFieldToIncrement);
+ metadata.setExported(true);
+ } else
+ metadata.setExported(false);
+
+ this.exportConnection.assignEObjectToModel(componentToExport);
+ incrementText(this.txtTotalViews);
+ increaseProgressBar();
+ }
+
+ setProgressBarLabel("Exporting view objects ...");
+ Iterator> viewObjectsIterator = this.exportedModel.getAllViewObjects().entrySet().iterator();
+ while ( viewObjectsIterator.hasNext() ) {
+ IDiagramModelObject componentToExport = viewObjectsIterator.next().getValue();
+
+ if ( this.exportedModel.getDBMetadata(componentToExport.getDiagramModel()).isExported() ) {
+ DATABASE_STATUS dbStatus = this.exportedModel.getDBMetadata(componentToExport).getDatabaseStatus();
+ if ( dbStatus == DATABASE_STATUS.isNewInModel )
+ doExport(componentToExport, this.txtNewViewObjectsInModel);
+ else if ( dbStatus == DATABASE_STATUS.isUpdatedInModel )
+ doExport(componentToExport, this.txtUpdatedViewObjectsInModel);
+
+ this.exportConnection.assignEObjectToModel(componentToExport);
+ }
+
+ incrementText(this.txtTotalViewObjects);
+ increaseProgressBar();
+ }
+
+ setProgressBarLabel("Exporting view connections ...");
+ Iterator> viewConnectionsIterator = this.exportedModel.getAllViewConnections().entrySet().iterator();
+ while ( viewConnectionsIterator.hasNext() ) {
+ IDiagramModelConnection componentToExport = viewConnectionsIterator.next().getValue();
+
+ if ( this.exportedModel.getDBMetadata(componentToExport.getDiagramModel()).isExported() ) {
+ DATABASE_STATUS dbStatus = this.exportedModel.getDBMetadata(componentToExport).getDatabaseStatus();
+ if ( dbStatus == DATABASE_STATUS.isNewInModel )
+ doExport(componentToExport, this.txtNewViewConnectionsInModel);
+ else if ( dbStatus == DATABASE_STATUS.isUpdatedInModel )
+ doExport(componentToExport, this.txtUpdatedViewConnectionsInModel);
+
+ this.exportConnection.assignEObjectToModel(componentToExport);
+ }
+
+ incrementText(this.txtTotalViewConnections);
+ increaseProgressBar();
+ }
+
+ setProgressBarLabel("Exporting images ...");
+ // no need to use imagesNotInModel as the requested images have been imported at the same time as their view object
+ IArchiveManager archiveMgr = (IArchiveManager)this.exportedModel.getAdapter(IArchiveManager.class);
+ for ( String path: this.exportedModel.getAllImagePaths() ) {
+ if ( this.exportConnection.exportImage(path, archiveMgr.getBytesFromEntry(path)) )
+ incrementText(this.txtNewImagesInModel);
+ increaseProgressBar();
+ }
+
+ // we register the undoableCommands on the model's stack, this way, the user will be able to manually undo them
+ this.stack.execute(undoableCommands);
+ }
+ } catch (Exception exportError) {
+ // if the exception is not raised because the user clicked on the cancel button, then we rollback and close the database connection
+ if ( !isClosedByUser() ) {
+ // TODO: find a better way to manage the cancel button
+ setActiveAction(STATUS.Error);
+
+ // if the user clicked on the "cancel" button, then the database connection is closed, which generates an exception when a SQL request is executed
+ try {
+ rollbackAndCloseConnection();
+
+ doShowResult(STATUS.Error, errorMessage + "\n"+exportError.getMessage());
+ popup(Level.ERROR, errorMessage + "\n\nThe transaction has been rolled back to leave the database in a coherent state. You may solve the issue and export again your components.", exportError);
+ } catch (SQLException closeDBError) {
+ doShowResult(STATUS.Error, "Error while exporting model.\n"+exportError.getMessage()+"\nThe transaction failed to rollback, please check your database carrefully !");
+
+ popup(Level.FATAL, "An error occurred while exporting the components."+exportError);
+ popup(Level.FATAL, "An exception has been detected during the rollback and closure of the database transaction.\n\nThe database is left in an unknown state.\n\nPlease check carrefully your database !", closeDBError);
+ }
+ }
+
+ // we rollback any update done on the model
+ if ( !undoableCommands.isEmpty() ) {
+ this.stack.undo();
+ // this.undoableCommands.undo();
+ for ( Object cmd: undoableCommands.getCommands() ) {
+ try {
+ Method getException = IDBCommand.class.getMethod("getException()");
+ Exception e = (Exception) getException.invoke(cmd);
+ if ( e != null ) {
+ popup(Level.FATAL, "Failed to restore the model as it was before the export. Please verify it carefully.", e);
+ // a single message is sufficient to alert the user
+ break;
+ }
+ } catch (@SuppressWarnings("unused") Exception ign) {
+ // nothing to do if the command does not have manage exceptions
+ }
+ }
+ }
+
+ return;
+ }
+
+ // if we're here, it means that no exception has been raised during the export process
+ try {
+ commitAndCloseConnection();
+ setActiveAction(STATUS.Ok);
+ // Once the export is finished, we copy the exportedVersion to the currentVersion for all the model's components
+ copyCurrentVersionToInitialVersion();
+
+ doShowResult(STATUS.Ok, "*** Export successful ***");
+ } catch (Exception err) {
+ setActiveAction(STATUS.Error);
+ doShowResult(STATUS.Error, "Failed to commit the database transaction.\n"+err.getMessage()+"\nPlease check your database carrefully.");
+ popup(Level.FATAL, "The model has been successfully exported to the database, but an exception has been raised during the database connection commit and closure, thus your dabase may be left in an incoherent state.\n\nPlease check carrefully your database !", err);
+ return;
+ }
+ }
+
+ private void doExport(EObject objToExport, Text txtFieldToIncrement) throws Exception {
+ this.exportConnection.exportEObject(objToExport);
+ incrementText(txtFieldToIncrement);
+ }
+
+ void copyCurrentVersionToInitialVersion() {
+ if ( logger.isDebugEnabled() ) logger.debug("Copying current version to initial version.");
+
+ this.exportedModel.getInitialVersion().set(this.exportedModel.getCurrentVersion());
+
+ Iterator> ite = this.exportedModel.getAllElements().entrySet().iterator();
+ while (ite.hasNext()) {
+ DBMetadata dbMetadata = this.exportedModel.getDBMetadata(ite.next().getValue());
+ dbMetadata.getInitialVersion().set(dbMetadata.getCurrentVersion());
+ }
+
+ Iterator> itr = this.exportedModel.getAllRelationships().entrySet().iterator();
+ while (itr.hasNext()) {
+ DBMetadata dbMetadata = this.exportedModel.getDBMetadata(itr.next().getValue());
+ dbMetadata.getInitialVersion().set(dbMetadata.getCurrentVersion());
+ }
+
+ Iterator> itf = this.exportedModel.getAllFolders().entrySet().iterator();
+ while (itf.hasNext()) {
+ DBMetadata dbMetadata = this.exportedModel.getDBMetadata(itf.next().getValue());
+ dbMetadata.getInitialVersion().set(dbMetadata.getCurrentVersion());
+ }
+
+ Iterator> itv = this.exportedModel.getAllViews().entrySet().iterator();
+ while (itv.hasNext()) {
+ DBMetadata dbMetadata = this.exportedModel.getDBMetadata(itv.next().getValue());
+ dbMetadata.getInitialVersion().set(dbMetadata.getCurrentVersion());
+ }
+
+ Iterator> ito = this.exportedModel.getAllViewObjects().entrySet().iterator();
+ while (ito.hasNext()) {
+ DBMetadata dbMetadata = this.exportedModel.getDBMetadata(ito.next().getValue());
+ dbMetadata.getInitialVersion().set(dbMetadata.getCurrentVersion());
+ }
+
+ Iterator> itc = this.exportedModel.getAllViewConnections().entrySet().iterator();
+ while (itc.hasNext()) {
+ DBMetadata dbMetadata = this.exportedModel.getDBMetadata(itc.next().getValue());
+ dbMetadata.getInitialVersion().set(dbMetadata.getCurrentVersion());
+ }
+ }
+
+ /**
+ * Creates a group that will display the conflicts raised during the export process
+ */
+ protected void createGrpConflict() {
+ if ( this.grpConflict == null ) {
+ this.grpConflict = new Group(this.compoRightBottom, SWT.NONE);
+ this.grpConflict.setBackground(GROUP_BACKGROUND_COLOR);
+ this.grpConflict.setFont(TITLE_FONT);
+ this.grpConflict.setText("Conflict: ");
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ fd.bottom = new FormAttachment(100);
+ this.grpConflict.setLayoutData(fd);
+ this.grpConflict.setLayout(new FormLayout());
+
+ this.lblCantExport = new Label(this.grpConflict, SWT.NONE);
+ this.lblCantExport.setBackground(GROUP_BACKGROUND_COLOR);
+ this.lblCantExport.setText("Can't export because some components conflict with newer version in the database:");
+ fd = new FormData();
+ fd.top = new FormAttachment(0, getDefaultMargin());
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ this.lblCantExport.setLayoutData(fd);
+
+ this.tblListConflicts = new Table(this.grpConflict, SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL);
+ this.tblListConflicts.setLinesVisible(true);
+ this.tblListConflicts.setBackground(TABLE_BACKGROUND_COLOR);
+ this.tblListConflicts.addListener(SWT.Selection, new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ // we search for the component that is conflicting
+ String id = DBGuiExportModel.this.tblListConflicts.getSelection()[0].getText();
+
+ EObject conflictingComponent = DBGuiExportModel.this.exportedModel.searchComponentFromId(id);
+
+ if ( conflictingComponent == null ) {
+ DBGuiExportModel.this.btnExportMyVersion.setEnabled(false);
+ DBGuiExportModel.this.btnDoNotExport.setEnabled(false);
+ DBGuiExportModel.this.btnImportDatabaseVersion.setEnabled(false);
+ DBGuiExportModel.this.tblCompareComponent.removeAll();
+ popup(Level.ERROR, "Do not know which component is conflicting !!! That's weird !!!");
+ } else {
+ DBGuiExportModel.this.btnExportMyVersion.setEnabled(true);
+ DBGuiExportModel.this.btnDoNotExport.setEnabled(true);
+ DBGuiExportModel.this.btnImportDatabaseVersion.setEnabled( (conflictingComponent instanceof IArchimateElement) || (conflictingComponent instanceof IArchimateRelationship) );
+
+ fillInCompareTable(DBGuiExportModel.this.tblCompareComponent, conflictingComponent, DBGuiExportModel.this.exportedModel.getDBMetadata(conflictingComponent).getLatestDatabaseVersion().getVersion());
+ }
+ DBGuiExportModel.this.grpComponents.setVisible(false);
+ DBGuiExportModel.this.grpModelVersions.setVisible(false);
+ DBGuiExportModel.this.grpConflict.setVisible(true);
+ DBGuiExportModel.this.compoRightBottom.layout();
+ }
+ });
+ fd = new FormData();
+ fd.top = new FormAttachment(this.lblCantExport, getDefaultMargin());
+ fd.left = new FormAttachment(25);
+ fd.right = new FormAttachment(75);
+ fd.bottom = new FormAttachment(40);
+ this.tblListConflicts.setLayoutData(fd);
+
+ Label lblCompare = new Label(this.grpConflict, SWT.NONE);
+ lblCompare.setBackground(GROUP_BACKGROUND_COLOR);
+ lblCompare.setText("Please verify your version against the latest version in the database:");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.tblListConflicts, 20);
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ lblCompare.setLayoutData(fd);
+
+ this.tblCompareComponent = new Tree(this.grpConflict, SWT.BORDER | SWT.FULL_SELECTION | SWT.HIDE_SELECTION | SWT.V_SCROLL);
+ this.tblCompareComponent.setBackground(TABLE_BACKGROUND_COLOR);
+ this.tblCompareComponent.setHeaderVisible(true);
+ this.tblCompareComponent.setLinesVisible(true);
+ fd = new FormData();
+ fd.top = new FormAttachment(lblCompare, getDefaultMargin());
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ fd.right = new FormAttachment(100, -getDefaultMargin());
+ fd.bottom = new FormAttachment(100, -40);
+ this.tblCompareComponent.setLayoutData(fd);
+
+ TreeColumn colItems = new TreeColumn(this.tblCompareComponent, SWT.NONE);
+ colItems.setText("Items");
+ colItems.setWidth(119);
+
+ TreeColumn colYourVersion = new TreeColumn(this.tblCompareComponent, SWT.NONE);
+ colYourVersion.setText("Your version");
+ colYourVersion.setWidth(220);
+
+ TreeColumn colDatabaseVersion = new TreeColumn(this.tblCompareComponent, SWT.NONE);
+ colDatabaseVersion.setText("Database version");
+ colDatabaseVersion.setWidth(220);
+
+ this.btnImportDatabaseVersion = new Button(this.grpConflict, SWT.NONE);
+ this.btnImportDatabaseVersion.setImage(IMPORT_FROM_DATABASE_IMAGE);
+ this.btnImportDatabaseVersion.setText("Import database version");
+ this.btnImportDatabaseVersion.setEnabled(false);
+ this.btnImportDatabaseVersion.addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if ( DBGuiExportModel.this.checkRememberChoice.getSelection() ) {
+ // if the button checkRememberChoice is checked, then we apply the choice for all the conflicting components.
+ // at the end, only those with errors will stay
+ DBGuiExportModel.this.tblListConflicts.setSelection(0);
+ for ( int i=0; i
+ * Sets the exportChoice and removes the component from the tblListconflicts table
+ * If no conflict remain, then it relaunch the doExportComponents method
+ * @param requiredChoice
+ */
+ protected void tagComponentWithConflictResolutionChoice(CONFLICT_CHOICE requiredChoice) {
+ CONFLICT_CHOICE effectiveChoice = requiredChoice;
+
+ EObject component = (EObject)this.tblListConflicts.getSelection()[0].getData();
+ if ( component == null ) {
+ popup(Level.ERROR, "Can't get conflicting component \""+this.tblListConflicts.getSelection()[0].getText()+"\"");
+ return;
+ }
+
+ this.exportedModel.getAllConflicts().put(component, effectiveChoice);
+ switch (effectiveChoice) {
+ case doNotExport: if ( logger.isDebugEnabled() ) logger.debug("Tagging component to do not export"); break;
+ case exportToDatabase: if ( logger.isDebugEnabled() ) logger.debug("Tagging component to export current version to database"); break;
+ case importFromDatabase: if ( logger.isDebugEnabled() ) logger.debug("Tagging component to import database version"); break;
+ case askUser: if ( logger.isDebugEnabled() ) logger.debug("Tagging component to ask user"); break;
+ default:
+ }
+
+ int index = this.tblListConflicts.getSelectionIndex();
+ this.tblListConflicts.remove(index);
+ if ( logger.isDebugEnabled() ) logger.debug("Remaining " + this.tblListConflicts.getItemCount() + " conflicts");
+ if ( this.tblListConflicts.getItemCount() == 0 ) {
+ this.grpComponents.setVisible(true);
+ this.grpModelVersions.setVisible(true);
+ this.grpConflict.setVisible(false);
+ export();
+ } else {
+ if ( this.tblListConflicts.getItemCount() < 2 )
+ this.lblCantExport.setText("Can't export because "+this.tblListConflicts.getItemCount()+" component conflicts with newer version in the database:");
+ else
+ this.lblCantExport.setText("Can't export because "+this.tblListConflicts.getItemCount()+" components conflict with newer version in the database:");
+
+ if ( index < this.tblListConflicts.getItemCount() )
+ this.tblListConflicts.setSelection(index);
+ else
+ this.tblListConflicts.setSelection(index-1);
+ this.tblListConflicts.notifyListeners(SWT.Selection, new Event()); // shows up the tblListConflicts table and calls fillInCompareTable()
+ }
+ }
+
+ protected void doShowResult(STATUS status, String message) {
+ logger.debug("Showing result.");
+ hideProgressBar();
+ if ( this.grpConflict != null ) this.grpConflict.setVisible(false);
+ this.grpComponents.setVisible(true);
+ this.grpModelVersions.setVisible(true);
+
+ setActiveAction(ACTION.Three);
+
+ if ( status == STATUS.Ok ) {
+ logger.info(String.format(" <------ In model ------> <----- In database ---->"));
+ logger.info(String.format(" Total New Updated Deleted New Updated Deleted Conflict"));
+ logger.info(String.format(" Elements: %6d %6d %6d %6d %6d %6d %6d %6d", this.exportedModel.getAllElements().size(), toInt(this.txtNewElementsInModel.getText()), toInt(this.txtUpdatedElementsInModel.getText()), toInt(this.txtDeletedElementsInModel.getText()), toInt(this.txtNewElementsInDatabase.getText()), toInt(this.txtUpdatedElementsInDatabase.getText()), toInt(this.txtDeletedElementsInDatabase.getText()), toInt(this.txtConflictingElements.getText())) );
+ logger.info(String.format(" Relationships: %6d %6d %6d %6d %6d %6d %6d %6d", this.exportedModel.getAllRelationships().size(), toInt(this.txtNewRelationshipsInModel.getText()), toInt(this.txtUpdatedRelationshipsInModel.getText()), toInt(this.txtDeletedRelationshipsInModel.getText()), toInt(this.txtNewRelationshipsInDatabase.getText()), toInt(this.txtUpdatedRelationshipsInDatabase.getText()), toInt(this.txtDeletedRelationshipsInDatabase.getText()), toInt(this.txtConflictingRelationships.getText())) );
+ if ( !DBPlugin.areEqual(this.selectedDatabase.getDriver().toLowerCase(), "neo4j") ) {
+ logger.info(String.format(" Folders: %6d %6d %6d %6d %6d %6d %6d %6d", this.exportedModel.getAllFolders().size(), toInt(this.txtNewFoldersInModel.getText()), toInt(this.txtUpdatedFoldersInModel.getText()), toInt(this.txtDeletedFoldersInModel.getText()), toInt(this.txtNewFoldersInDatabase.getText()), toInt(this.txtUpdatedFoldersInDatabase.getText()), toInt(this.txtDeletedFoldersInDatabase.getText()), toInt(this.txtConflictingFolders.getText())) );
+ logger.info(String.format(" views: %6d %6d %6d %6d %6d %6d %6d %6d", this.exportedModel.getAllViews().size(), toInt(this.txtNewViewsInModel.getText()), toInt(this.txtUpdatedViewsInModel.getText()), toInt(this.txtDeletedViewsInModel.getText()), toInt(this.txtNewViewsInDatabase.getText()), toInt(this.txtUpdatedViewsInDatabase.getText()), toInt(this.txtDeletedViewsInDatabase.getText()), toInt(this.txtConflictingViews.getText())) );
+ logger.info(String.format(" Objects: %6d %6d %6d %6d %6d %6d %6d %6d", this.exportedModel.getAllViewObjects().size(), toInt(this.txtNewViewObjectsInModel.getText()), toInt(this.txtUpdatedViewObjectsInModel.getText()), toInt(this.txtDeletedViewObjectsInModel.getText()), toInt(this.txtNewViewObjectsInDatabase.getText()), toInt(this.txtUpdatedViewObjectsInDatabase.getText()), toInt(this.txtDeletedViewObjectsInDatabase.getText()), toInt(this.txtConflictingViewObjects.getText())) );
+ logger.info(String.format(" Connections: %6d %6d %6d %6d %6d %6d %6d %6d", this.exportedModel.getAllViewConnections().size(), toInt(this.txtNewViewConnectionsInModel.getText()), toInt(this.txtUpdatedViewConnectionsInModel.getText()), toInt(this.txtDeletedViewConnectionsInModel.getText()), toInt(this.txtNewViewConnectionsInDatabase.getText()), toInt(this.txtUpdatedViewConnectionsInDatabase.getText()), toInt(this.txtDeletedViewConnectionsInDatabase.getText()), toInt(this.txtConflictingViewConnections.getText())) );
+ logger.info(String.format(" images: %6d %6d %16s %6d", ((IArchiveManager)this.exportedModel.getAdapter(IArchiveManager.class)).getLoadedImagePaths().size(), toInt(this.txtNewImagesInModel.getText()), "", toInt(this.txtNewImagesInDatabase.getText())) );
+ }
+
+ setMessage(message, GREEN_COLOR);
+ if ( DBPlugin.INSTANCE.getPreferenceStore().getBoolean("closeIfSuccessful") ) {
+ if ( logger.isDebugEnabled() ) logger.debug("Automatically closing the window as set in preferences");
+ close();
+ return;
+ }
+ if ( DBPlugin.INSTANCE.getPreferenceStore().getBoolean("removeDirtyFlag") ) {
+ if ( logger.isDebugEnabled() ) logger.debug("Removing model's dirty flag");
+ this.stack.markSaveLocation();
+ }
+ } else {
+ setMessage(message, RED_COLOR);
+ }
+
+ this.btnDoAction.setEnabled(false);
+ this.btnClose.setText("Close");
+
+ try {
+ if ( this.btnClose.getText().equals("Cancel") && (this.connection != null) && this.connection.isConnected() )
+ this.connection.rollback();
+ } catch (SQLException e) {
+ logger.error("Failed to check if database connection is closed.", e);
+ }
+ }
+
+ @Override
+ public void close() {
+ // we remove the view screenshots to same memory
+ Iterator> viewsIterator = this.exportedModel.getAllViews().entrySet().iterator();
+ while ( viewsIterator.hasNext() ) {
+ increaseProgressBar();
+ IDiagramModel view = viewsIterator.next().getValue();
+ this.exportedModel.getDBMetadata(view).getScreenshot().dispose();
+ }
+
+ super.close();
+ }
+
+ Button btnDoNotExport;
+ Button btnExportMyVersion;
+ Button btnImportDatabaseVersion;
+ Button btnCompareModelToDatabase;
+
+ Button checkRememberChoice;
+
+ Group grpConflict;
+
+ Tree tblCompareComponent;
+ Table tblListConflicts;
+ private Label lblCantExport;
+
+ Text txtReleaseNote;
+
+ private Label lblTotal;
+ private Label lblModel;
+ private Label lblModelNew;
+ private Label lblModelUpdated;
+ private Label lblModelDeleted;
+ private Label lblDatabase;
+ private Label lblDatabaseNew;
+ private Label lblDatabaseUpdated;
+ private Label lblDatabaseDeleted;
+ private Label lblConflicts;
+
+ private Label modelHorizontalSeparator;
+ private Label modelVerticalSeparatorLeft;
+ private Label modelVerticalSeparatorRight;
+ private Label databaseHorizontalSeparator;
+ private Label databaseVerticalSeparatorLeft;
+ private Label databaseVerticalSeparatorRight;
+
+ private Text txtTotalProfiles;
+ private Text txtNewProfilesInModel;
+ private Text txtUpdatedProfilesInModel;
+ private Text txtDeletedProfilesInModel;
+ private Text txtNewProfilesInDatabase;
+ private Text txtUpdatedProfilesInDatabase;
+ private Text txtDeletedProfilesInDatabase;
+ private Text txtConflictingProfiles;
+
+ private Text txtTotalElements;
+ private Text txtNewElementsInModel;
+ private Text txtUpdatedElementsInModel;
+ private Text txtDeletedElementsInModel;
+ private Text txtNewElementsInDatabase;
+ private Text txtUpdatedElementsInDatabase;
+ private Text txtDeletedElementsInDatabase;
+ private Text txtConflictingElements;
+
+ private Text txtTotalRelationships;
+ private Text txtNewRelationshipsInModel;
+ private Text txtUpdatedRelationshipsInModel;
+ private Text txtDeletedRelationshipsInModel;
+ private Text txtNewRelationshipsInDatabase;
+ private Text txtUpdatedRelationshipsInDatabase;
+ private Text txtDeletedRelationshipsInDatabase;
+ private Text txtConflictingRelationships;
+
+ private Text txtTotalFolders;
+ private Text txtNewFoldersInModel;
+ private Text txtUpdatedFoldersInModel;
+ private Text txtDeletedFoldersInModel;
+ private Text txtNewFoldersInDatabase;
+ private Text txtUpdatedFoldersInDatabase;
+ private Text txtDeletedFoldersInDatabase;
+ private Text txtConflictingFolders;
+
+ private Text txtTotalViews;
+ private Text txtNewViewsInModel;
+ private Text txtUpdatedViewsInModel;
+ private Text txtDeletedViewsInModel;
+ private Text txtNewViewsInDatabase;
+ private Text txtUpdatedViewsInDatabase;
+ private Text txtDeletedViewsInDatabase;
+ private Text txtConflictingViews;
+
+ private Text txtTotalViewObjects;
+ private Text txtNewViewObjectsInModel;
+ private Text txtUpdatedViewObjectsInModel;
+ private Text txtDeletedViewObjectsInModel;
+ private Text txtNewViewObjectsInDatabase;
+ private Text txtUpdatedViewObjectsInDatabase;
+ private Text txtDeletedViewObjectsInDatabase;
+ private Text txtConflictingViewObjects;
+
+ private Text txtTotalViewConnections;
+ private Text txtNewViewConnectionsInModel;
+ private Text txtUpdatedViewConnectionsInModel;
+ private Text txtDeletedViewConnectionsInModel;
+ private Text txtNewViewConnectionsInDatabase;
+ private Text txtUpdatedViewConnectionsInDatabase;
+ private Text txtDeletedViewConnectionsInDatabase;
+ private Text txtConflictingViewConnections;
+
+ private Text txtTotalImages;
+ private Text txtNewImagesInModel;
+ private Text txtNewImagesInDatabase;
+
+
+ Table tblModelVersions;
+ Text txtModelName;
+ Text txtPurpose;
+}
diff --git a/sources/src/org/archicontribs/database/GUI/DBGuiImportComponents.java b/sources/src/org/archicontribs/database/GUI/DBGuiImportComponents.java
new file mode 100644
index 00000000..1e84e504
--- /dev/null
+++ b/sources/src/org/archicontribs/database/GUI/DBGuiImportComponents.java
@@ -0,0 +1,2631 @@
+/**
+ * This program and the accompanying materials
+ * are made available under the terms of the License
+ * which accompanies this distribution in the file LICENSE.txt
+ */
+
+package org.archicontribs.database.GUI;
+
+import java.io.ByteArrayInputStream;
+import java.sql.SQLException;
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.log4j.Level;
+import org.archicontribs.database.DBLogger;
+import org.archicontribs.database.DBPlugin;
+import org.archicontribs.database.connection.DBDatabaseImportConnection;
+import org.archicontribs.database.connection.DBSelect;
+import org.archicontribs.database.data.DBImportMode;
+import org.archicontribs.database.model.DBArchimateModel;
+import org.archicontribs.database.model.DBMetadata;
+import org.archicontribs.database.model.commands.DBImportElementFromIdCommand;
+import org.archicontribs.database.model.commands.DBImportFolderFromIdCommand;
+import org.archicontribs.database.model.commands.DBImportRelationshipFromIdCommand;
+import org.archicontribs.database.model.commands.DBImportViewFromIdCommand;
+import org.archicontribs.database.model.commands.DBResolveConnectionsCommand;
+import org.archicontribs.database.model.commands.DBResolveRelationshipsCommand;
+import org.archicontribs.database.model.commands.IDBCommand;
+import org.archicontribs.database.model.commands.IDBImportCommand;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.CommandStack;
+import org.eclipse.gef.commands.CompoundCommand;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyleRange;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.layout.FormLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+
+import com.archimatetool.canvas.CanvasEditorPlugin;
+import com.archimatetool.canvas.ICanvasImages;
+import com.archimatetool.editor.ArchiPlugin;
+import com.archimatetool.editor.ui.IArchiImages;
+import com.archimatetool.editor.ui.ImageFactory;
+import com.archimatetool.editor.ui.services.ViewManager;
+import com.archimatetool.editor.views.tree.ITreeModelView;
+import com.archimatetool.model.FolderType;
+import com.archimatetool.model.IArchimateDiagramModel;
+import com.archimatetool.model.IFolder;
+
+/**
+ * This class manages the GUI that allows to import an individual component from the database
+ *
+ * @author Herve Jouin
+ */
+public class DBGuiImportComponents extends DBGui {
+ @SuppressWarnings("hiding")
+ protected static final DBLogger logger = new DBLogger(DBGuiImportComponents.class);
+
+ protected DBArchimateModel importedModel;
+ protected IArchimateDiagramModel selectedView;
+ protected IFolder selectedFolder;
+
+ private Group grpFilter;
+ private Group grpComponent;
+
+ Composite compoModels;
+ Composite compoElements;
+ Button radioOptionModel;
+ Button radioOptionElement;
+ Button radioOptionView;
+ private Text filterName;
+ private Button hideOption; // to hide empty names for elements and relationships, top level folders and default views
+ private Button hideAlreadyInModel;
+
+ DBDatabaseImportConnection importConnection = null;
+
+ //private Composite compoFolders;
+ //private Button strategyFolders;
+ //private Button applicationFolders;
+ //private Button businessFolders;
+ //private Button technologyFolders;
+ //private Button otherFolders;
+ //private Button motivationFolders;
+ //private Button implementationFolders;
+
+ Composite compoViews;
+ private Button archimateViews;
+ private Button canvasViews;
+ private Button sketchViews;
+
+ Label lblComponents;
+ Table tblComponents;
+ Label lblPreview;
+
+
+ ComponentLabel resourceLabel;
+ ComponentLabel capabilityLabel;
+ ComponentLabel courseOfActionLabel;
+ ComponentLabel applicationComponentLabel;
+ ComponentLabel applicationCollaborationLabel;
+ ComponentLabel applicationInterfaceLabel;
+ ComponentLabel applicationFunctionLabel;
+ ComponentLabel applicationInteractionLabel;
+ ComponentLabel applicationEventLabel;
+ ComponentLabel applicationServiceLabel;
+ ComponentLabel dataObjectLabel;
+ ComponentLabel applicationProcessLabel;
+ ComponentLabel businessActorLabel;
+ ComponentLabel businessRoleLabel;
+ ComponentLabel businessCollaborationLabel;
+ ComponentLabel businessInterfaceLabel;
+ ComponentLabel businessProcessLabel;
+ ComponentLabel businessFunctionLabel;
+ ComponentLabel businessInteractionLabel;
+ ComponentLabel businessEventLabel;
+ ComponentLabel businessServiceLabel;
+ ComponentLabel businessObjectLabel;
+ ComponentLabel contractLabel;
+ ComponentLabel representationLabel;
+ ComponentLabel nodeLabel;
+ ComponentLabel deviceLabel;
+ ComponentLabel systemSoftwareLabel;
+ ComponentLabel technologyCollaborationLabel;
+ ComponentLabel technologyInterfaceLabel;
+ ComponentLabel pathLabel;
+ ComponentLabel communicationNetworkLabel;
+ ComponentLabel technologyFunctionLabel;
+ ComponentLabel technologyProcessLabel;
+ ComponentLabel technologyInteractionLabel;
+ ComponentLabel technologyEventLabel;
+ ComponentLabel technologyServiceLabel;
+ ComponentLabel artifactLabel;
+ ComponentLabel equipmentLabel;
+ ComponentLabel facilityLabel;
+ ComponentLabel distributionNetworkLabel;
+ ComponentLabel materialLabel;
+ ComponentLabel workpackageLabel;
+ ComponentLabel deliverableLabel;
+ ComponentLabel implementationEventLabel;
+ ComponentLabel plateauLabel;
+ ComponentLabel gapLabel;
+ ComponentLabel stakeholderLabel;
+ ComponentLabel driverLabel;
+ ComponentLabel assessmentLabel;
+ ComponentLabel goalLabel;
+ ComponentLabel outcomeLabel;
+ ComponentLabel principleLabel;
+ ComponentLabel requirementLabel;
+ ComponentLabel constaintLabel;
+ ComponentLabel smeaningLabel;
+ ComponentLabel valueLabel;
+ ComponentLabel productLabel;
+ ComponentLabel groupingLabel;
+ ComponentLabel locationLabel;
+ ComponentLabel junctionLabel;
+
+ private Label lblStrategy;
+ private Label lblBusiness;
+ private Label lblApplication;
+ private Label lblTechnology;
+ private Label lblPhysical;
+ private Label lblImplementation;
+ private Label lblMotivation;
+
+ ComponentLabel[] allElementLabels;
+
+ /**
+ * Creates the GUI to import components
+ * @param model
+ * @param view
+ * @param folder
+ * @param title
+ * @throws Exception
+ */
+ public DBGuiImportComponents(DBArchimateModel model, IArchimateDiagramModel view, IFolder folder, String title) throws Exception {
+ super(title);
+
+ this.includeNeo4j = false;
+
+ setMessage("Counting model's components");
+ model.countAllObjects();
+ if ( logger.isDebugEnabled() ) logger.debug("The model has got "+model.getAllElements().size()+" elements and "+model.getAllRelationships().size()+" relationships.");
+ closeMessage();
+
+ if ( logger.isDebugEnabled() ) logger.debug("Setting up GUI for importing a component (plugin version "+DBPlugin.pluginVersion.toString()+").");
+
+ // model in which the component should be imported
+ this.importedModel = model;
+
+ // if specified, the imported element or relationship will be instantiated as an object or a connection in the view
+ this.selectedView = view;
+
+ // if specified, the imported view will be instantiated into the folder (if the root folder type is view)
+ this.selectedFolder = folder;
+
+ createAction(ACTION.One, "Choose component");
+ setActiveAction(ACTION.One);
+
+ // we show the option in the bottom
+ setOption("Import type:",
+ "Template mode", DBPlugin.INSTANCE.getPreferenceStore().getString("defaultImportMode").equals("template"), "The components will be copied except if the \"template\" property's value is \"shared\".",
+ "Force shared mode", DBPlugin.INSTANCE.getPreferenceStore().getString("defaultImportMode").equals("shared"), "The components will be shared across models. All the modifications done on those components will be visible to other models.",
+ "Force copy mode", DBPlugin.INSTANCE.getPreferenceStore().getString("defaultImportMode").equals("copy"), "A copy of the components will be created. All your modifications will remain private to your model and will not be visible by other models.");
+
+ // We activate the btnDoAction button: if the user select the "Import" button --> call the doImport() method
+ setBtnAction("Import", new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent event) {
+ DBGuiImportComponents.this.btnDoAction.setEnabled(false);
+ try {
+ doImport();
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "An exception has been raised during import.", err);
+ }
+ }
+ @Override
+ public void widgetDefaultSelected(SelectionEvent event) { widgetSelected(event); }
+ });
+
+ // We activate the Eclipse Help framework
+ setHelpHref("importComponent.html");
+
+ enableOption();
+ createGrpFilter();
+ createGrpComponents();
+
+ // we pre-select components depending on the folder selected
+ if ( this.selectedFolder == null ) {
+ // if the folder and the view are both null, then, the user selected the model
+ if ( this.selectedView == null ) {
+ this.radioOptionModel.setSelection(true);
+ this.radioOptionElement.setSelection(false);
+ this.radioOptionView.setSelection(false);
+ }
+ } else {
+ this.radioOptionModel.setSelection(false);
+ this.radioOptionElement.setSelection(true);
+ this.radioOptionView.setSelection(false);
+
+ switch ( model.getDBMetadata(this.selectedFolder).getRootFolderType() ) {
+ case FolderType.STRATEGY_VALUE:
+ this.lblStrategy.notifyListeners(SWT.MouseUp, null);
+ break;
+
+ case FolderType.BUSINESS_VALUE:
+ this.lblBusiness.notifyListeners(SWT.MouseUp, null);
+ break;
+
+ case FolderType.APPLICATION_VALUE:
+ this.lblApplication.notifyListeners(SWT.MouseUp, null);
+ break;
+
+ case FolderType.TECHNOLOGY_VALUE:
+ this.lblTechnology.notifyListeners(SWT.MouseUp, null); // the null event indicates that the labels must be selected but the elements list must not be gathered from the database
+ this.lblPhysical.notifyListeners(SWT.MouseUp, null);
+ break;
+
+ case FolderType.IMPLEMENTATION_MIGRATION_VALUE:
+ this.lblImplementation.notifyListeners(SWT.MouseUp, null);
+ break;
+
+ case FolderType.MOTIVATION_VALUE:
+ this.lblMotivation.notifyListeners(SWT.MouseUp, null);
+ break;
+
+ case FolderType.OTHER_VALUE:
+ // there is no "other" group so no MouseUp listener. The getElements needs to be called manually.
+ this.locationLabel.setSelected(true);
+ this.locationLabel.redraw();
+
+ this.groupingLabel.setSelected(true);
+ this.groupingLabel.redraw();
+
+ this.junctionLabel.setSelected(true);
+ this.junctionLabel.redraw();
+ break;
+
+ case FolderType.DIAGRAMS_VALUE:
+ if ( view == null ) {
+ // if no view is selected, then we suppose we must import a view in the selected folder
+ // if a view is selected, we suppose we must import a component into that view (but we cannot guess which one)
+ this.radioOptionModel.setSelection(false);
+ this.radioOptionElement.setSelection(false);
+ this.radioOptionView.setSelection(true);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ getDatabases(false);
+
+ // we reset the location of the imported view objects if any
+ DBImportElementFromIdCommand.resetCreatedViewObjectsLocation();
+ }
+
+ /**
+ * Called when a database is selected in the comboDatabases and that the connection to this database succeeded.
+ */
+ @Override
+ protected void connectedToDatabase(boolean ignore) {
+ this.importConnection = new DBDatabaseImportConnection(getDatabaseConnection());
+ this.compoRightBottom.setVisible(true);
+ this.compoRightBottom.layout();
+ try {
+ this.tblComponents.clearAll();
+
+ if ( this.radioOptionModel.getSelection() )
+ getModels();
+ else if ( this.radioOptionElement.getSelection() )
+ getElements();
+ else if ( this.radioOptionView.getSelection() )
+ getViews();
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "An exception has been raised.", err);
+ }
+ }
+
+ private void createGrpFilter() {
+ this.grpFilter = new Group(this.compoRightBottom, SWT.NONE);
+ this.grpFilter.setBackground(GROUP_BACKGROUND_COLOR);
+ this.grpFilter.setFont(GROUP_TITLE_FONT);
+ this.grpFilter.setText("Filter: ");
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ fd.bottom = new FormAttachment(50, -5);
+ this.grpFilter.setLayoutData(fd);
+ this.grpFilter.setLayout(new FormLayout());
+
+ Label chooseCategory = new Label(this.grpFilter, SWT.NONE);
+ chooseCategory.setBackground(GROUP_BACKGROUND_COLOR);
+ chooseCategory.setFont(BOLD_FONT);
+ chooseCategory.setText("Category:");
+ fd = new FormData();
+ fd.top = new FormAttachment(0, 20);
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ chooseCategory.setLayoutData(fd);
+
+ this.radioOptionModel = new Button(this.grpFilter, SWT.RADIO);
+ this.radioOptionModel.setBackground(GROUP_BACKGROUND_COLOR);
+ this.radioOptionModel.setText("Models");
+ this.radioOptionModel.setSelection(false);
+ this.radioOptionModel.addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent event) {
+ if ( DBGuiImportComponents.this.radioOptionModel.getSelection() ) {
+ try {
+ getModels();
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "An exception has been raised.", err);
+ }
+ }
+ }
+ @Override
+ public void widgetDefaultSelected(SelectionEvent event) { widgetSelected(event); }
+ });
+ fd = new FormData();
+ fd.top = new FormAttachment(chooseCategory, 5);
+ fd.left = new FormAttachment(0, 20);
+ this.radioOptionModel.setLayoutData(fd);
+
+ this.radioOptionElement = new Button(this.grpFilter, SWT.RADIO);
+ this.radioOptionElement.setBackground(GROUP_BACKGROUND_COLOR);
+ this.radioOptionElement.setText("Elements");
+ this.radioOptionElement.setSelection(true);
+ this.radioOptionElement.addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent event) {
+ if ( DBGuiImportComponents.this.radioOptionElement.getSelection() ) {
+ try {
+ getElements();
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "An exception has been raised.", err);
+ }
+ }
+ }
+ @Override
+ public void widgetDefaultSelected(SelectionEvent event) { widgetSelected(event); }
+ });
+ fd = new FormData();
+ fd.top = new FormAttachment(this.radioOptionModel, 5);
+ fd.left = new FormAttachment(0, 20);
+ this.radioOptionElement.setLayoutData(fd);
+
+ this.radioOptionView = new Button(this.grpFilter, SWT.RADIO);
+ this.radioOptionView.setBackground(GROUP_BACKGROUND_COLOR);
+ this.radioOptionView.setText("Views");
+ this.radioOptionView.addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent event) {
+ if ( DBGuiImportComponents.this.radioOptionView.getSelection() ) {
+ try {
+ getViews();
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "An exception has been raised.", err);
+ }
+ }
+ }
+ @Override
+ public void widgetDefaultSelected(SelectionEvent event) { widgetSelected(event); }
+ });
+ fd = new FormData();
+ fd.top = new FormAttachment(this.radioOptionElement, 5);
+ fd.left = new FormAttachment(0, 20);
+ this.radioOptionView.setLayoutData(fd);
+
+ Label chooseName = new Label(this.grpFilter, SWT.NONE);
+ chooseName.setBackground(GROUP_BACKGROUND_COLOR);
+ chooseName.setFont(BOLD_FONT);
+ chooseName.setText("Name filter:");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.radioOptionView, getDefaultMargin());
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ chooseName.setLayoutData(fd);
+
+ this.filterName = new Text(this.grpFilter, SWT.NONE);
+ fd = new FormData();
+ fd.top = new FormAttachment(chooseName, 5);
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ fd.right = new FormAttachment(0, 125);
+ this.filterName.setLayoutData(fd);
+ this.filterName.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent event) {
+ try {
+ if ( DBGuiImportComponents.this.importConnection.isConnected() ) {
+ if ( DBGuiImportComponents.this.radioOptionModel.getSelection() )
+ getModels();
+ if ( DBGuiImportComponents.this.radioOptionElement.getSelection() )
+ getElements();
+ //else if ( compoFolders.isVisible() )
+ // getFolders();
+ else if ( DBGuiImportComponents.this.radioOptionView.getSelection () )
+ getViews();
+ }
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "An exception has been raised.", err);
+ }
+ }
+ });
+
+ createCompoModels();
+ createCompoElements();
+ //createCompoComposites();
+ //createCompoFolders();
+ createCompoViews();
+ }
+
+ private void createCompoModels() {
+ this.compoModels = new Composite(this.grpFilter, SWT.NONE);
+ this.compoModels.setBackground(GROUP_BACKGROUND_COLOR);
+ this.compoModels.setVisible(false);
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(0, 135);
+ fd.right = new FormAttachment(100, -getDefaultMargin());
+ fd.bottom = new FormAttachment(100, -getDefaultMargin());
+ this.compoModels.setLayoutData(fd);
+ this.compoModels.setLayout(new FormLayout());
+
+ Label title = new Label(this.compoModels, SWT.NONE);
+ title.setText("Please select a model to merge in your current model ...");
+ title.setBackground(GROUP_BACKGROUND_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ title.setLayoutData(fd);
+ }
+
+ private void createCompoElements() {
+ this.compoElements = new Composite(this.grpFilter, SWT.NONE);
+ this.compoElements.setBackground(GROUP_BACKGROUND_COLOR);
+ this.compoElements.setVisible(false);
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(0, 135);
+ fd.right = new FormAttachment(100, -getDefaultMargin());
+ fd.bottom = new FormAttachment(100, -getDefaultMargin());
+ this.compoElements.setLayoutData(fd);
+ this.compoElements.setLayout(new FormLayout());
+
+ Label title = new Label(this.compoElements, SWT.CENTER);
+ title.setText("You may click on a label or an icon to (un)select the corresponding classes ...");
+ title.setBackground(GROUP_BACKGROUND_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ title.setLayoutData(fd);
+
+ Composite strategyActiveCompo = new Composite(this.compoElements, SWT.TRANSPARENT);
+ Composite strategyBehaviorCompo = new Composite(this.compoElements, SWT.TRANSPARENT);
+ Composite strategyPassiveCompo = new Composite(this.compoElements, SWT.TRANSPARENT );
+
+ Composite businessActiveCompo = new Composite(this.compoElements, SWT.TRANSPARENT);
+ Composite businessBehaviorCompo = new Composite(this.compoElements, SWT.TRANSPARENT);
+ Composite businessPassiveCompo = new Composite(this.compoElements, SWT.TRANSPARENT );
+
+ Composite applicationActiveCompo = new Composite(this.compoElements, SWT.TRANSPARENT);
+ Composite applicationBehaviorCompo = new Composite(this.compoElements, SWT.TRANSPARENT);
+ Composite applicationPassiveCompo = new Composite(this.compoElements, SWT.TRANSPARENT);
+
+ Composite technologyActiveCompo = new Composite(this.compoElements, SWT.TRANSPARENT);
+ Composite technologyBehaviorCompo = new Composite(this.compoElements, SWT.TRANSPARENT);
+ Composite technologyPassiveCompo = new Composite(this.compoElements, SWT.TRANSPARENT);
+
+ Composite physicalActiveCompo = new Composite(this.compoElements, SWT.TRANSPARENT);
+ Composite physicalBehaviorCompo = new Composite(this.compoElements, SWT.TRANSPARENT);
+ Composite physicalPassive = new Composite(this.compoElements, SWT.TRANSPARENT);
+
+ Composite implementationCompo = new Composite(this.compoElements, SWT.TRANSPARENT);
+
+
+ Composite motivationCompo = new Composite(this.compoElements, SWT.TRANSPARENT);
+
+ Composite otherCompo = new Composite(this.compoElements, SWT.TRANSPARENT);
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Strategy layer
+ // Passive
+ // Behavior
+ this.capabilityLabel = new ComponentLabel(strategyBehaviorCompo, "Capability");
+ this.courseOfActionLabel = new ComponentLabel(strategyBehaviorCompo, "Course Of Action");
+ // Active
+ this.resourceLabel = new ComponentLabel(strategyActiveCompo, "Resource");
+
+ // Business layer
+ // Passive
+ this.productLabel = new ComponentLabel(businessPassiveCompo, "Product");
+ // Behavior
+ this.businessProcessLabel = new ComponentLabel(businessBehaviorCompo, "Business Process");
+ this.businessFunctionLabel = new ComponentLabel(businessBehaviorCompo, "Business Function");
+ this.businessInteractionLabel = new ComponentLabel(businessBehaviorCompo, "Business Interaction");
+ this.businessEventLabel = new ComponentLabel(businessBehaviorCompo, "Business Event");
+ this.businessServiceLabel = new ComponentLabel(businessBehaviorCompo, "Business Service");
+ this.businessObjectLabel = new ComponentLabel(businessBehaviorCompo, "Business Object");
+ this.contractLabel = new ComponentLabel(businessBehaviorCompo, "Contract");
+ this.representationLabel = new ComponentLabel(businessBehaviorCompo, "Representation");
+ // Active
+ this.businessActorLabel = new ComponentLabel(businessActiveCompo, "Business Actor");
+ this.businessRoleLabel = new ComponentLabel(businessActiveCompo, "Business Role");
+ this.businessCollaborationLabel = new ComponentLabel(businessActiveCompo, "Business Collaboration");
+ this.businessInterfaceLabel = new ComponentLabel(businessActiveCompo, "Business Interface");
+
+ // Application layer
+ //Passive
+ this.dataObjectLabel = new ComponentLabel(applicationPassiveCompo, "Data Object");
+ //Behavior
+ this.applicationFunctionLabel = new ComponentLabel(applicationBehaviorCompo, "Application Function");
+ this.applicationInteractionLabel = new ComponentLabel(applicationBehaviorCompo, "Application Interaction");
+ this.applicationEventLabel = new ComponentLabel(applicationBehaviorCompo, "Application Event");
+ this.applicationServiceLabel = new ComponentLabel(applicationBehaviorCompo, "Application Service");
+ this.applicationProcessLabel = new ComponentLabel(applicationBehaviorCompo, "Application Process");
+ // Active
+ this.applicationComponentLabel = new ComponentLabel(applicationActiveCompo, "Application Component");
+ this.applicationCollaborationLabel = new ComponentLabel(applicationActiveCompo, "Application Collaboration");
+ this.applicationInterfaceLabel = new ComponentLabel(applicationActiveCompo, "Application Interface");
+
+ // Technology layer
+ // Passive
+ this.artifactLabel = new ComponentLabel(technologyPassiveCompo, "Artifact");
+ // Behavior
+ this.technologyFunctionLabel = new ComponentLabel(technologyBehaviorCompo, "Technology Function");
+ this.technologyProcessLabel = new ComponentLabel(technologyBehaviorCompo, "Technology Process");
+ this.technologyInteractionLabel = new ComponentLabel(technologyBehaviorCompo, "Technology Interaction");
+ this.technologyEventLabel = new ComponentLabel(technologyBehaviorCompo, "Technology Event");
+ this.technologyServiceLabel = new ComponentLabel(technologyBehaviorCompo, "Technology Service");
+ // Active
+ this.nodeLabel = new ComponentLabel(technologyActiveCompo, "Node");
+ this.deviceLabel = new ComponentLabel(technologyActiveCompo, "Device");
+ this.systemSoftwareLabel = new ComponentLabel(technologyActiveCompo, "System Software");
+ this.technologyCollaborationLabel = new ComponentLabel(technologyActiveCompo, "Technology Collaboration");
+ this.technologyInterfaceLabel = new ComponentLabel(technologyActiveCompo, "Technology Interface");
+ this.pathLabel = new ComponentLabel(technologyActiveCompo, "Path");
+ this.communicationNetworkLabel = new ComponentLabel(technologyActiveCompo, "Communication Network");
+
+ // Physical layer
+ // Passive
+ // Behavior
+ this.materialLabel = new ComponentLabel(physicalBehaviorCompo, "Material");
+ // Active
+ this.equipmentLabel = new ComponentLabel(physicalActiveCompo, "Equipment");
+ this.facilityLabel = new ComponentLabel(physicalActiveCompo, "Facility");
+ this.distributionNetworkLabel = new ComponentLabel(physicalActiveCompo, "Distribution Network");
+
+ // Implementation layer
+ this.workpackageLabel = new ComponentLabel(implementationCompo, "Work Package");
+ this.deliverableLabel = new ComponentLabel(implementationCompo, "Deliverable");
+ this.implementationEventLabel = new ComponentLabel(implementationCompo, "Implementation Event");
+ this.plateauLabel = new ComponentLabel(implementationCompo, "Plateau");
+ this.gapLabel = new ComponentLabel(implementationCompo, "Gap");
+
+ // Motivation layer
+ this.stakeholderLabel = new ComponentLabel(motivationCompo, "Stakeholder");
+ this.driverLabel = new ComponentLabel(motivationCompo, "Driver");
+ this.assessmentLabel = new ComponentLabel(motivationCompo, "Assessment");
+ this.goalLabel = new ComponentLabel(motivationCompo, "Goal");
+ this.outcomeLabel = new ComponentLabel(motivationCompo, "Outcome");
+ this.principleLabel = new ComponentLabel(motivationCompo, "Principle");
+ this.requirementLabel = new ComponentLabel(motivationCompo, "Requirement");
+ this.constaintLabel = new ComponentLabel(motivationCompo, "Constraint");
+ this.smeaningLabel = new ComponentLabel(motivationCompo, "Meaning");
+ this.valueLabel = new ComponentLabel(motivationCompo, "Value");
+
+ // Containers !!!
+ //
+ this.groupingLabel = new ComponentLabel(otherCompo, "Grouping");
+ this.locationLabel = new ComponentLabel(otherCompo, "Location");
+ this.junctionLabel = new ComponentLabel(otherCompo, "Junction");
+
+ this.allElementLabels = new ComponentLabel[]{ this.resourceLabel, this.capabilityLabel, this.courseOfActionLabel, this.applicationComponentLabel, this.applicationCollaborationLabel, this.applicationInterfaceLabel, this.applicationFunctionLabel, this.applicationInteractionLabel, this.applicationEventLabel, this.applicationServiceLabel, this.dataObjectLabel, this.applicationProcessLabel, this.businessActorLabel, this.businessRoleLabel, this.businessCollaborationLabel, this.businessInterfaceLabel, this.businessProcessLabel, this.businessFunctionLabel, this.businessInteractionLabel, this.businessEventLabel, this.businessServiceLabel, this.businessObjectLabel, this.contractLabel, this.representationLabel, this.nodeLabel, this.deviceLabel, this.systemSoftwareLabel, this.technologyCollaborationLabel, this.technologyInterfaceLabel, this.pathLabel, this.communicationNetworkLabel, this.technologyFunctionLabel, this.technologyProcessLabel, this.technologyInteractionLabel, this.technologyEventLabel, this.technologyServiceLabel, this.artifactLabel, this.equipmentLabel, this.facilityLabel, this.distributionNetworkLabel, this.materialLabel, this.workpackageLabel, this.deliverableLabel, this.implementationEventLabel, this.plateauLabel, this.gapLabel, this.stakeholderLabel, this.driverLabel, this.assessmentLabel, this.goalLabel, this.outcomeLabel, this.principleLabel, this.requirementLabel, this.constaintLabel, this.smeaningLabel, this.valueLabel, this.productLabel, this.locationLabel, this.groupingLabel, this.junctionLabel};
+
+ Label passiveLabel = new Label(this.compoElements, SWT.TRANSPARENT | SWT.CENTER);
+ Canvas passiveCanvas = new Canvas(this.compoElements, SWT.TRANSPARENT | SWT.BORDER);
+ fd = new FormData();
+ fd.top = new FormAttachment(title, 2);
+ fd.bottom = new FormAttachment(implementationCompo, 1, SWT.TOP);
+ fd.left = new FormAttachment(0, 70);
+ fd.right = new FormAttachment(0, 110);
+ passiveCanvas.setLayoutData(fd);
+ fd = new FormData();
+ fd.top = new FormAttachment(passiveCanvas, 1, SWT.TOP);
+ fd.left = new FormAttachment(0, 71);
+ fd.right = new FormAttachment(0, 109);
+ passiveLabel.setLayoutData(fd);
+ passiveLabel.setText("Passive");
+ passiveLabel.setBackground(PASSIVE_COLOR);
+ passiveLabel.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseUp(MouseEvent event) {
+ ArrayList labelList = new ArrayList();
+
+ labelList.add(DBGuiImportComponents.this.productLabel);
+ labelList.add(DBGuiImportComponents.this.dataObjectLabel);
+ labelList.add(DBGuiImportComponents.this.artifactLabel);
+
+ boolean areAllSet = true;
+ for ( ComponentLabel label: labelList) {
+ if ( !label.isSelected()) {
+ areAllSet = false;
+ break;
+ }
+ }
+
+ for ( ComponentLabel label: labelList) {
+ label.setSelected(!areAllSet);
+ label.redraw();
+ }
+
+ if ( event != null ) {
+ super.mouseUp(event);
+
+ try {
+ getElements();
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "An exception has been raised.", err);
+ }
+ }
+ }
+ });
+
+ Label behaviorLabel = new Label(this.compoElements, SWT.TRANSPARENT | SWT.CENTER);
+ Canvas behaviorCanvas = new Canvas(this.compoElements, SWT.TRANSPARENT | SWT.BORDER);
+ fd = new FormData();
+ fd.top = new FormAttachment(title, 2);
+ fd.bottom = new FormAttachment(implementationCompo, 1, SWT.TOP);
+ fd.left = new FormAttachment(0, 115);
+ fd.right = new FormAttachment(55);
+ behaviorCanvas.setLayoutData(fd);
+ fd = new FormData();
+ fd.top = new FormAttachment(behaviorCanvas, 1, SWT.TOP);
+ fd.left = new FormAttachment(0, 116);
+ fd.right = new FormAttachment(55, -1);
+ behaviorLabel.setLayoutData(fd);
+ behaviorLabel.setText("Behavior");
+ behaviorLabel.setBackground(PASSIVE_COLOR);
+ behaviorLabel.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseUp(MouseEvent event) {
+ ArrayList labelList = new ArrayList();
+
+ labelList.add(DBGuiImportComponents.this.capabilityLabel);
+ labelList.add(DBGuiImportComponents.this.courseOfActionLabel);
+ labelList.add(DBGuiImportComponents.this.businessProcessLabel);
+ labelList.add(DBGuiImportComponents.this.businessFunctionLabel);
+ labelList.add(DBGuiImportComponents.this.businessInteractionLabel);
+ labelList.add(DBGuiImportComponents.this.businessEventLabel);
+ labelList.add(DBGuiImportComponents.this.businessServiceLabel);
+ labelList.add(DBGuiImportComponents.this.businessObjectLabel);
+ labelList.add(DBGuiImportComponents.this.contractLabel);
+ labelList.add(DBGuiImportComponents.this.representationLabel);
+ labelList.add(DBGuiImportComponents.this.applicationFunctionLabel);
+ labelList.add(DBGuiImportComponents.this.applicationInteractionLabel);
+ labelList.add(DBGuiImportComponents.this.applicationEventLabel);
+ labelList.add(DBGuiImportComponents.this.applicationServiceLabel);
+ labelList.add(DBGuiImportComponents.this.applicationProcessLabel);
+ labelList.add(DBGuiImportComponents.this.technologyFunctionLabel);
+ labelList.add(DBGuiImportComponents.this.technologyProcessLabel);
+ labelList.add(DBGuiImportComponents.this.technologyInteractionLabel);
+ labelList.add(DBGuiImportComponents.this.technologyEventLabel);
+ labelList.add(DBGuiImportComponents.this.technologyServiceLabel);
+ labelList.add(DBGuiImportComponents.this.materialLabel);
+
+ boolean areAllSet = true;
+ for ( ComponentLabel label: labelList) {
+ if ( !label.isSelected()) {
+ areAllSet = false;
+ break;
+ }
+ }
+
+ for ( ComponentLabel label: labelList) {
+ label.setSelected(!areAllSet);
+ label.redraw();
+ }
+
+ if ( event != null ) {
+ super.mouseUp(event);
+
+ try {
+ getElements();
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "An exception has been raised.", err);
+ }
+ }
+ }
+ });
+
+ Label activeLabel = new Label(this.compoElements, SWT.TRANSPARENT | SWT.CENTER);
+ Canvas activeCanvas = new Canvas(this.compoElements, SWT.TRANSPARENT | SWT.BORDER);
+ fd = new FormData();
+ fd.top = new FormAttachment(title, 2);
+ fd.bottom = new FormAttachment(implementationCompo, 1, SWT.TOP);
+ fd.left = new FormAttachment(55, 5);
+ fd.right = new FormAttachment(100, -65);
+ activeCanvas.setLayoutData(fd);
+ fd = new FormData();
+ fd.top = new FormAttachment(activeCanvas, 1, SWT.TOP);
+ fd.left = new FormAttachment(55, 6);
+ fd.right = new FormAttachment(100, -66);
+ activeLabel.setLayoutData(fd);
+ activeLabel.setText("Active");
+ activeLabel.setBackground(PASSIVE_COLOR);
+ activeLabel.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseUp(MouseEvent event) {
+ ArrayList labelList = new ArrayList();
+
+ labelList.add(DBGuiImportComponents.this.resourceLabel);
+ labelList.add(DBGuiImportComponents.this.businessActorLabel);
+ labelList.add(DBGuiImportComponents.this.businessRoleLabel);
+ labelList.add(DBGuiImportComponents.this.businessCollaborationLabel);
+ labelList.add(DBGuiImportComponents.this.businessInterfaceLabel);
+ labelList.add(DBGuiImportComponents.this.applicationComponentLabel);
+ labelList.add(DBGuiImportComponents.this.applicationCollaborationLabel);
+ labelList.add(DBGuiImportComponents.this.applicationInterfaceLabel);
+ labelList.add(DBGuiImportComponents.this.nodeLabel);
+ labelList.add(DBGuiImportComponents.this.deviceLabel);
+ labelList.add(DBGuiImportComponents.this.systemSoftwareLabel);
+ labelList.add(DBGuiImportComponents.this.technologyCollaborationLabel);
+ labelList.add(DBGuiImportComponents.this.technologyInterfaceLabel);
+ labelList.add(DBGuiImportComponents.this.pathLabel);
+ labelList.add(DBGuiImportComponents.this.communicationNetworkLabel);
+ labelList.add(DBGuiImportComponents.this.equipmentLabel);
+ labelList.add(DBGuiImportComponents.this.facilityLabel);
+ labelList.add(DBGuiImportComponents.this.distributionNetworkLabel);
+
+ boolean areAllSet = true;
+ for ( ComponentLabel label: labelList) {
+ if ( !label.isSelected()) {
+ areAllSet = false;
+ break;
+ }
+ }
+
+ for ( ComponentLabel label: labelList) {
+ label.setSelected(!areAllSet);
+ label.redraw();
+ }
+
+ if ( event != null ) {
+ super.mouseUp(event);
+
+ try {
+ getElements();
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "An exception has been raised.", err);
+ }
+ }
+ }
+ });
+
+ this.lblMotivation = new Label(this.compoElements, SWT.TRANSPARENT | SWT.CENTER);
+ Canvas motivationCanvas = new Canvas(this.compoElements, SWT.TRANSPARENT);
+ fd = new FormData();
+ fd.top = new FormAttachment(title, 2);
+ fd.bottom = new FormAttachment(85, -2);
+ fd.left = new FormAttachment(100, -60);
+ fd.right = new FormAttachment(100);
+ motivationCanvas.setLayoutData(fd);
+ fd = new FormData();
+ fd.top = new FormAttachment(motivationCanvas, 1, SWT.TOP);
+ fd.left = new FormAttachment(100, -59);
+ fd.right = new FormAttachment(100, -1);
+ this.lblMotivation.setLayoutData(fd);
+ this.lblMotivation.setText("Motivation");
+ this.lblMotivation.setBackground(MOTIVATION_COLOR);
+ this.lblMotivation.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseUp(MouseEvent event) {
+ ArrayList labelList = new ArrayList();
+
+ labelList.add(DBGuiImportComponents.this.stakeholderLabel);
+ labelList.add(DBGuiImportComponents.this.driverLabel);
+ labelList.add(DBGuiImportComponents.this.assessmentLabel);
+ labelList.add(DBGuiImportComponents.this.goalLabel);
+ labelList.add(DBGuiImportComponents.this.outcomeLabel);
+ labelList.add(DBGuiImportComponents.this.valueLabel);
+ labelList.add(DBGuiImportComponents.this.principleLabel);
+ labelList.add(DBGuiImportComponents.this.requirementLabel);
+ labelList.add(DBGuiImportComponents.this.constaintLabel);
+ labelList.add(DBGuiImportComponents.this.smeaningLabel);
+
+ boolean areAllSet = true;
+ for ( ComponentLabel label: labelList) {
+ if ( !label.isSelected()) {
+ areAllSet = false;
+ break;
+ }
+ }
+
+ for ( ComponentLabel label: labelList) {
+ label.setSelected(!areAllSet);
+ label.redraw();
+ }
+
+ if ( event != null ) {
+ super.mouseUp(event);
+
+ try {
+ getElements();
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "An exception has been raised.", err);
+ }
+ }
+ }
+ });
+
+ PaintListener redraw = new PaintListener() {
+ @Override
+ public void paintControl(PaintEvent event) {
+ event.gc.setAlpha(100);
+ if ( event.widget == motivationCanvas )
+ event.gc.setBackground(MOTIVATION_COLOR);
+ else
+ event.gc.setBackground(PASSIVE_COLOR);
+ event.gc.fillRectangle(event.x, event.y, event.width, event.height);
+ }
+ };
+
+ passiveCanvas.addPaintListener(redraw);
+ behaviorCanvas.addPaintListener(redraw);
+ activeCanvas.addPaintListener(redraw);
+ motivationCanvas.addPaintListener(redraw);
+
+
+
+
+
+
+
+ this.lblStrategy = new Label(this.compoElements, SWT.NONE);
+ Canvas strategyCanvas = new Canvas(this.compoElements, SWT.NONE);
+ fd = new FormData();
+ fd.top = new FormAttachment(15, 2);
+ fd.bottom = new FormAttachment(29, -2);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100, -60);
+ strategyCanvas.setLayoutData(fd);
+ strategyCanvas.setBackground(STRATEGY_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(strategyCanvas, 0, SWT.CENTER);
+ fd.left = new FormAttachment(strategyCanvas, 2, SWT.LEFT);
+ this.lblStrategy.setLayoutData(fd);
+ this.lblStrategy.setBackground(STRATEGY_COLOR);
+ this.lblStrategy.setText("Strategy");
+ this.lblStrategy.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseUp(MouseEvent event) {
+ ArrayList labelList = new ArrayList();
+
+ labelList.add(DBGuiImportComponents.this.capabilityLabel);
+ labelList.add(DBGuiImportComponents.this.courseOfActionLabel);
+ labelList.add(DBGuiImportComponents.this.resourceLabel);
+
+ boolean areAllSet = true;
+ for ( ComponentLabel label: labelList) {
+ if ( !label.isSelected()) {
+ areAllSet = false;
+ break;
+ }
+ }
+
+ for ( ComponentLabel label: labelList) {
+ label.setSelected(!areAllSet);
+ label.redraw();
+ }
+
+ if ( event != null ) {
+ super.mouseUp(event);
+
+ try {
+ getElements();
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "An exception has been raised.", err);
+ }
+ }
+ }
+ });
+
+ this.lblBusiness = new Label(this.compoElements, SWT.NONE);
+ Canvas businessCanvas = new Canvas(this.compoElements, SWT.NONE);
+ fd = new FormData();
+ fd.top = new FormAttachment(29, 2);
+ fd.bottom = new FormAttachment(43, -2);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100, -60);
+ businessCanvas.setLayoutData(fd);
+ businessCanvas.setBackground(BUSINESS_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(businessCanvas, 0, SWT.CENTER);
+ fd.left = new FormAttachment(businessCanvas, 2, SWT.LEFT);
+ this.lblBusiness.setLayoutData(fd);
+ this.lblBusiness.setBackground(BUSINESS_COLOR);
+ this.lblBusiness.setText("Business");
+ this.lblBusiness.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseUp(MouseEvent event) {
+ ArrayList labelList = new ArrayList();
+
+ labelList.add(DBGuiImportComponents.this.productLabel);
+ labelList.add(DBGuiImportComponents.this.businessProcessLabel);
+ labelList.add(DBGuiImportComponents.this.businessFunctionLabel);
+ labelList.add(DBGuiImportComponents.this.businessInteractionLabel);
+ labelList.add(DBGuiImportComponents.this.businessEventLabel);
+ labelList.add(DBGuiImportComponents.this.businessServiceLabel);
+ labelList.add(DBGuiImportComponents.this.businessObjectLabel);
+ labelList.add(DBGuiImportComponents.this.contractLabel);
+ labelList.add(DBGuiImportComponents.this.representationLabel);
+ labelList.add(DBGuiImportComponents.this.businessActorLabel);
+ labelList.add(DBGuiImportComponents.this.businessRoleLabel);
+ labelList.add(DBGuiImportComponents.this.businessCollaborationLabel);
+ labelList.add(DBGuiImportComponents.this.businessInterfaceLabel);
+
+ boolean areAllSet = true;
+ for ( ComponentLabel label: labelList) {
+ if ( !label.isSelected()) {
+ areAllSet = false;
+ break;
+ }
+ }
+
+ for ( ComponentLabel label: labelList) {
+ label.setSelected(!areAllSet);
+ label.redraw();
+ }
+
+ if ( event != null ) {
+ super.mouseUp(event);
+
+ try {
+ getElements();
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "An exception has been raised.", err);
+ }
+ }
+ }
+ });
+
+ this.lblApplication = new Label(this.compoElements, SWT.NONE);
+ Canvas applicationCanvas = new Canvas(this.compoElements, SWT.NONE);
+ fd = new FormData();
+ fd.top = new FormAttachment(43, 2);
+ fd.bottom = new FormAttachment(57, -2);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100, -60);
+ applicationCanvas.setLayoutData(fd);
+ applicationCanvas.setBackground(APPLICATION_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(applicationCanvas, 0, SWT.CENTER);
+ fd.left = new FormAttachment(applicationCanvas, 2, SWT.LEFT);
+ this.lblApplication.setLayoutData(fd);
+ this.lblApplication.setBackground(APPLICATION_COLOR);
+ this.lblApplication.setText("Application");
+ this.lblApplication.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseUp(MouseEvent event) {
+ ArrayList labelList = new ArrayList();
+
+ labelList.add(DBGuiImportComponents.this.dataObjectLabel);
+ labelList.add(DBGuiImportComponents.this.applicationFunctionLabel);
+ labelList.add(DBGuiImportComponents.this.applicationInteractionLabel);
+ labelList.add(DBGuiImportComponents.this.applicationEventLabel);
+ labelList.add(DBGuiImportComponents.this.applicationServiceLabel);
+ labelList.add(DBGuiImportComponents.this.applicationProcessLabel);
+ labelList.add(DBGuiImportComponents.this.applicationComponentLabel);
+ labelList.add(DBGuiImportComponents.this.applicationCollaborationLabel);
+ labelList.add(DBGuiImportComponents.this.applicationInterfaceLabel);
+
+ boolean areAllSet = true;
+ for ( ComponentLabel label: labelList) {
+ if ( !label.isSelected()) {
+ areAllSet = false;
+ break;
+ }
+ }
+
+ for ( ComponentLabel label: labelList) {
+ label.setSelected(!areAllSet);
+ label.redraw();
+ }
+
+ if ( event != null ) {
+ super.mouseUp(event);
+
+ try {
+ getElements();
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "An exception has been raised.", err);
+ }
+ }
+ }
+ });
+
+ this.lblTechnology = new Label(this.compoElements, SWT.NONE);
+ Canvas technologyCanvas = new Canvas(this.compoElements, SWT.NONE);
+ fd = new FormData();
+ fd.top = new FormAttachment(57, 2);
+ fd.bottom = new FormAttachment(71, -2);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100, -60);
+ technologyCanvas.setLayoutData(fd);
+ technologyCanvas.setBackground(TECHNOLOGY_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(technologyCanvas, 0, SWT.CENTER);
+ fd.left = new FormAttachment(technologyCanvas, 2, SWT.LEFT);
+ this.lblTechnology.setLayoutData(fd);
+ this.lblTechnology.setBackground(TECHNOLOGY_COLOR);
+ this.lblTechnology.setText("Technology");
+ this.lblTechnology.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseUp(MouseEvent event) {
+ ArrayList labelList = new ArrayList();
+
+ labelList.add(DBGuiImportComponents.this.artifactLabel);
+ labelList.add(DBGuiImportComponents.this.technologyFunctionLabel);
+ labelList.add(DBGuiImportComponents.this.technologyProcessLabel);
+ labelList.add(DBGuiImportComponents.this.technologyInteractionLabel);
+ labelList.add(DBGuiImportComponents.this.technologyEventLabel);
+ labelList.add(DBGuiImportComponents.this.technologyServiceLabel);
+ labelList.add(DBGuiImportComponents.this.nodeLabel);
+ labelList.add(DBGuiImportComponents.this.deviceLabel);
+ labelList.add(DBGuiImportComponents.this.systemSoftwareLabel);
+ labelList.add(DBGuiImportComponents.this.technologyCollaborationLabel);
+ labelList.add(DBGuiImportComponents.this.technologyInterfaceLabel);
+ labelList.add(DBGuiImportComponents.this.pathLabel);
+ labelList.add(DBGuiImportComponents.this.communicationNetworkLabel);
+
+ boolean areAllSet = true;
+ for ( ComponentLabel label: labelList) {
+ if ( !label.isSelected()) {
+ areAllSet = false;
+ break;
+ }
+ }
+
+ for ( ComponentLabel label: labelList) {
+ label.setSelected(!areAllSet);
+ label.redraw();
+ }
+
+ if ( event != null ) {
+ super.mouseUp(event);
+
+ try {
+ getElements();
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "An exception has been raised.", err);
+ }
+ }
+ }
+ });
+
+ this.lblPhysical = new Label(this.compoElements, SWT.NONE);
+ Canvas physicalCanvas = new Canvas(this.compoElements, SWT.NONE);
+ fd = new FormData();
+ fd.top = new FormAttachment(71, 2);
+ fd.bottom = new FormAttachment(85, -2);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100, -60);
+ physicalCanvas.setLayoutData(fd);
+ physicalCanvas.setBackground(PHYSICAL_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(physicalCanvas, 0, SWT.CENTER);
+ fd.left = new FormAttachment(physicalCanvas, 2, SWT.LEFT);
+ this.lblPhysical.setLayoutData(fd);
+ this.lblPhysical.setBackground(PHYSICAL_COLOR);
+ this.lblPhysical.setText("Physical");
+ this.lblPhysical.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseUp(MouseEvent event) {
+ ArrayList labelList = new ArrayList();
+
+ labelList.add(DBGuiImportComponents.this.materialLabel);
+ labelList.add(DBGuiImportComponents.this.equipmentLabel);
+ labelList.add(DBGuiImportComponents.this.facilityLabel);
+ labelList.add(DBGuiImportComponents.this.distributionNetworkLabel);
+
+ boolean areAllSet = true;
+ for ( ComponentLabel label: labelList) {
+ if ( !label.isSelected()) {
+ areAllSet = false;
+ break;
+ }
+ }
+
+ for ( ComponentLabel label: labelList) {
+ label.setSelected(!areAllSet);
+ label.redraw();
+ }
+
+ if ( event != null ) {
+ super.mouseUp(event);
+
+ try {
+ getElements();
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "An exception has been raised.", err);
+ }
+ }
+ }
+ });
+
+ this.lblImplementation = new Label(this.compoElements, SWT.NONE);
+ Canvas implementationCanvas = new Canvas(this.compoElements, SWT.NONE);
+ fd = new FormData();
+ fd.top = new FormAttachment(85, 2);
+ fd.bottom = new FormAttachment(100);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100, -65);
+ implementationCanvas.setLayoutData(fd);
+ implementationCanvas.setBackground(IMPLEMENTATION_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(implementationCanvas, 0, SWT.CENTER);
+ fd.left = new FormAttachment(implementationCanvas, 2, SWT.LEFT);
+ this.lblImplementation.setLayoutData(fd);
+ this.lblImplementation.setBackground(IMPLEMENTATION_COLOR);
+ this.lblImplementation.setText("Implementation");
+ this.lblImplementation.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseUp(MouseEvent event) {
+ ArrayList labelList = new ArrayList();
+
+ labelList.add(DBGuiImportComponents.this.workpackageLabel);
+ labelList.add(DBGuiImportComponents.this.deliverableLabel);
+ labelList.add(DBGuiImportComponents.this.implementationEventLabel);
+ labelList.add(DBGuiImportComponents.this.plateauLabel);
+ labelList.add(DBGuiImportComponents.this.gapLabel);
+
+ boolean areAllSet = true;
+ for ( ComponentLabel label: labelList) {
+ if ( !label.isSelected()) {
+ areAllSet = false;
+ break;
+ }
+ }
+
+ for ( ComponentLabel label: labelList) {
+ label.setSelected(!areAllSet);
+ label.redraw();
+ }
+
+ if ( event != null ) {
+ super.mouseUp(event);
+
+ try {
+ getElements();
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "An exception has been raised.", err);
+ }
+ }
+ }
+ });
+
+ Canvas otherCanvas = new Canvas(this.compoElements, SWT.NONE);
+ fd = new FormData();
+ fd.top = new FormAttachment(85, 2);
+ fd.bottom = new FormAttachment(100);
+ fd.left = new FormAttachment(100, -60);
+ fd.right = new FormAttachment(100);
+ otherCanvas.setLayoutData(fd);
+
+ // strategy + active
+ fd = new FormData();
+ fd.top = new FormAttachment(strategyCanvas, 0, SWT.TOP);
+ fd.bottom = new FormAttachment(strategyCanvas, 0, SWT.BOTTOM);
+ fd.left = new FormAttachment(activeCanvas, 0, SWT.LEFT);
+ fd.right = new FormAttachment(activeCanvas, 0, SWT.RIGHT);
+ strategyActiveCompo.setLayoutData(fd);
+ RowLayout rd = new RowLayout(SWT.HORIZONTAL);
+ rd.center = true;
+ rd.fill = true;
+ rd.justify = true;
+ rd.wrap = true;
+ rd.marginBottom = 5;
+ rd.marginTop = 5;
+ rd.marginLeft = 5;
+ rd.marginRight = 5;
+ rd.spacing = 0;
+ strategyActiveCompo.setLayout(rd);
+
+ // strategy + behavior
+ fd = new FormData();
+ fd.top = new FormAttachment(strategyCanvas, 0, SWT.TOP);
+ fd.bottom = new FormAttachment(strategyCanvas, 0, SWT.BOTTOM);
+ fd.left = new FormAttachment(behaviorCanvas, 0, SWT.LEFT);
+ fd.right = new FormAttachment(behaviorCanvas, 0, SWT.RIGHT);
+ strategyBehaviorCompo.setLayoutData(fd);
+ strategyBehaviorCompo.setLayout(rd);
+
+ // strategy + passive
+ fd = new FormData();
+ fd.top = new FormAttachment(strategyCanvas, 0, SWT.TOP);
+ fd.bottom = new FormAttachment(strategyCanvas, 0, SWT.BOTTOM);
+ fd.left = new FormAttachment(passiveCanvas, 0, SWT.LEFT);
+ fd.right = new FormAttachment(passiveCanvas, 0, SWT.RIGHT);
+ strategyPassiveCompo.setLayoutData(fd);
+ strategyPassiveCompo.setLayout(rd);
+
+ // business + active
+ fd = new FormData();
+ fd.top = new FormAttachment(businessCanvas, 0, SWT.TOP);
+ fd.bottom = new FormAttachment(businessCanvas, 0, SWT.BOTTOM);
+ fd.left = new FormAttachment(activeCanvas, 0, SWT.LEFT);
+ fd.right = new FormAttachment(activeCanvas, 0, SWT.RIGHT);
+ businessActiveCompo.setLayoutData(fd);
+ businessActiveCompo.setLayout(rd);
+
+ // business + behavior
+ fd = new FormData();
+ fd.top = new FormAttachment(businessCanvas, 0, SWT.TOP);
+ fd.bottom = new FormAttachment(businessCanvas, 0, SWT.BOTTOM);
+ fd.left = new FormAttachment(behaviorCanvas, 0, SWT.LEFT);
+ fd.right = new FormAttachment(behaviorCanvas, 0, SWT.RIGHT);
+ businessBehaviorCompo.setLayoutData(fd);
+ businessBehaviorCompo.setLayout(rd);
+
+ // Business + passive
+ fd = new FormData();
+ fd.top = new FormAttachment(businessCanvas, 0, SWT.TOP);
+ fd.bottom = new FormAttachment(businessCanvas, 0, SWT.BOTTOM);
+ fd.left = new FormAttachment(passiveCanvas, 0, SWT.LEFT);
+ fd.right = new FormAttachment(passiveCanvas, 0, SWT.RIGHT);
+ businessPassiveCompo.setLayoutData(fd);
+ businessPassiveCompo.setLayout(rd);
+
+
+
+ // application + active
+ fd = new FormData();
+ fd.top = new FormAttachment(applicationCanvas, 0, SWT.TOP);
+ fd.bottom = new FormAttachment(applicationCanvas, 0, SWT.BOTTOM);
+ fd.left = new FormAttachment(activeCanvas, 0, SWT.LEFT);
+ fd.right = new FormAttachment(activeCanvas, 0, SWT.RIGHT);
+ applicationActiveCompo.setLayoutData(fd);
+ applicationActiveCompo.setLayout(rd);
+
+
+ // application + behavior
+ fd = new FormData();
+ fd.top = new FormAttachment(applicationCanvas, 0, SWT.TOP);
+ fd.bottom = new FormAttachment(applicationCanvas, 0, SWT.BOTTOM);
+ fd.left = new FormAttachment(behaviorCanvas, 0, SWT.LEFT);
+ fd.right = new FormAttachment(behaviorCanvas, 0, SWT.RIGHT);
+ applicationBehaviorCompo.setLayoutData(fd);
+ applicationBehaviorCompo.setLayout(rd);
+
+ // application + passive
+ fd = new FormData();
+ fd.top = new FormAttachment(applicationCanvas, 0, SWT.TOP);
+ fd.bottom = new FormAttachment(applicationCanvas, 0, SWT.BOTTOM);
+ fd.left = new FormAttachment(passiveCanvas, 0, SWT.LEFT);
+ fd.right = new FormAttachment(passiveCanvas, 0, SWT.RIGHT);
+ applicationPassiveCompo.setLayoutData(fd);
+ applicationPassiveCompo.setLayout(rd);
+
+
+ // technology + active
+ fd = new FormData();
+ fd.top = new FormAttachment(technologyCanvas, 0, SWT.TOP);
+ fd.bottom = new FormAttachment(technologyCanvas, 0, SWT.BOTTOM);
+ fd.left = new FormAttachment(activeCanvas, 0, SWT.LEFT);
+ fd.right = new FormAttachment(activeCanvas, 0, SWT.RIGHT);
+ technologyActiveCompo.setLayoutData(fd);
+ technologyActiveCompo.setLayout(rd);
+
+ // technology + behavior
+ fd = new FormData();
+ fd.top = new FormAttachment(technologyCanvas, 0, SWT.TOP);
+ fd.bottom = new FormAttachment(technologyCanvas, 0, SWT.BOTTOM);
+ fd.left = new FormAttachment(behaviorCanvas, 0, SWT.LEFT);
+ fd.right = new FormAttachment(behaviorCanvas, 0, SWT.RIGHT);
+ technologyBehaviorCompo.setLayoutData(fd);
+ technologyBehaviorCompo.setLayout(rd);
+
+ // technology + passive
+ fd = new FormData();
+ fd.top = new FormAttachment(technologyCanvas, 0, SWT.TOP);
+ fd.bottom = new FormAttachment(technologyCanvas, 0, SWT.BOTTOM);
+ fd.left = new FormAttachment(passiveCanvas, 0, SWT.LEFT);
+ fd.right = new FormAttachment(passiveCanvas, 0, SWT.RIGHT);
+ technologyPassiveCompo.setLayoutData(fd);
+ technologyPassiveCompo.setLayout(rd);
+
+ // physical + active
+ fd = new FormData();
+ fd.top = new FormAttachment(physicalCanvas, 0, SWT.TOP);
+ fd.bottom = new FormAttachment(physicalCanvas, 0, SWT.BOTTOM);
+ fd.left = new FormAttachment(activeCanvas, 0, SWT.LEFT);
+ fd.right = new FormAttachment(activeCanvas, 0, SWT.RIGHT);
+ physicalActiveCompo.setLayoutData(fd);
+ physicalActiveCompo.setLayout(rd);
+
+ // physical + behavior
+ fd = new FormData();
+ fd.top = new FormAttachment(physicalCanvas, 0, SWT.TOP);
+ fd.bottom = new FormAttachment(physicalCanvas, 0, SWT.BOTTOM);
+ fd.left = new FormAttachment(behaviorCanvas, 0, SWT.LEFT);
+ fd.right = new FormAttachment(behaviorCanvas, 0, SWT.RIGHT);
+ physicalBehaviorCompo.setLayoutData(fd);
+ physicalBehaviorCompo.setLayout(rd);
+
+ // physical + passive
+ fd = new FormData();
+ fd.top = new FormAttachment(physicalCanvas, 0, SWT.TOP);
+ fd.bottom = new FormAttachment(physicalCanvas, 0, SWT.BOTTOM);
+ fd.left = new FormAttachment(passiveCanvas, 0, SWT.LEFT);
+ fd.right = new FormAttachment(passiveCanvas, 0, SWT.RIGHT);
+ physicalPassive.setLayoutData(fd);
+ physicalPassive.setLayout(rd);
+
+ // implementation
+ fd = new FormData();
+ fd.top = new FormAttachment(implementationCanvas, 0, SWT.TOP);
+ fd.bottom = new FormAttachment(implementationCanvas, 0, SWT.BOTTOM);
+ fd.left = new FormAttachment(passiveCanvas, 0, SWT.LEFT);
+ fd.right = new FormAttachment(activeCanvas, 0, SWT.RIGHT);
+ implementationCompo.setLayoutData(fd);
+ rd = new RowLayout(SWT.HORIZONTAL);
+ rd.center = true;
+ rd.fill = true;
+ rd.justify = true;
+ rd.wrap = true;
+ rd.marginBottom = 5;
+ rd.marginTop = 7;
+ rd.marginLeft = 5;
+ rd.marginRight = 5;
+ rd.spacing = 0;
+ implementationCompo.setLayout(rd);
+
+ // motivation
+ fd = new FormData();
+ fd.top = new FormAttachment(motivationCanvas, 20, SWT.TOP);
+ fd.bottom = new FormAttachment(motivationCanvas, 0, SWT.BOTTOM);
+ fd.left = new FormAttachment(motivationCanvas, 0, SWT.LEFT);
+ fd.right = new FormAttachment(motivationCanvas, 0, SWT.RIGHT);
+ motivationCompo.setLayoutData(fd);
+ rd = new RowLayout(SWT.VERTICAL);
+ rd.center = true;
+ rd.fill = true;
+ rd.justify = true;
+ rd.wrap = true;
+ rd.marginBottom = 5;
+ rd.marginTop = 5;
+ rd.marginLeft = 20;
+ rd.marginRight = 5;
+ rd.spacing = 0;
+ motivationCompo.setLayout(rd);
+
+ // other
+ fd = new FormData();
+ fd.top = new FormAttachment(otherCanvas, 0, SWT.TOP);
+ fd.bottom = new FormAttachment(otherCanvas, 0, SWT.BOTTOM);
+ fd.left = new FormAttachment(otherCanvas, 0, SWT.LEFT);
+ fd.right = new FormAttachment(otherCanvas, 0, SWT.RIGHT);
+ otherCompo.setLayoutData(fd);
+ rd = new RowLayout(SWT.HORIZONTAL);
+ rd.center = true;
+ rd.fill = true;
+ rd.justify = true;
+ rd.wrap = true;
+ rd.marginBottom = 5;
+ rd.marginTop = 5;
+ rd.marginLeft = 5;
+ rd.marginRight = 5;
+ rd.spacing = 0;
+ otherCompo.setLayout(rd);
+ }
+
+ /*
+ private void createCompoFolders() {
+ compoFolders = new Composite(grpFilter, SWT.NONE);
+ compoFolders.setBackground(GROUP_BACKGROUND_COLOR);
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(0, 135);
+ fd.right = new FormAttachment(100, -getDefaultMargin());
+ fd.bottom = new FormAttachment(100, -getDefaultMargin());
+ compoFolders.setLayoutData(fd);
+ compoFolders.setLayout(new FormLayout());
+
+ Label folderTypeLabel = new Label(compoFolders, SWT.NONE);
+ folderTypeLabel.setBackground(GROUP_BACKGROUND_COLOR);
+ folderTypeLabel.setText("Select folders type to display:");
+ fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(0, 30);
+ folderTypeLabel.setLayoutData(fd);
+
+ strategyFolders = new Button(compoFolders, SWT.CHECK);
+ strategyFolders.setBackground(GROUP_BACKGROUND_COLOR);
+ strategyFolders.setText("Strategy");
+ fd = new FormData();
+ fd.top = new FormAttachment(folderTypeLabel, 5);
+ fd.left = new FormAttachment(folderTypeLabel, 20, SWT.LEFT);
+ strategyFolders.setLayoutData(fd);
+ strategyFolders.addListener(SWT.MouseUp, getFoldersListener);
+
+ businessFolders = new Button(compoFolders, SWT.CHECK);
+ businessFolders.setBackground(GROUP_BACKGROUND_COLOR);
+ businessFolders.setText("Business");
+ fd = new FormData();
+ fd.top = new FormAttachment(strategyFolders, 5);
+ fd.left = new FormAttachment(strategyFolders, 0, SWT.LEFT);
+ businessFolders.setLayoutData(fd);
+ businessFolders.addListener(SWT.MouseUp, getFoldersListener);
+
+ applicationFolders = new Button(compoFolders, SWT.CHECK);
+ applicationFolders.setBackground(GROUP_BACKGROUND_COLOR);
+ applicationFolders.setText("Application");
+ fd = new FormData();
+ fd.top = new FormAttachment(businessFolders, 5);
+ fd.left = new FormAttachment(strategyFolders, 0, SWT.LEFT);
+ applicationFolders.setLayoutData(fd);
+ applicationFolders.addListener(SWT.MouseUp, getFoldersListener);
+
+ technologyFolders = new Button(compoFolders, SWT.CHECK);
+ technologyFolders.setBackground(GROUP_BACKGROUND_COLOR);
+ technologyFolders.setText("Technology && Physical");
+ fd = new FormData();
+ fd.top = new FormAttachment(applicationFolders, 5);
+ fd.left = new FormAttachment(strategyFolders, 0, SWT.LEFT);
+ technologyFolders.setLayoutData(fd);
+ technologyFolders.addListener(SWT.MouseUp, getFoldersListener);
+
+ motivationFolders = new Button(compoFolders, SWT.CHECK);
+ motivationFolders.setBackground(GROUP_BACKGROUND_COLOR);
+ motivationFolders.setText("Motivation");
+ fd = new FormData();
+ fd.top = new FormAttachment(technologyFolders, 5);
+ fd.left = new FormAttachment(strategyFolders, 0, SWT.LEFT);
+ motivationFolders.setLayoutData(fd);
+ motivationFolders.addListener(SWT.MouseUp, getFoldersListener);
+
+ implementationFolders = new Button(compoFolders, SWT.CHECK);
+ implementationFolders.setBackground(GROUP_BACKGROUND_COLOR);
+ implementationFolders.setText("Implementation & Migration");
+ fd = new FormData();
+ fd.top = new FormAttachment(motivationFolders, 5);
+ fd.left = new FormAttachment(strategyFolders, 0, SWT.LEFT);
+ implementationFolders.setLayoutData(fd);
+ implementationFolders.addListener(SWT.MouseUp, getFoldersListener);
+
+ otherFolders = new Button(compoFolders, SWT.CHECK);
+ otherFolders.setBackground(GROUP_BACKGROUND_COLOR);
+ otherFolders.setText("Other");
+ fd = new FormData();
+ fd.top = new FormAttachment(implementationFolders, 5);
+ fd.left = new FormAttachment(strategyFolders, 0, SWT.LEFT);
+ otherFolders.setLayoutData(fd);
+ otherFolders.addListener(SWT.MouseUp, getFoldersListener);
+ }
+ */
+
+ private void createCompoViews() {
+ this.compoViews = new Composite(this.grpFilter, SWT.NONE);
+ this.compoViews.setBackground(GROUP_BACKGROUND_COLOR);
+ this.compoViews.setVisible(false);
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(0, 135);
+ fd.right = new FormAttachment(100, -getDefaultMargin());
+ fd.bottom = new FormAttachment(100, -getDefaultMargin());
+ this.compoViews.setLayoutData(fd);
+ this.compoViews.setLayout(new FormLayout());
+
+ Label viewTypeLabel = new Label(this.compoViews, SWT.NONE);
+ viewTypeLabel.setBackground(GROUP_BACKGROUND_COLOR);
+ viewTypeLabel.setText("Select views type to display:");
+ fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(0, 30);
+ viewTypeLabel.setLayoutData(fd);
+
+ this.archimateViews = new Button(this.compoViews, SWT.CHECK);
+ this.archimateViews.setBackground(GROUP_BACKGROUND_COLOR);
+ this.archimateViews.setText("Archimate views");
+ this.archimateViews.setSelection(true);
+ fd = new FormData();
+ fd.top = new FormAttachment(viewTypeLabel, 5);
+ fd.left = new FormAttachment(viewTypeLabel, 20, SWT.LEFT);
+ this.archimateViews.setLayoutData(fd);
+ this.archimateViews.addListener(SWT.MouseUp, this.getViewsListener);
+
+ this.canvasViews = new Button(this.compoViews, SWT.CHECK);
+ this.canvasViews.setBackground(GROUP_BACKGROUND_COLOR);
+ this.canvasViews.setText("Canvas");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.archimateViews, 5);
+ fd.left = new FormAttachment(viewTypeLabel, 20, SWT.LEFT);
+ this.canvasViews.setLayoutData(fd);
+ this.canvasViews.addListener(SWT.MouseUp, this.getViewsListener);
+
+ this.sketchViews = new Button(this.compoViews, SWT.CHECK);
+ this.sketchViews.setBackground(GROUP_BACKGROUND_COLOR);
+ this.sketchViews.setText("Sketch views");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.canvasViews, 5);
+ fd.left = new FormAttachment(viewTypeLabel, 20, SWT.LEFT);
+ this.sketchViews.setLayoutData(fd);
+ this.sketchViews.addListener(SWT.MouseUp, this.getViewsListener);
+ }
+
+ private void createGrpComponents() {
+ this.grpComponent = new Group(this.compoRightBottom, SWT.NONE);
+ this.grpComponent.setBackground(GROUP_BACKGROUND_COLOR);
+ this.grpComponent.setFont(GROUP_TITLE_FONT);
+ this.grpComponent.setText("Select the component to import: ");
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(this.grpFilter, getDefaultMargin());
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ fd.bottom = new FormAttachment(100);
+ this.grpComponent.setLayoutData(fd);
+ this.grpComponent.setLayout(new FormLayout());
+
+ this.lblComponents = new Label(this.grpComponent, SWT.CENTER);
+ this.lblComponents.setBackground(GROUP_BACKGROUND_COLOR);
+ this.lblComponents.setText("0 component matches your criterias.");
+ fd = new FormData();
+ fd.top = new FormAttachment(0, 5);
+ fd.left = new FormAttachment(0, 5);
+ fd.right = new FormAttachment(70, -5);
+ this.lblComponents.setLayoutData(fd);
+
+ SelectionListener redrawTblComponents = new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent event) {
+ try {
+ if ( DBGuiImportComponents.this.importConnection.isConnected() ) {
+ DBGuiImportComponents.this.tblComponents.clearAll();
+
+ if ( DBGuiImportComponents.this.radioOptionModel.getSelection() )
+ getModels();
+ else if ( DBGuiImportComponents.this.radioOptionElement.getSelection() )
+ getElements();
+ else if ( DBGuiImportComponents.this.radioOptionView.getSelection() )
+ getViews();
+ }
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "An exception has been raised.", err);
+ }
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent event) {
+ widgetSelected(event);
+ }
+ };
+
+ this.hideAlreadyInModel = new Button(this.grpComponent, SWT.CHECK);
+ this.hideAlreadyInModel.setBackground(GROUP_BACKGROUND_COLOR);
+ this.hideAlreadyInModel.setText("Hide components already in model");
+ this.hideAlreadyInModel.setSelection(true);
+ this.hideAlreadyInModel.addSelectionListener(redrawTblComponents);
+
+ this.hideOption = new Button(this.grpComponent, SWT.CHECK);
+ this.hideOption.setBackground(GROUP_BACKGROUND_COLOR);
+ this.hideOption.setText("Hide components with empty names");
+ this.hideOption.setSelection(true);
+ this.hideOption.addSelectionListener(redrawTblComponents);
+
+ this.tblComponents = new Table(this.grpComponent, SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL | SWT.MULTI);
+ this.tblComponents.setLinesVisible(true);
+ this.tblComponents.setHeaderVisible(true);
+ this.tblComponents.setBackground(TABLE_BACKGROUND_COLOR);
+ this.tblComponents.addListener(SWT.Selection, new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ if ( DBGuiImportComponents.this.tblComponents.getItemCount() < 2 ) {
+ DBGuiImportComponents.this.lblComponents.setText(DBGuiImportComponents.this.tblComponents.getItemCount()+" component matches your criterias");
+ } else {
+ DBGuiImportComponents.this.lblComponents.setText(DBGuiImportComponents.this.tblComponents.getItemCount()+" components match your criterias");
+ }
+
+ if ( DBGuiImportComponents.this.tblComponents.getSelectionCount() == 0) {
+ DBGuiImportComponents.this.lblComponents.setText(DBGuiImportComponents.this.lblComponents.getText()+".");
+ } else {
+ DBGuiImportComponents.this.lblComponents.setText(DBGuiImportComponents.this.lblComponents.getText()+" ("+DBGuiImportComponents.this.tblComponents.getSelectionCount()+" selected).");
+
+ byte[] screenshot = null;
+ if ( DBGuiImportComponents.this.compoViews.isVisible() && (DBGuiImportComponents.this.tblComponents.getSelectionCount() == 1) ) {
+ try ( DBSelect resultViewScreenshot = new DBSelect(DBGuiImportComponents.this.importConnection.getDatabaseEntry().getName(), DBGuiImportComponents.this.importConnection.getConnection(), "SELECT screenshot FROM "+DBGuiImportComponents.this.selectedDatabase.getSchemaPrefix()+"views WHERE id = ? AND version = (SELECT MAX(version) FROM "+DBGuiImportComponents.this.selectedDatabase.getSchemaPrefix()+"views WHERE id = ?)", DBGuiImportComponents.this.tblComponents.getSelection()[0].getData("id"), DBGuiImportComponents.this.tblComponents.getSelection()[0].getData("id")) ) {
+ if ( resultViewScreenshot.next() )
+ screenshot = resultViewScreenshot.getBytes("screenshot");
+ } catch (SQLException e) {
+ logger.error("Failed to get the view screenshot from the database",e);
+ }
+ }
+ DBGuiImportComponents.this.lblPreview.setData("screenshot", screenshot);
+ DBGuiImportComponents.this.lblPreview.notifyListeners(SWT.Resize, new Event());
+ }
+
+ DBGuiImportComponents.this.btnDoAction.setEnabled(true); // as soon a component is selected, we can import it
+ }
+ });
+
+ this.tblComponents.addListener(SWT.Dispose, this.tooltipListener);
+ this.tblComponents.addListener(SWT.KeyDown, this.tooltipListener);
+ this.tblComponents.addListener(SWT.MouseMove, this.tooltipListener);
+ this.tblComponents.addListener(SWT.MouseHover, this.tooltipListener);
+
+ this.lblPreview = new Label(this.grpComponent, SWT.BORDER);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.tblComponents, 0, SWT.TOP);
+ fd.left = new FormAttachment(this.tblComponents, 5);
+ fd.right = new FormAttachment(100, -5);
+ fd.bottom = new FormAttachment(this.tblComponents, 0, SWT.BOTTOM);
+ this.lblPreview.setLayoutData(fd);
+
+ this.lblPreview.addListener(SWT.Resize, new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ Image screenshot = DBGuiImportComponents.this.lblPreview.getImage();
+ if ( screenshot != null ) {
+ DBGuiImportComponents.this.lblPreview.setImage(null);
+ screenshot.dispose();
+ }
+
+ byte[] screenshotBytes = (byte[]) DBGuiImportComponents.this.lblPreview.getData("screenshot");
+ if ( screenshotBytes != null ) {
+ screenshot = new Image(DBGuiImportComponents.this.lblPreview.getDisplay(), new ByteArrayInputStream(screenshotBytes));
+ ImageData data = screenshot.getImageData();
+
+ double scaleWidth = DBGuiImportComponents.this.lblPreview.getSize().x / (double)data.width;
+ double scaleHeight = DBGuiImportComponents.this.lblPreview.getSize().y / (double)data.height;
+ double scale = (scaleWidth < scaleHeight) ? scaleWidth : scaleHeight;
+
+ int width = (int) (data.width * scale);
+ int height = (int) (data.height * scale);
+
+ DBGuiImportComponents.this.lblPreview.setImage(new Image(DBGuiImportComponents.this.lblPreview.getDisplay(), data.scaledTo(width, height)));
+ screenshot.dispose();
+ }
+ }
+ });
+
+ TableColumn colName = new TableColumn(this.tblComponents, SWT.NONE);
+ colName.setText("Name");
+ colName.setWidth(150);
+ colName.addListener(SWT.Selection, this.sortListener);
+
+
+ TableColumn colDocumentation = new TableColumn(this.tblComponents, SWT.NONE);
+ colDocumentation.setText("Documentation");
+ colDocumentation.setWidth(300);
+ colDocumentation.addListener(SWT.Selection, this.sortListener);
+
+ this.tblComponents.addListener(SWT.MouseDoubleClick, new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ if ( DBGuiImportComponents.this.btnDoAction.getEnabled() )
+ DBGuiImportComponents.this.btnDoAction.notifyListeners(SWT.Selection, new Event());
+ }
+ });
+
+ fd = new FormData();
+ fd.bottom = new FormAttachment(100, -5);
+ fd.left = new FormAttachment(35, 5);
+ this.hideOption.setLayoutData(fd);
+
+ fd = new FormData();
+ fd.bottom = new FormAttachment(100, -5);
+ fd.right = new FormAttachment(35, -5);
+ this.hideAlreadyInModel.setLayoutData(fd);
+
+ fd = new FormData();
+ fd.top = new FormAttachment(this.lblComponents, 5);
+ fd.left = new FormAttachment(0, 5);
+ fd.right = new FormAttachment(70, -5);
+ fd.bottom = new FormAttachment(this.hideAlreadyInModel, -5);
+ this.tblComponents.setLayoutData(fd);
+ }
+
+ void getModels() throws Exception {
+ this.compoModels.setVisible(true);
+ this.compoElements.setVisible(false);
+ //compoFolders.setVisible(false);
+ this.compoViews.setVisible(false);
+
+ this.tblComponents.removeAll();
+ Image image = this.lblPreview.getImage();
+ if ( image != null ) {
+ this.lblPreview.setImage(null);
+ image.dispose();
+ }
+ this.lblPreview.setVisible(false);
+
+ if ( this.selectedDatabase == null )
+ return;
+
+ setMessage("Getting list of models from database ...");
+
+ if ( logger.isDebugEnabled() ) logger.debug("Getting models");
+
+ this.hideAlreadyInModel.setVisible(false);
+ this.hideOption.setVisible(false);
+
+ this.tblComponents.getColumn(1).setText("Purpose");
+
+ String filterRequest = "";
+ if ( this.filterName.getText().length() != 0 )
+ filterRequest = " AND UPPER(name) like '%"+this.filterName.getText().toUpperCase()+"%'";
+
+ try (DBSelect result = new DBSelect(DBGuiImportComponents.this.importConnection.getDatabaseEntry().getName(), DBGuiImportComponents.this.importConnection.getConnection(), "SELECT id, version, name, purpose FROM "+this.selectedDatabase.getSchemaPrefix()+"models m WHERE version = (SELECT MAX(version) FROM "+this.selectedDatabase.getSchemaPrefix()+"models WHERE id = m.id)" + filterRequest) ) {
+ while (result.next()) {
+ if ( !DBPlugin.areEqual(result.getString("id"), this.importedModel.getId()) ) {
+ StringBuilder tooltipBuilder = new StringBuilder();
+ TableItem item = createTableItem(this.tblComponents, result.getString("id"), "model", result.getString("name"), result.getString("purpose"));
+ logger.trace("Found model "+result.getString("name"));
+ try ( DBSelect resultProperties = new DBSelect(DBGuiImportComponents.this.importConnection.getDatabaseEntry().getName(), DBGuiImportComponents.this.importConnection.getConnection(), "SELECT name, value FROM "+this.selectedDatabase.getSchemaPrefix()+"properties WHERE parent_id = ? AND parent_version = ?", result.getString("id"), result.getInt("version")) ) {
+ while ( resultProperties.next() ) {
+ if ( tooltipBuilder.length() != 0 )
+ tooltipBuilder.append("\n");
+ tooltipBuilder.append(" - ");
+ tooltipBuilder.append(resultProperties.getString("name"));
+ tooltipBuilder.append(": ");
+ String value = resultProperties.getString("value");
+ if ( value.length() > 22 )
+ tooltipBuilder.append(value.substring(0,19)+"...");
+ else
+ tooltipBuilder.append(value);
+ }
+ }
+ if ( tooltipBuilder.length() != 0 )
+ item.setData("tooltip", tooltipBuilder.toString());
+ }
+ }
+ }
+ closeMessage();
+
+ if ( this.tblComponents.getItemCount() < 2 ) {
+ this.lblComponents.setText(this.tblComponents.getItemCount()+" model matches your criterias");
+ } else {
+ this.lblComponents.setText(this.tblComponents.getItemCount()+" models match your criterias");
+ }
+
+ this.btnDoAction.setEnabled(false);
+ }
+
+ void getElements() throws Exception {
+ this.compoModels.setVisible(false);
+ this.compoElements.setVisible(true);
+ //compoFolders.setVisible(false);
+ this.compoViews.setVisible(false);
+
+ this.tblComponents.removeAll();
+ Image image = this.lblPreview.getImage();
+ if ( image != null ) {
+ this.lblPreview.setImage(null);
+ image.dispose();
+ }
+ this.lblPreview.setVisible(false);
+
+ this.tblComponents.getColumn(1).setText("Documentation");
+
+ if ( this.selectedDatabase == null )
+ return;
+
+ StringBuilder inList = new StringBuilder();
+ ArrayList classList = new ArrayList();
+ for (ComponentLabel label: this.allElementLabels) {
+ if ( label.isSelected() ) {
+ inList.append(inList.length()==0 ? "?" : ", ?");
+ classList.add(label.getElementClassname());
+ }
+ }
+
+ if ( inList.length() != 0 ) {
+ if ( logger.isDebugEnabled() ) logger.debug("Getting elements");
+
+ setMessage("Getting list of elements from the database ...");
+
+ this.hideAlreadyInModel.setVisible(true);
+ this.hideOption.setVisible(true);
+ this.hideOption.setText("Hide components with empty names");
+ String addOn = "";
+ if ( this.hideOption.getSelection() ) {
+ if ( this.selectedDatabase.getDriver().equals("oracle") ) {
+ addOn = " AND LENGTH(name) <> 0";
+ } else {
+ addOn = " AND name <> ''";
+ }
+ }
+
+ addOn += " AND version = (SELECT MAX(version) FROM "+this.selectedDatabase.getSchemaPrefix()+"elements WHERE id = e.id)";
+ addOn += " ORDER BY name";
+
+ if ( inList.length() != 0 ) {
+ String filterRequest = "";
+ if ( this.filterName.getText().length() != 0 )
+ filterRequest = " AND UPPER(name) like '%"+this.filterName.getText().toUpperCase()+"%'";
+
+ try (DBSelect result = new DBSelect(DBGuiImportComponents.this.importConnection.getDatabaseEntry().getName(), DBGuiImportComponents.this.importConnection.getConnection(), "SELECT id, version, class, name, documentation FROM "+this.selectedDatabase.getSchemaPrefix()+"elements e WHERE class IN ("+inList.toString()+")" + filterRequest + addOn, classList) ) {
+ while (result.next()) {
+ if ( !this.hideAlreadyInModel.getSelection() || (this.importedModel.getAllElements().get(result.getString("id"))==null)) {
+ StringBuilder tooltipBuilder = new StringBuilder();
+ TableItem item = createTableItem(this.tblComponents, result.getString("id"), result.getString("Class"), result.getString("name"), result.getString("documentation"));
+
+ try ( DBSelect resultProperties = new DBSelect(DBGuiImportComponents.this.importConnection.getDatabaseEntry().getName(), DBGuiImportComponents.this.importConnection.getConnection(), "SELECT name, value FROM "+this.selectedDatabase.getSchemaPrefix()+"properties WHERE parent_id = ? AND parent_version = ?", result.getString("id"), result.getInt("version")) ) {
+ while ( resultProperties.next() ) {
+ if ( tooltipBuilder.length() != 0 )
+ tooltipBuilder.append("\n");
+ tooltipBuilder.append(" - ");
+ tooltipBuilder.append(resultProperties.getString("name"));
+ tooltipBuilder.append(": ");
+ String value = resultProperties.getString("value");
+ if ( value.length() > 22 )
+ tooltipBuilder.append(value.substring(0,19)+"...");
+ else
+ tooltipBuilder.append(value);
+ }
+ }
+ if ( tooltipBuilder.length() != 0 )
+ item.setData("tooltip", tooltipBuilder.toString());
+ }
+ }
+ }
+ }
+
+ closeMessage();
+ }
+
+ if ( this.tblComponents.getItemCount() < 2 ) {
+ this.lblComponents.setText(this.tblComponents.getItemCount()+" component matches your criterias");
+ } else {
+ this.lblComponents.setText(this.tblComponents.getItemCount()+" components match your criterias");
+ }
+
+ this.btnDoAction.setEnabled(false);
+ }
+
+ /*
+ private void getFolders() throws Exception {
+ this.compoModels.setVisible(false);
+ compoElements.setVisible(false);
+ compoFolders.setVisible(true);
+ compoViews.setVisible(false);
+
+ tblComponents.removeAll();
+ Image image = this.lblPreview.getImage();
+ if ( image != null ) {
+ this.lblPreview.setImage(null);
+ image.dispose();
+ }
+ this.lblPreview.setVisible(false);
+
+ if ( logger.isTraceEnabled() ) logger.trace("Getting folders");
+
+ StringBuilder inList = new StringBuilder();
+ ArrayList typeList = new ArrayList();
+ if ( strategyFolders.getSelection() ) {
+ inList.append(inList.length()==0 ? "?" : ", ?");
+ typeList.add(String.valueOf(FolderType.STRATEGY_VALUE));
+ }
+ if ( businessFolders.getSelection() ) {
+ inList.append(inList.length()==0 ? "?" : ", ?");
+ typeList.add(String.valueOf(FolderType.BUSINESS_VALUE));
+ }
+ if ( applicationFolders.getSelection() ) {
+ inList.append(inList.length()==0 ? "?" : ", ?");
+ typeList.add(String.valueOf(FolderType.APPLICATION_VALUE));
+ }
+ if ( technologyFolders.getSelection() ) {
+ inList.append(inList.length()==0 ? "?" : ", ?");
+ typeList.add(String.valueOf(FolderType.TECHNOLOGY_VALUE));
+ }
+ if ( motivationFolders.getSelection() ) {
+ inList.append(inList.length()==0 ? "?" : ", ?");
+ typeList.add(String.valueOf(FolderType.MOTIVATION_VALUE));
+ }
+ if ( implementationFolders.getSelection() ) {
+ inList.append(inList.length()==0 ? "?" : ", ?");
+ typeList.add(String.valueOf(FolderType.IMPLEMENTATION_MIGRATION_VALUE));
+ }
+ if ( otherFolders.getSelection() ) {
+ inList.append(inList.length()==0 ? "?" : ", ?");
+ typeList.add(String.valueOf(FolderType.OTHER_VALUE));
+ }
+
+ hideOption.setText("Hide top level folders");
+ String addOn = "";
+ if ( hideOption.getSelection() )
+ addOn = " AND type = 0";
+ addOn += " ORDER BY name";
+
+ if ( inList.length() != 0 ) {
+ String filterRequest = "";
+ if ( this.filterName.getText().length() != 0 )
+ filterRequest = " AND UPPER(name) like '%"+this.filterName.getText().toUpperCase()+"%'";
+
+ try ( ResultSet result = database.select("SELECT id, name, documentation FROM "+selectedDatabase.getSchemaPrefix()+"folders WHERE root_type IN ("+inList.toString()+")" + filterRequest + addOn, typeList)) {
+ while (result.next()) {
+ if ( !hideAlreadyInModel.getSelection() || (importedModel.getAllFolders().get(result.getString("id"))==null))
+ createTableItem(tblComponents, result.getString("id"), "Folder", result.getString("name"), result.getString("documentation"));
+ }
+ }
+ }
+
+ if ( tblComponents.getItemCount() < 2 ) {
+ lblComponents.setText(tblComponents.getItemCount()+" component matches your criterias");
+ } else {
+ lblComponents.setText(tblComponents.getItemCount()+" components match your criterias");
+ }
+
+ btnDoAction.setEnabled(false);
+ }
+ */
+
+ void getViews() throws Exception {
+ this.compoModels.setVisible(false);
+ this.compoElements.setVisible(false);
+ //compoFolders.setVisible(false);
+ this.compoViews.setVisible(true);
+
+ this.tblComponents.removeAll();
+ Image image = this.lblPreview.getImage();
+ if ( image != null ) {
+ this.lblPreview.setImage(null);
+ image.dispose();
+ }
+ this.lblPreview.setVisible(true);
+
+ this.tblComponents.getColumn(1).setText("Documentation");
+
+ if ( this.selectedDatabase == null )
+ return;
+
+ StringBuilder inList = new StringBuilder();
+ ArrayList classList = new ArrayList();
+ if ( this.archimateViews.getSelection() ) {
+ inList.append(inList.length()==0 ? "?" : ", ?");
+ classList.add("ArchimateDiagramModel");
+ }
+ if ( this.canvasViews.getSelection() ) {
+ inList.append(inList.length()==0 ? "?" : ", ?");
+ classList.add("CanvasModel");
+ }
+ if ( this.sketchViews.getSelection() ) {
+ inList.append(inList.length()==0 ? "?" : ", ?");
+ classList.add("SketchModel");
+ }
+
+ if ( inList.length() != 0 ) {
+ setMessage("Getting list of views from database ...");
+
+ if ( logger.isDebugEnabled() ) logger.debug("Getting views");
+
+ this.hideAlreadyInModel.setVisible(true);
+ this.hideOption.setVisible(true);
+ this.hideOption.setText("Hide default views");
+ String addOn = "";
+ if ( this.hideOption.getSelection() )
+ addOn = " AND name <> 'Default View'";
+
+ addOn += " AND version = (SELECT MAX(version) FROM "+this.selectedDatabase.getSchemaPrefix()+"views WHERE id = v.id)";
+ addOn += " ORDER BY name";
+
+ if ( inList.length() != 0 ) {
+ String filterRequest = "";
+ if ( this.filterName.getText().length() != 0 )
+ filterRequest = " AND UPPER(name) like '%"+this.filterName.getText().toUpperCase()+"%'";
+
+ try (DBSelect result = new DBSelect(DBGuiImportComponents.this.importConnection.getDatabaseEntry().getName(), DBGuiImportComponents.this.importConnection.getConnection(), "SELECT id, version, class, name, documentation FROM "+this.selectedDatabase.getSchemaPrefix()+"views v WHERE class IN ("+inList.toString()+")" + filterRequest + addOn, classList)) {
+ while (result.next()) {
+ if ( !this.hideAlreadyInModel.getSelection() || (this.importedModel.getAllViews().get(result.getString("id"))==null)) {
+ StringBuilder tooltipBuilder = new StringBuilder();
+ TableItem item = createTableItem(this.tblComponents, result.getString("id"), result.getString("Class"), result.getString("name"), result.getString("documentation"));
+
+ try ( DBSelect resultProperties = new DBSelect(DBGuiImportComponents.this.importConnection.getDatabaseEntry().getName(), DBGuiImportComponents.this.importConnection.getConnection(), "SELECT name, value FROM "+this.selectedDatabase.getSchemaPrefix()+"properties WHERE parent_id = ? AND parent_version = ?", result.getString("id"), result.getInt("version")) ) {
+ while ( resultProperties.next() ) {
+ if ( tooltipBuilder.length() != 0 )
+ tooltipBuilder.append("\n");
+ tooltipBuilder.append(" - ");
+ tooltipBuilder.append(resultProperties.getString("name"));
+ tooltipBuilder.append(": ");
+ String value = resultProperties.getString("value");
+ if ( value.length() > 22 )
+ tooltipBuilder.append(value.substring(0,19)+"...");
+ else
+ tooltipBuilder.append(value);
+ }
+ }
+ if ( tooltipBuilder.length() != 0 )
+ item.setData("tooltip", tooltipBuilder.toString());
+ }
+ }
+ }
+ }
+
+ closeMessage();
+ }
+
+ if ( this.tblComponents.getItemCount() < 2 ) {
+ this.lblComponents.setText(this.tblComponents.getItemCount()+" component matches your criterias");
+ } else {
+ this.lblComponents.setText(this.tblComponents.getItemCount()+" components match your criterias");
+ }
+
+ this.btnDoAction.setEnabled(false);
+ }
+
+
+
+ private static TableItem createTableItem(Table table, String id, String className, String name, String documentation) {
+ TableItem item = new TableItem(table, SWT.NONE);
+ item.setData("id", id);
+ item.setText(0, " "+name);
+ if ( documentation != null ) item.setText(1, documentation);
+ item.setImage(getImage(className));
+ return item;
+ }
+
+ /**
+ * gets the image associated with an archimate class
+ * @param className the name of tha archimate class
+ * @return the image associated with the archimate class
+ */
+ private static Image getImage(String className) {
+ ImageFactory ImageFactory;
+
+ if ( className.toUpperCase().startsWith("CANVAS") ) {
+ ImageFactory = new ImageFactory(CanvasEditorPlugin.INSTANCE);
+ return ImageFactory.getImage(ICanvasImages.ICON_CANVAS_MODEL);
+ }
+
+ ImageFactory = new ImageFactory(ArchiPlugin.INSTANCE);
+ switch (className.toUpperCase()) {
+ case "FOLDER": return ImageFactory.getImage(IArchiImages.ECLIPSE_IMAGE_FOLDER);
+ case "JUNCTION": return ImageFactory.getImage(IArchiImages.ICON_AND_JUNCTION);
+ case "APPLICATIONCOLLABORATION": return ImageFactory.getImage(IArchiImages.ICON_APPLICATION_COLLABORATION);
+ case "APPLICATIONCOMPONENT": return ImageFactory.getImage(IArchiImages.ICON_APPLICATION_COMPONENT);
+ case "APPLICATIONEVENT": return ImageFactory.getImage(IArchiImages.ICON_APPLICATION_EVENT);
+ case "APPLICATIONFUNCTION": return ImageFactory.getImage(IArchiImages.ICON_APPLICATION_FUNCTION);
+ case "APPLICATIONINTERACTION": return ImageFactory.getImage(IArchiImages.ICON_APPLICATION_INTERACTION);
+ case "APPLICATIONINTERFACE": return ImageFactory.getImage(IArchiImages.ICON_APPLICATION_INTERFACE);
+ case "APPLICATIONPROCESS": return ImageFactory.getImage(IArchiImages.ICON_APPLICATION_PROCESS);
+ case "APPLICATIONSERVICE": return ImageFactory.getImage(IArchiImages.ICON_APPLICATION_SERVICE);
+ case "ARTIFACT": return ImageFactory.getImage(IArchiImages.ICON_ARTIFACT);
+ case "ASSESSMENT": return ImageFactory.getImage(IArchiImages.ICON_ASSESSMENT);
+ case "BUSINESSACTOR": return ImageFactory.getImage(IArchiImages.ICON_BUSINESS_ACTOR);
+ case "BUSINESSCOLLABORATION": return ImageFactory.getImage(IArchiImages.ICON_BUSINESS_COLLABORATION);
+ case "BUSINESSEVENT": return ImageFactory.getImage(IArchiImages.ICON_BUSINESS_EVENT);
+ case "BUSINESSFUNCTION": return ImageFactory.getImage(IArchiImages.ICON_BUSINESS_FUNCTION);
+ case "BUSINESSINTERACTION": return ImageFactory.getImage(IArchiImages.ICON_BUSINESS_INTERACTION);
+ case "BUSINESSINTERFACE": return ImageFactory.getImage(IArchiImages.ICON_BUSINESS_INTERFACE);
+ case "BUSINESSOBJECT": return ImageFactory.getImage(IArchiImages.ICON_BUSINESS_OBJECT);
+ case "BUSINESSPROCESS": return ImageFactory.getImage(IArchiImages.ICON_BUSINESS_PROCESS);
+ case "BUSINESSROLE": return ImageFactory.getImage(IArchiImages.ICON_BUSINESS_ROLE);
+ case "BUSINESSSERVICE": return ImageFactory.getImage(IArchiImages.ICON_BUSINESS_SERVICE);
+ case "CAPABILITY": return ImageFactory.getImage(IArchiImages.ICON_CAPABILITY);
+ case "COMMUNICATIONNETWORK": return ImageFactory.getImage(IArchiImages.ICON_COMMUNICATION_NETWORK);
+ case "CONTRACT": return ImageFactory.getImage(IArchiImages.ICON_CONTRACT);
+ case "CONSTRAINT": return ImageFactory.getImage(IArchiImages.ICON_CONSTRAINT);
+ case "COURSEOFACTION": return ImageFactory.getImage(IArchiImages.ICON_COURSE_OF_ACTION);
+ case "DATAOBJECT": return ImageFactory.getImage(IArchiImages.ICON_DATA_OBJECT);
+ case "DELIVERABLE": return ImageFactory.getImage(IArchiImages.ICON_DELIVERABLE);
+ case "DEVICE": return ImageFactory.getImage(IArchiImages.ICON_DEVICE);
+ case "DISTRIBUTIONNETWORK": return ImageFactory.getImage(IArchiImages.ICON_DISTRIBUTION_NETWORK);
+ case "DRIVER": return ImageFactory.getImage(IArchiImages.ICON_DRIVER);
+ case "EQUIPMENT": return ImageFactory.getImage(IArchiImages.ICON_EQUIPMENT);
+ case "FACILITY": return ImageFactory.getImage(IArchiImages.ICON_FACILITY);
+ case "GAP": return ImageFactory.getImage(IArchiImages.ICON_GAP);
+ case "GOAL": return ImageFactory.getImage(IArchiImages.ICON_GOAL);
+ case "GROUPING": return ImageFactory.getImage(IArchiImages.ICON_GROUPING);
+ case "IMPLEMENTATIONEVENT": return ImageFactory.getImage(IArchiImages.ICON_IMPLEMENTATION_EVENT);
+ case "LOCATION": return ImageFactory.getImage(IArchiImages.ICON_LOCATION);
+ case "MATERIAL": return ImageFactory.getImage(IArchiImages.ICON_MATERIAL);
+ case "MEANING": return ImageFactory.getImage(IArchiImages.ICON_MEANING);
+ case "NODE": return ImageFactory.getImage(IArchiImages.ICON_NODE);
+ case "OUTCOME": return ImageFactory.getImage(IArchiImages.ICON_OUTCOME);
+ case "PATH": return ImageFactory.getImage(IArchiImages.ICON_PATH);
+ case "PLATEAU": return ImageFactory.getImage(IArchiImages.ICON_PLATEAU);
+ case "PRINCIPLE": return ImageFactory.getImage(IArchiImages.ICON_PRINCIPLE);
+ case "PRODUCT": return ImageFactory.getImage(IArchiImages.ICON_PRODUCT);
+ case "REPRESENTATION": return ImageFactory.getImage(IArchiImages.ICON_REPRESENTATION);
+ case "RESOURCE": return ImageFactory.getImage(IArchiImages.ICON_RESOURCE);
+ case "REQUIREMENT": return ImageFactory.getImage(IArchiImages.ICON_REQUIREMENT);
+ case "STAKEHOLDER": return ImageFactory.getImage(IArchiImages.ICON_STAKEHOLDER);
+ case "SYSTEMSOFTWARE": return ImageFactory.getImage(IArchiImages.ICON_SYSTEM_SOFTWARE);
+ case "TECHNOLOGYCOLLABORATION": return ImageFactory.getImage(IArchiImages.ICON_TECHNOLOGY_COLLABORATION);
+ case "TECHNOLOGYEVENT": return ImageFactory.getImage(IArchiImages.ICON_TECHNOLOGY_EVENT);
+ case "TECHNOLOGYFUNCTION": return ImageFactory.getImage(IArchiImages.ICON_TECHNOLOGY_FUNCTION);
+ case "TECHNOLOGYINTERFACE": return ImageFactory.getImage(IArchiImages.ICON_TECHNOLOGY_INTERFACE);
+ case "TECHNOLOGYINTERACTION": return ImageFactory.getImage(IArchiImages.ICON_TECHNOLOGY_INTERACTION);
+ case "TECHNOLOGYPROCESS": return ImageFactory.getImage(IArchiImages.ICON_TECHNOLOGY_PROCESS);
+ case "TECHNOLOGYSERVICE": return ImageFactory.getImage(IArchiImages.ICON_TECHNOLOGY_SERVICE);
+ case "VALUE": return ImageFactory.getImage(IArchiImages.ICON_VALUE);
+ case "WORKPACKAGE": return ImageFactory.getImage(IArchiImages.ICON_WORKPACKAGE);
+ case "ACCESSRELATIONSHIP": return ImageFactory.getImage(IArchiImages.ICON_ACESS_RELATION);
+ case "AGGREGATIONRELATIONSHIP": return ImageFactory.getImage(IArchiImages.ICON_AGGREGATION_RELATION);
+ case "ASSIGNMENTRELATIONSHIP": return ImageFactory.getImage(IArchiImages.ICON_ASSIGNMENT_RELATION);
+ case "ASSOCIATIONRELATIONSHIP": return ImageFactory.getImage(IArchiImages.ICON_ASSOCIATION_RELATION);
+ case "COMPOSITIONRELATIONSHIP": return ImageFactory.getImage(IArchiImages.ICON_COMPOSITION_RELATION);
+ case "FLOWRELATIONSHIP": return ImageFactory.getImage(IArchiImages.ICON_FLOW_RELATION);
+ case "INFLUENCERELATIONSHIP": return ImageFactory.getImage(IArchiImages.ICON_INFLUENCE_RELATION);
+ case "REALIZATIONRELATIONSHIP": return ImageFactory.getImage(IArchiImages.ICON_REALIZATION_RELATION);
+ case "SERVINGRELATIONSHIP": return ImageFactory.getImage(IArchiImages.ICON_SERVING_RELATION);
+ case "SPECIALIZATIONRELATIONSHIP": return ImageFactory.getImage(IArchiImages.ICON_SPECIALIZATION_RELATION);
+ case "TRIGGERINGRELATIONSHIP": return ImageFactory.getImage(IArchiImages.ICON_TRIGGERING_RELATION);
+ case "DIAGRAMMODELGROUP": return ImageFactory.getImage(IArchiImages.ICON_GROUP);
+ case "DIAGRAMMODELNOTE": return ImageFactory.getImage(IArchiImages.ICON_NOTE);
+ case "ARCHIMATEDIAGRAMMODEL": return ImageFactory.getImage(IArchiImages.ICON_DIAGRAM);
+ case "SKETCHMODEL": return ImageFactory.getImage(IArchiImages.ICON_SKETCH);
+ case "SKETCHMODELSTICKY": return ImageFactory.getImage(IArchiImages.ICON_STICKY);
+ case "SKETCHMODELACTOR": return ImageFactory.getImage(IArchiImages.ICON_ACTOR);
+ case "MODEL": return ImageFactory.getImage(IArchiImages.ICON_APP);
+ default:
+ throw new IllegalArgumentException("The class '" + className + "' is not a valid class"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+
+ void doImport() throws Exception {
+ // We rename the "close" button to "cancel"
+ this.btnClose.setText("Cancel");
+
+ if ( logger.isDebugEnabled() )
+ logger.debug("Importing "+this.tblComponents.getSelectionCount()+" component" + ((this.tblComponents.getSelectionCount()>1) ? "s" : "") + " in " + DBImportMode.getLabel(getOptionValue()) + ".");
+
+ CompoundCommand undoRedoCommands = new CompoundCommand();
+ int done = 0;
+ try {
+ for ( TableItem tableItem: this.tblComponents.getSelection() ) {
+ String id = (String)tableItem.getData("id");
+ String name = tableItem.getText(0).trim();
+
+ if ( this.radioOptionModel.getSelection() ) {
+ setMessage("("+(++done)+"/"+this.tblComponents.getSelectionCount()+") Importing model \""+name+"\".");
+
+ // import folders
+ setMessage("("+done+"/"+this.tblComponents.getSelectionCount()+") Importing folders from model \""+name+"\".");
+ Map foldersConversionMap = new HashMap();
+
+ Map translatedFolders = new HashMap();
+
+ try ( DBSelect result = new DBSelect(DBGuiImportComponents.this.importConnection.getDatabaseEntry().getName(), DBGuiImportComponents.this.importConnection.getConnection(), "SELECT fim.folder_id, fim.folder_version, fim.parent_folder_id, f.type, f.root_type, f.name FROM "+this.selectedDatabase.getSchemaPrefix()+"folders_in_model fim JOIN "+this.selectedDatabase.getSchemaPrefix()+"folders f ON fim.folder_id = f.id and fim.folder_version = f.version WHERE fim.model_id = ? AND fim.model_version = (SELECT MAX(model_version) FROM "+this.selectedDatabase.getSchemaPrefix()+"folders_in_model WHERE model_id = ?) ORDER BY fim.pos", id, id) ) {
+ while ( result.next() ) {
+ // we check if we already know how to convert this folder
+ String convertedFolderId = translatedFolders.get(result.getString("folder_id"));
+
+ if ( convertedFolderId == null ) {
+ // if the folder is not known, we calculate its path in order to check if the same path already exist in the current model
+ String folderPath;
+ String folderId = result.getString("folder_id");
+ int folderType = result.getInt("type");
+ boolean isRootFolder = (folderType != 0);
+
+ if ( isRootFolder )
+ // for root folders, the path is directl the name of the folder
+ folderPath = result.getString("name");
+ else {
+ // for other folders, we recursively get the name of the parent folders until a root folder is found
+ StringBuilder folderPathBuilder = new StringBuilder();
+ while ( !isRootFolder ) {
+ try (DBSelect subResult = new DBSelect(DBGuiImportComponents.this.importConnection.getDatabaseEntry().getName(), DBGuiImportComponents.this.importConnection.getConnection(), "SELECT fim.folder_id, fim.folder_version, fim.parent_folder_id, f.type, f.root_type, f.name FROM "+this.selectedDatabase.getSchemaPrefix()+"folders_in_model fim JOIN "+this.selectedDatabase.getSchemaPrefix()+"folders f ON fim.folder_id = f.id and fim.folder_version = f.version WHERE fim.model_id = ? AND fim.model_version = (SELECT MAX(model_version) FROM "+this.selectedDatabase.getSchemaPrefix()+"folders_in_model WHERE model_id = ?) AND fim.folder_id = ?", id, id, folderId) ) {
+ if ( folderPathBuilder.length() == 0 )
+ folderPathBuilder.append(subResult.getString("name"));
+ else {
+ folderPathBuilder.insert(0, "\0"); // we ensure that the separator cannot be part of a folder name
+ folderPathBuilder.insert(0, subResult.getString("name"));
+ }
+ folderId = subResult.getString("parent_folder_id");
+ folderType = subResult.getInt("type");
+ isRootFolder = (folderType != 0);
+ }
+ }
+ folderPath = folderPathBuilder.toString();
+ }
+
+ // we search for the corresponding path in the current model
+ IFolder parentFolder = null;
+ for ( String subFolderName: folderPath.split("[\0]") ) {
+ if ( parentFolder == null ) {
+ // root folders are get by their type
+ parentFolder = this.importedModel.getFolder(FolderType.get(folderType));
+ } else {
+ // other folders are get by their name
+ IFolder folder = null;
+ for ( IFolder subFolder: parentFolder.getFolders() ) {
+ if ( (folder == null) && subFolder.getName().equals(subFolderName) ) {
+ folder = subFolder;
+ }
+ }
+
+ if ( folder == null ) {
+ // if we're here, this means that we did not find the folder path in the model
+ // so we import the folder
+ IDBImportCommand command = new DBImportFolderFromIdCommand(this.importConnection, this.importedModel, parentFolder, result.getString("folder_id"), result.getInt("folder_version"), DBImportMode.get(getOptionValue()));
+ if ( command.getException() != null )
+ throw command.getException();
+ command.execute();
+ if ( command.getException() != null )
+ throw command.getException();
+ undoRedoCommands.add((Command)command);
+
+ parentFolder = (IFolder) command.getImported();
+ } else
+ parentFolder = folder;
+ }
+ }
+
+ if ( parentFolder == null )
+ throw new Exception("Failed to get folder for path "+folderPath.replaceAll("[\0]", "/"));
+ convertedFolderId = parentFolder.getId();
+ if ( logger.isTraceEnabled() ) logger.trace("Creating translation for path "+folderPath.replaceAll("[\0]", "/")+" to "+DBMetadata.getDBMetadata(parentFolder).getDebugName());
+ //TODO: get folder properties from the database !!!
+ translatedFolders.put(result.getString("folder_id"), convertedFolderId);
+ }
+ }
+ }
+
+ // import elements
+ setMessage("("+done+"/"+this.tblComponents.getSelectionCount()+") Importing elements from model \""+name+"\".");
+ try ( DBSelect result = new DBSelect(DBGuiImportComponents.this.importConnection.getDatabaseEntry().getName(), DBGuiImportComponents.this.importConnection.getConnection(), "SELECT element_id, element_version, parent_folder_id FROM "+this.selectedDatabase.getSchemaPrefix()+"elements_in_model WHERE model_id = ? AND model_version = (SELECT MAX(model_version) FROM "+this.selectedDatabase.getSchemaPrefix()+"elements_in_model WHERE model_id = ?) ORDER BY pos", id, id) ) {
+ while ( result.next() ) {
+ // we check if the parent folder needs to be translated
+ IFolder parentFolder = foldersConversionMap.get(result.getString("parent_folder_id"));
+ if ( parentFolder != null )
+ logger.debug(" Translating parent folder to \""+parentFolder.getName()+"\"("+parentFolder.getId()+")");
+ else
+ parentFolder = this.importedModel.getAllFolders().get(result.getString("parent_folder_id"));
+ IDBImportCommand command = new DBImportElementFromIdCommand(this.importConnection, this.importedModel, null, parentFolder, result.getString("element_id"), result.getInt("element_version"), DBImportMode.get(getOptionValue()), false);
+ if ( command.getException() != null )
+ throw command.getException();
+ command.execute();
+ if ( command.getException() != null )
+ throw command.getException();
+ undoRedoCommands.add((Command)command);
+ }
+ }
+
+ // import relationships
+ setMessage("("+done+"/"+this.tblComponents.getSelectionCount()+") Importing relationships from model \""+name+"\".");
+ try ( DBSelect result = new DBSelect(DBGuiImportComponents.this.importConnection.getDatabaseEntry().getName(), DBGuiImportComponents.this.importConnection.getConnection(), "SELECT relationship_id, relationship_version, parent_folder_id FROM "+this.selectedDatabase.getSchemaPrefix()+"relationships_in_model WHERE model_id = ? AND model_version = (SELECT MAX(model_version) FROM "+this.selectedDatabase.getSchemaPrefix()+"relationships_in_model WHERE model_id = ?) ORDER BY pos", id, id) ) {
+ while ( result.next() ) {
+ // we check if the parent folder needs to be translated
+ IFolder parentFolder = foldersConversionMap.get(result.getString("parent_folder_id"));
+ if ( parentFolder != null )
+ logger.debug(" Translating parent folder to \""+parentFolder.getName()+"\"("+parentFolder.getId()+")");
+ else
+ parentFolder = this.importedModel.getAllFolders().get(result.getString("parent_folder_id"));
+ IDBImportCommand command = new DBImportRelationshipFromIdCommand(this.importConnection, this.importedModel, null, parentFolder, result.getString("relationship_id"), result.getInt("relationship_version"), DBImportMode.get(getOptionValue()));
+ if ( command.getException() != null )
+ throw command.getException();
+ command.execute();
+ if ( command.getException() != null )
+ throw command.getException();
+ undoRedoCommands.add((Command)command);
+ }
+ }
+
+ setMessage("("+done+"/"+this.tblComponents.getSelectionCount()+") Resolving relationships from model \""+name+"\".");
+ if ( (this.importedModel.getAllSourceRelationshipsToResolve().size() != 0) || (this.importedModel.getAllTargetRelationshipsToResolve().size() != 0) ) {
+ DBResolveRelationshipsCommand resolveRelationshipsCommand = new DBResolveRelationshipsCommand(this.importedModel);
+ resolveRelationshipsCommand.execute();
+ if ( resolveRelationshipsCommand.getException() != null )
+ throw resolveRelationshipsCommand.getException();
+ undoRedoCommands.add(resolveRelationshipsCommand);
+ }
+
+ // import views
+ setMessage("("+done+"/"+this.tblComponents.getSelectionCount()+") Importing views from model \""+name+"\".");
+ try ( DBSelect result = new DBSelect(DBGuiImportComponents.this.importConnection.getDatabaseEntry().getName(), DBGuiImportComponents.this.importConnection.getConnection(), "SELECT view_id, view_version, parent_folder_id FROM "+this.selectedDatabase.getSchemaPrefix()+"views_in_model WHERE model_id = ? AND model_version = (SELECT MAX(model_version) FROM "+this.selectedDatabase.getSchemaPrefix()+"views_in_model WHERE model_id = ?) ORDER BY pos", id, id) ) {
+ while ( result.next() ) {
+ // we check if the parent folder needs to be translated
+ IFolder parentFolder = foldersConversionMap.get(result.getString("parent_folder_id"));
+ if ( parentFolder != null )
+ logger.debug(" Translating parent folder to \""+parentFolder.getName()+"\"("+parentFolder.getId()+")");
+ else
+ parentFolder = this.importedModel.getAllFolders().get(result.getString("parent_folder_id"));
+ IDBImportCommand command = new DBImportViewFromIdCommand(this.importConnection, this.importedModel, parentFolder, result.getString("view_id"), result.getInt("view_version"), DBImportMode.get(getOptionValue()), true);
+ if ( command.getException() != null )
+ throw command.getException();
+ command.execute();
+ if ( command.getException() != null )
+ throw command.getException();
+ undoRedoCommands.add((Command)command);
+ }
+ }
+
+ setMessage("("+done+"/"+this.tblComponents.getSelectionCount()+") Resolving connections from model \""+name+"\".");
+ if ( (this.importedModel.getAllSourceConnectionsToResolve().size() != 0) || (this.importedModel.getAllTargetConnectionsToResolve().size() != 0) ) {
+ DBResolveConnectionsCommand resolveConnectionsCommand = new DBResolveConnectionsCommand(this.importedModel);
+ resolveConnectionsCommand.execute();
+ if ( resolveConnectionsCommand.getException() != null )
+ throw resolveConnectionsCommand.getException();
+ undoRedoCommands.add(resolveConnectionsCommand);
+ }
+ } else if ( this.radioOptionElement.getSelection() ) {
+ setMessage("("+(++done)+"/"+this.tblComponents.getSelectionCount()+") Importing element \""+name+"\".");
+ IDBImportCommand command = new DBImportElementFromIdCommand(this.importConnection, this.importedModel, this.selectedView, this.selectedFolder, id, 0, DBImportMode.get(getOptionValue()), true);
+ if ( command.getException() != null )
+ throw command.getException();
+ command.execute();
+ if ( command.getException() != null )
+ throw command.getException();
+ undoRedoCommands.add((Command)command);
+ }
+
+ else if ( this.radioOptionView.getSelection() ) {
+ setMessage("("+(++done)+"/"+this.tblComponents.getSelectionCount()+") Importing view \""+name+"\".");
+ IDBImportCommand command = new DBImportViewFromIdCommand(this.importConnection, this.importedModel, this.selectedFolder, id, 0, DBImportMode.get(getOptionValue()), true);
+ if ( command.getException() != null )
+ throw command.getException();
+ command.execute();
+ if ( command.getException() != null )
+ throw command.getException();
+ undoRedoCommands.add((Command)command);
+ }
+ }
+
+ DBResolveRelationshipsCommand resolveRelationshipsCommand = new DBResolveRelationshipsCommand(this.importedModel);
+ resolveRelationshipsCommand.execute();
+ if ( resolveRelationshipsCommand.getException() != null )
+ throw resolveRelationshipsCommand.getException();
+ undoRedoCommands.add(resolveRelationshipsCommand);
+
+ DBResolveConnectionsCommand resolveConnectionsCommand = new DBResolveConnectionsCommand(this.importedModel);
+ resolveConnectionsCommand.execute();
+ if ( resolveConnectionsCommand.getException() != null )
+ throw resolveConnectionsCommand.getException();
+ undoRedoCommands.add(resolveConnectionsCommand);
+
+ ((CommandStack)this.importedModel.getAdapter(CommandStack.class)).execute(undoRedoCommands);
+
+ // we select the imported components in the model tree
+ List imported = new ArrayList();
+
+ Iterator iterator = undoRedoCommands.getCommands().iterator();
+ while ( iterator.hasNext() ) {
+ IDBCommand command = iterator.next();
+
+ if ( command instanceof IDBImportCommand && ((IDBImportCommand)command).getImported() != null )
+ imported.add(((IDBImportCommand)command).getImported());
+ }
+
+ if ( !imported.isEmpty() ) {
+ // We select the element in the model tree
+ ITreeModelView treeView = (ITreeModelView)ViewManager.showViewPart(ITreeModelView.ID, true);
+ if(treeView != null)
+ treeView.getViewer().setSelection(new StructuredSelection(imported));
+ }
+
+ // we redraw the tblComponents table to unselect the items (and hide the newly imported components if the option is selected)
+ this.hideAlreadyInModel.notifyListeners(SWT.Selection, new Event());
+ } catch(RuntimeException e) {
+ popup(Level.ERROR, "Couldn't import component.", e);
+ } finally {
+ // we do not catch the exception if any, but we need to close the popup
+ closeMessage();
+ // We rename the "cancel" button to "close"
+ this.btnClose.setText("Close");
+ }
+ }
+
+ private class ComponentLabel {
+ Label label;
+
+ ComponentLabel(Composite parent, String toolTip) {
+ this.label = new Label(parent, SWT.NONE);
+ this.label.setSize(100, 100);
+ this.label.setToolTipText(toolTip);
+ this.label.setImage(getImage(getElementClassname()));
+ this.label.addPaintListener(this.redraw);
+ this.label.addListener(SWT.MouseUp, DBGuiImportComponents.this.getElementsListener);
+ setSelected(false);
+ }
+
+ private PaintListener redraw = new PaintListener() {
+ @Override
+ public void paintControl(PaintEvent event)
+ {
+ if ( ComponentLabel.this.isSelected() )
+ ComponentLabel.this.label.setBackground(GREY_COLOR);
+ //event.gc.drawRoundRectangle(0, 0, 16, 16, 2, 2);
+ else
+ ComponentLabel.this.label.setBackground(null);
+ }
+ };
+
+ public String getElementClassname() {
+ return this.label.getToolTipText().replaceAll(" ", "");
+ }
+
+ public void setSelected(boolean selected) {
+ this.label.setData("isSelected", selected);
+ }
+
+ public boolean isSelected() {
+ Boolean selected = (Boolean)this.label.getData("isSelected");
+ if ( selected == null )
+ return false;
+ return selected.booleanValue();
+ }
+
+ public void redraw() {
+ this.label.redraw();
+ }
+ }
+
+ Listener getElementsListener = new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ Label label = (Label)event.widget;
+ label.setData("isSelected", !(Boolean)label.getData("isSelected"));
+ label.redraw();
+ try {
+ getElements();
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "An exception has been raised.", err);
+ }
+ }
+ };
+
+ /*
+ private Listener getFoldersListener = new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ try {
+ getFolders();
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "An exception has been raised.", err);
+ }
+ }
+ };
+ */
+
+ final private Listener getViewsListener = new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ try {
+ getViews();
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "An exception has been raised.", err);
+ }
+ }
+ };
+
+ final private Listener tooltipListener = new Listener() {
+ Shell tip = null;
+ StyledText label = null;
+
+ @Override
+ public void handleEvent (Event event) {
+ switch (event.type) {
+ case SWT.Dispose:
+ case SWT.KeyDown:
+ case SWT.MouseMove:
+ if (this.tip == null) break;
+ this.tip.dispose ();
+ this.tip = null;
+ this.label = null;
+ break;
+
+ case SWT.MouseHover:
+ TableItem item = DBGuiImportComponents.this.tblComponents.getItem (new Point (event.x, event.y));
+
+ if (item != null) {
+ Table table = item.getParent();
+
+ if ( (this.tip != null) && !this.tip.isDisposed () )
+ this.tip.dispose ();
+
+ if ( item.getData("tooltip") != null ) {
+ this.tip = new Shell (table.getShell(), SWT.ON_TOP | SWT.NO_FOCUS | SWT.TOOL);
+ FillLayout layout = new FillLayout ();
+ layout.marginWidth = 2;
+ this.tip.setLayout (layout);
+ this.label = new StyledText (this.tip, SWT.NONE);
+ this.label.setEditable(false);
+ this.label.setText("Properties:\n"+(String)item.getData("tooltip"));
+ StyleRange style = new StyleRange( 0, 11, null, null, SWT.BOLD);
+ style.underline = true;
+ this.label.setStyleRange(style);
+ Point size = this.tip.computeSize (SWT.DEFAULT, SWT.DEFAULT);
+ Point pt = table.toDisplay (event.x, event.y);
+ this.tip.setBounds (pt.x, pt.y, size.x, size.y);
+ this.tip.setVisible (true);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ };
+
+ @Override
+ public void close() {
+ if ( this.lblPreview.getImage() != null )
+ this.lblPreview.getImage().dispose();
+
+ super.close();
+ }
+
+ private Listener sortListener = new Listener() {
+ @Override
+ public void handleEvent(Event e) {
+ TableColumn sortedColumn = (TableColumn) e.widget;
+ Table table = sortedColumn.getParent();
+ table.setSortColumn(sortedColumn);
+ Integer sortDirection = (Integer)sortedColumn.getData("sortDirection");
+ if ( sortDirection == null || sortDirection == SWT.DOWN )
+ sortDirection=SWT.UP;
+ else
+ sortDirection=SWT.DOWN;
+ sortedColumn.setData("sortDirection",sortDirection);
+ table.setSortDirection(sortDirection);
+
+ int columnIndex = 0;
+ for ( int i = 0; i < table.getColumns().length; ++i ) {
+ if ( table.getColumn(i).equals(sortedColumn) ) {
+ columnIndex = i;
+ break;
+ }
+ }
+
+ TableItem[] items = table.getItems();
+ Collator collator = Collator.getInstance(Locale.getDefault());
+
+ for (int i = 1; i < items.length; i++) {
+ String value1 = items[i].getText(columnIndex);
+ for (int j = 0; j < i; j++) {
+ String value2 = items[j].getText(columnIndex);
+ if ( (sortDirection == SWT.UP && collator.compare(value1, value2) < 0) || (sortDirection == SWT.DOWN && collator.compare(value1, value2) > 0)) {
+ // we save the old values
+ String name = items[i].getText(0);
+ String documentation = items[i].getText(1);
+ String tooltip = (String) items[i].getData("tooltip");
+ Image image = items[i].getImage();
+
+ // we delete the old row
+ items[i].dispose();
+
+ // we create the new one
+ TableItem item = new TableItem(table, SWT.NONE, j);
+
+ // and restore the saved values
+ item.setText(0, name);
+ if ( documentation != null ) item.setText(1, documentation);
+ item.setData("tooltip", tooltip);
+ item.setImage(image);
+
+ // at last, we refresh the items list
+ items = table.getItems();
+ break;
+ }
+ }
+ }
+ }
+ };
+}
diff --git a/sources/src/org/archicontribs/database/GUI/DBGuiImportImage.java b/sources/src/org/archicontribs/database/GUI/DBGuiImportImage.java
new file mode 100644
index 00000000..5fe8eca0
--- /dev/null
+++ b/sources/src/org/archicontribs/database/GUI/DBGuiImportImage.java
@@ -0,0 +1,246 @@
+/**
+ * This program and the accompanying materials
+ * are made available under the terms of the License
+ * which accompanies this distribution in the file LICENSE.txt
+ */
+package org.archicontribs.database.GUI;
+
+import org.apache.log4j.Level;
+import org.archicontribs.database.DBLogger;
+import org.archicontribs.database.DBPlugin;
+import org.archicontribs.database.connection.DBDatabaseImportConnection;
+import org.archicontribs.database.model.DBArchimateModel;
+import org.eclipse.nebula.widgets.gallery.DefaultGalleryItemRenderer;
+import org.eclipse.nebula.widgets.gallery.Gallery;
+import org.eclipse.nebula.widgets.gallery.GalleryItem;
+import org.eclipse.nebula.widgets.gallery.NoGroupRenderer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Scale;
+
+import com.archimatetool.editor.utils.PlatformUtils;
+
+/**
+ * This class holds the methods requires to import an image from the database
+ *
+ * @author Herve Jouin
+ */
+public class DBGuiImportImage extends DBGui {
+ @SuppressWarnings("hiding")
+ private static final DBLogger logger = new DBLogger(DBGuiImportImage.class);
+
+ private int DEFAULT_GALLERY_ITEM_SIZE = 128;
+ private int MIN_GALLERY_ITEM_SIZE = 64;
+ private int MAX_GALLERY_ITEM_SIZE = 256;
+
+ String imagePath = null;
+ Image image = null;
+
+ DBDatabaseImportConnection importConnection;
+
+ private Group grpImages;
+ Gallery gallery;
+ GalleryItem rootGalleryItem;
+ Scale scale;
+
+ public DBGuiImportImage(DBArchimateModel model, String title) throws Exception {
+ // We call the DBGui constructor that will create the underlying form and expose the compoRight, compoRightUp and compoRightBottom composites
+ super(title);
+
+ if ( logger.isDebugEnabled() ) logger.debug("Setting up GUI for importing an image \""+model.getName()+"\" (plugin version "+DBPlugin.pluginVersion.toString()+").");
+
+ createGrpImages();
+
+ this.compoRightBottom.setVisible(true);
+ this.compoRightBottom.layout();
+
+ createAction(ACTION.One, "1 - select image");
+
+ // we show an arrow in front of the first action
+ setActiveAction(ACTION.One);
+
+ // if the user select the "Import" button --> import the image, set the importedImagePath variable and close the window
+ setBtnAction("Import image", new SelectionListener() {
+ @Override public void widgetSelected(SelectionEvent e) {
+ GalleryItem[] selectedItems = DBGuiImportImage.this.gallery.getSelection();
+ if ( selectedItems != null && selectedItems.length != 0 ) {
+ Image selectedImage = selectedItems[0].getImage();
+ if ( selectedImage != null ) {
+ DBGuiImportImage.this.imagePath = (String)selectedItems[0].getData("imagePath");
+ DBGuiImportImage.this.image = new Image(display, selectedImage, SWT.IMAGE_COPY);
+ close();
+ }
+ }
+ }
+ @Override public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); }
+ });
+
+ // We rename the "close" button to "Cancel"
+ this.btnClose.setText("Cancel");
+
+ // We activate the Eclipse Help framework
+ setHelpHref("importImage.html");
+ }
+
+ @Override
+ public void run() {
+ super.run();
+ try {
+ getDatabases(false);
+ } catch (Exception err) {
+ popup(Level.ERROR, "Failed to get the databases.", err);
+ return;
+ }
+ }
+
+ /**
+ * Creates a group displaying the images from the database
+ */
+ private void createGrpImages() {
+ this.grpImages = new Group(this.compoRightBottom, SWT.NONE);
+ this.grpImages.setBackground(GROUP_BACKGROUND_COLOR);
+ this.grpImages.setText("Images in the database: ");
+ this.grpImages.setFont(GROUP_TITLE_FONT);
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ fd.bottom = new FormAttachment(100);
+ this.grpImages.setLayoutData(fd);
+ this.grpImages.setLayout(new GridLayout(2, false));
+
+ Composite galleryComposite = new Composite(this.grpImages, SWT.FILL);
+ galleryComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
+ GridLayout layout = new GridLayout();
+ layout.marginWidth = 0;
+ layout.marginHeight = 0;
+ galleryComposite.setLayout(layout);
+
+ this.gallery = new Gallery(galleryComposite, SWT.V_SCROLL | SWT.BORDER | SWT.FILL);
+ this.gallery.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ // Renderers
+ final NoGroupRenderer groupRenderer = new NoGroupRenderer();
+ groupRenderer.setItemSize(this.DEFAULT_GALLERY_ITEM_SIZE, this.DEFAULT_GALLERY_ITEM_SIZE);
+ groupRenderer.setAutoMargin(true);
+ groupRenderer.setMinMargin(10);
+ this.gallery.setGroupRenderer(groupRenderer);
+
+ final DefaultGalleryItemRenderer itemRenderer = new DefaultGalleryItemRenderer();
+ itemRenderer.setDropShadows(true);
+ itemRenderer.setDropShadowsSize(7);
+ itemRenderer.setShowRoundedSelectionCorners(false);
+ this.gallery.setItemRenderer(itemRenderer);
+
+ // Root Group
+ this.rootGalleryItem = new GalleryItem(this.gallery, SWT.NONE);
+
+ // Slider
+ this.scale = new Scale(galleryComposite, SWT.HORIZONTAL);
+ GridData gd = new GridData(SWT.END, SWT.NONE, false, false);
+ gd.widthHint = 120;
+ if(PlatformUtils.isMac()) { // Mac clips height of slider
+ gd.heightHint = 18;
+ }
+ this.scale.setLayoutData(gd);
+ this.scale.setMinimum(this.MIN_GALLERY_ITEM_SIZE);
+ this.scale.setMaximum(this.MAX_GALLERY_ITEM_SIZE);
+ this.scale.setIncrement(8);
+ this.scale.setPageIncrement(32);
+ this.scale.setSelection(this.DEFAULT_GALLERY_ITEM_SIZE);
+ this.scale.addSelectionListener(new SelectionAdapter() {
+ @Override public void widgetSelected(SelectionEvent e) {
+ int inc = DBGuiImportImage.this.scale.getSelection();
+ itemRenderer.setDropShadows(inc >= 96);
+ groupRenderer.setItemSize(inc, inc);
+ }
+ });
+
+ // Gallery selections
+ this.gallery.addSelectionListener(new SelectionAdapter() {
+ @Override public void widgetSelected(SelectionEvent e) {
+ DBGuiImportImage.this.btnDoAction.setEnabled(e.item instanceof GalleryItem);
+ }
+ });
+
+ // Double-clicks
+ this.gallery.addListener(SWT.MouseDoubleClick, new Listener() {
+ @Override public void handleEvent(Event event) {
+ Image selectedImage = DBGuiImportImage.this.gallery.getItem(new Point(event.x, event.y)).getImage();
+ if ( selectedImage != null ) {
+ DBGuiImportImage.this.imagePath = (String)DBGuiImportImage.this.gallery.getItem(new Point(event.x, event.y)).getData("imagePath");
+ DBGuiImportImage.this.image = new Image(display, selectedImage, SWT.IMAGE_COPY);
+ close();
+ }
+ }
+ });
+
+ // Dispose of the images here not in the main dispose() method because if the help system is showing then
+ // the TrayDialog is resized and this control is asked to relayout.
+ this.gallery.addDisposeListener(new DisposeListener() {
+ @Override
+ public void widgetDisposed(DisposeEvent e) {
+ notConnectedToDatabase(); // we dispose the images
+ }
+ });
+ }
+
+ /**
+ * This method is called each time a database is selected and a connection has been established to it.
+ */
+ @Override
+ protected void connectedToDatabase(boolean forceCheckDatabase) {
+ notConnectedToDatabase(); // we dispose the images
+
+ this.importConnection = new DBDatabaseImportConnection(getDatabaseConnection());
+
+ try {
+ for ( String path: this.importConnection.getImageListFromDatabase() ) {
+ GalleryItem item = new GalleryItem(this.rootGalleryItem, SWT.NONE);
+ item.setImage(this.importConnection.getImageFromDatabase(path));
+ item.setData("imagePath", path);
+ }
+ } catch (Exception err) {
+ popup(Level.ERROR, "Failed to get images from the database", err);
+ }
+ }
+
+ /**
+ *
+ */
+
+ /**
+ * This method is called each time a connection to the database fails.
+ */
+ @Override
+ protected void notConnectedToDatabase() {
+ if( this.rootGalleryItem != null && !this.rootGalleryItem.isDisposed()) {
+ while(this.rootGalleryItem.getItemCount() > 0) {
+ GalleryItem item = this.rootGalleryItem.getItem(0);
+ this.rootGalleryItem.remove(item);
+ }
+ }
+ }
+
+ public String getImagePath() {
+ return this.imagePath;
+ }
+
+ public Image getImage() {
+ return this.image;
+ }
+}
diff --git a/sources/src/org/archicontribs/database/GUI/DBGuiImportModel.java b/sources/src/org/archicontribs/database/GUI/DBGuiImportModel.java
new file mode 100644
index 00000000..dcbab212
--- /dev/null
+++ b/sources/src/org/archicontribs/database/GUI/DBGuiImportModel.java
@@ -0,0 +1,1029 @@
+/**
+ * This program and the accompanying materials
+ * are made available under the terms of the License
+ * which accompanies this distribution in the file LICENSE.txt
+ */
+
+package org.archicontribs.database.GUI;
+
+import java.io.IOException;
+import java.sql.Date;
+import java.sql.Timestamp;
+import java.text.Collator;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.log4j.Level;
+import org.archicontribs.database.DBLogger;
+import org.archicontribs.database.DBPlugin;
+import org.archicontribs.database.connection.DBDatabaseImportConnection;
+import org.archicontribs.database.model.DBArchimateFactory;
+import org.archicontribs.database.model.DBArchimateModel;
+import org.eclipse.gef.commands.CommandStack;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.layout.FormLayout;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+
+import com.archimatetool.editor.model.IEditorModelManager;
+import com.archimatetool.editor.ui.services.EditorManager;
+import com.archimatetool.editor.ui.services.ViewManager;
+import com.archimatetool.editor.views.tree.ITreeModelView;
+import com.archimatetool.model.FolderType;
+import com.archimatetool.model.IArchimateModel;
+import com.archimatetool.model.IDiagramModel;
+import com.archimatetool.model.IFolder;
+
+import lombok.Getter;
+
+/**
+ * This class manages the GUI that allows to import a model from a database
+ *
+ * @author Herve Jouin
+ */
+public class DBGuiImportModel extends DBGui {
+ @SuppressWarnings("hiding")
+ protected static final DBLogger logger = new DBLogger(DBGuiImportModel.class);
+
+ private DBArchimateModel modelToImport;
+
+ DBDatabaseImportConnection importConnection;
+
+ @Getter Table tblModels;
+ @Getter Table tblModelVersions;
+ @Getter Text txtFilterModels;
+
+ private Group grpModels;
+ private Group grpModelVersions;
+ private Group grpComponents;
+
+ private Label lblModelName;
+ Text txtModelName;
+ private Label lblPurpose;
+ Text txtPurpose;
+ private Label lblReleaseNote;
+ Text txtReleaseNote;
+
+ private Text txtTotalProfiles;
+ private Text txtTotalElements;
+ private Text txtTotalRelationships;
+ private Text txtTotalFolders;
+ private Text txtTotalViews;
+ private Text txtTotalViewObjects;
+ private Text txtTotalViewConnections;
+ private Text txtTotalImages;
+
+ private Text txtImportedProfiles;
+ private Text txtImportedElements;
+ private Text txtImportedRelationships;
+ private Text txtImportedFolders;
+ private Text txtImportedViews;
+ private Text txtImportedViewObjects;
+ private Text txtImportedViewConnections;
+ private Text txtImportedImages;
+
+ /**
+ * Creates the GUI to import a model
+ * @param title Title of the window
+ * @throws Exception
+ */
+ public DBGuiImportModel(String title) throws Exception {
+ this(title, null);
+ }
+
+ /**
+ * Creates the GUI to import a model
+ * @param title Title of the window
+ * @param defaultDatabaseName Name of the default database name to connect to
+ * @throws Exception
+ */
+ public DBGuiImportModel(String title, String defaultDatabaseName) throws Exception {
+ super(title);
+
+ if ( logger.isDebugEnabled() ) logger.debug("Setting up GUI for importing a model (plugin version "+DBPlugin.pluginVersion.toString()+").");
+
+ createAction(ACTION.One, "1 - Choose model");
+ createAction(ACTION.Two, "2 - Import model");
+ createAction(ACTION.Three, "3 - Status");
+ setActiveAction(ACTION.One);
+
+ // We activate the btnDoAction button: if the user select the "Import" button --> call the doImport() method
+ setBtnAction("Import", new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ String modelName = DBGuiImportModel.this.tblModels.getSelection()[0].getText();
+ String modelId = (String)DBGuiImportModel.this.tblModels.getSelection()[0].getData("id");
+ boolean checkName = true;
+
+ // we check that the model is not already in memory
+ List allModels = IEditorModelManager.INSTANCE.getModels();
+ for ( IArchimateModel existingModel: allModels ) {
+ if ( DBPlugin.areEqual(modelId, existingModel.getId()) ) {
+ popup(Level.ERROR, "A model with ID \""+modelId+"\" already exists. Cannot import it again ...");
+ return;
+ }
+ if ( checkName && DBPlugin.areEqual(modelName, existingModel.getName()) ) {
+ if ( !question("A model with name \""+modelName+"\" already exists.\n\nIt is possible to have two models with the same name as long as they've got distinct IDs but it is not recommended.\n\nDo you wish to force the import ?") ) {
+ return;
+ }
+ checkName = false; // if a third model has got the same name, we do not ask again.
+ }
+ }
+
+ setActiveAction(STATUS.Ok);
+ DBGuiImportModel.this.btnDoAction.setEnabled(false);
+ doImport();
+ }
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); }
+ });
+
+ // We rename the "close" button to "cancel"
+ this.btnClose.setText("Cancel");
+
+ // We activate the Eclipse Help framework
+ setHelpHref("importModel.html");
+
+ createGrpModel();
+ createGrpComponents();
+
+ // We connect to the database and call the databaseSelected() method
+ this.includeNeo4j = false;
+ getDatabases(false, null, defaultDatabaseName);
+ }
+
+ @Override
+ protected void databaseSelectedCleanup() {
+ if ( this.tblModels != null ) {
+ this.tblModels.removeAll();
+ }
+ if ( this.tblModelVersions != null ) {
+ this.tblModelVersions.removeAll();
+ }
+ }
+
+ /**
+ * Called when a database is selected in the comboDatabases and that the connection to this database succeeded.
+ */
+ @Override
+ protected void connectedToDatabase(boolean ignore) {
+ this.importConnection = new DBDatabaseImportConnection(getDatabaseConnection());
+
+ this.compoRightBottom.setVisible(true);
+ this.compoRightBottom.layout();
+
+ this.tblModels.removeAll();
+
+ this.txtFilterModels.notifyListeners(SWT.Modify, new Event()); // refreshes the list of models in the database
+
+ this.tblModels.layout();
+ this.tblModels.setVisible(true);
+ this.tblModels.setLinesVisible(true);
+ this.tblModels.setRedraw(true);
+ if (logger.isTraceEnabled() ) logger.trace(" found "+this.tblModels.getItemCount()+" model"+(this.tblModels.getItemCount()>1?"s":"")+" in total");
+
+ if ( this.tblModels.getItemCount() != 0 ) {
+ this.tblModels.setSelection(0);
+ this.tblModels.notifyListeners(SWT.Selection, new Event()); // calls database.getModelVersions()
+ }
+ }
+
+ protected void createGrpModel() {
+ this.grpModels = new Group(this.compoRightBottom, SWT.SHADOW_ETCHED_IN);
+ this.grpModels.setBackground(GROUP_BACKGROUND_COLOR);
+ this.grpModels.setFont(GROUP_TITLE_FONT);
+ this.grpModels.setText("Models: ");
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(50, -5);
+ fd.bottom = new FormAttachment(100);
+ this.grpModels.setLayoutData(fd);
+ this.grpModels.setLayout(new FormLayout());
+
+ Label lblListModels = new Label(this.grpModels, SWT.NONE);
+ lblListModels.setBackground(GROUP_BACKGROUND_COLOR);
+ lblListModels.setText("Filter:");
+ fd = new FormData();
+ fd.top = new FormAttachment(0, getDefaultMargin());
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ lblListModels.setLayoutData(fd);
+
+ this.txtFilterModels = new Text(this.grpModels, SWT.BORDER);
+ this.txtFilterModels.setToolTipText("You may use '%' as wildcard.");
+ this.txtFilterModels.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ DBGuiImportModel.this.tblModels.removeAll();
+ DBGuiImportModel.this.tblModelVersions.removeAll();
+ try {
+ for (Hashtable model : DBGuiImportModel.this.importConnection.getModels("%"+DBGuiImportModel.this.txtFilterModels.getText()+"%")) {
+ TableItem tableItem = new TableItem(DBGuiImportModel.this.tblModels, SWT.BORDER);
+ tableItem.setText(0, (String)model.get("name"));
+ tableItem.setText(1, new SimpleDateFormat("dd/MM/yyyy").format(((Date)model.get("created_on"))));
+ tableItem.setData("id", model.get("id"));
+ tableItem.setData("date", model.get("created_on"));
+ }
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "Failed to get the list of models in the database.", err);
+ }
+ }
+ });
+ fd = new FormData();
+ fd.top = new FormAttachment(lblListModels, 0, SWT.CENTER);
+ fd.left = new FormAttachment(lblListModels, 5);
+ fd.right = new FormAttachment(100, -getDefaultMargin());
+ this.txtFilterModels.setLayoutData(fd);
+
+
+
+ this.tblModels = new Table(this.grpModels, SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL | SWT.H_SCROLL);
+ this.tblModels.setLinesVisible(true);
+ this.tblModels.setHeaderVisible(true);
+ this.tblModels.setBackground(TABLE_BACKGROUND_COLOR);
+ this.tblModels.addListener(SWT.Selection, new Listener() {
+ @Override
+ public void handleEvent(Event e) {
+ DBGuiImportModel.this.tblModelVersions.removeAll();
+
+ try {
+ for (Hashtable version : DBGuiImportModel.this.importConnection.getModelVersions((String) DBGuiImportModel.this.tblModels.getSelection()[0].getData("id")) ) {
+ if ( DBGuiImportModel.this.tblModelVersions.getItemCount() == 0 ) {
+ // if the first line, then we add the "latest version"
+ TableItem tableItem = new TableItem(DBGuiImportModel.this.tblModelVersions, SWT.NULL);
+ tableItem.setText(1, "(latest version)");
+ tableItem.setData("name", version.get("name"));
+ tableItem.setData("note", version.get("note"));
+ tableItem.setData("purpose", version.get("purpose"));
+ }
+
+ TableItem tableItem = new TableItem(DBGuiImportModel.this.tblModelVersions, SWT.NULL);
+ tableItem.setText(0, (String)version.get("version"));
+ tableItem.setText(1, new SimpleDateFormat("dd/MM/yyyy").format((Timestamp)version.get("created_on")));
+ tableItem.setText(2, (String)version.get("created_by"));
+ tableItem.setData("name", version.get("name"));
+ tableItem.setData("note", version.get("note"));
+ tableItem.setData("purpose", version.get("purpose"));
+ }
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "Failed to get model's versions from the database", err);
+ }
+
+ if ( DBGuiImportModel.this.tblModelVersions.getItemCount() != 0 ) {
+ DBGuiImportModel.this.tblModelVersions.setSelection(0);
+ DBGuiImportModel.this.tblModelVersions.notifyListeners(SWT.Selection, new Event()); // calls database.getModelVersions()
+ }
+ }
+ });
+ this.tblModels.addListener(SWT.MouseDoubleClick, new Listener() {
+ @Override
+ public void handleEvent(Event e) {
+ if ( DBGuiImportModel.this.btnDoAction.getEnabled() )
+ DBGuiImportModel.this.btnDoAction.notifyListeners(SWT.Selection, new Event());
+ }
+ });
+ fd = new FormData();
+ fd.top = new FormAttachment(lblListModels, getDefaultMargin());
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ fd.right = new FormAttachment(100, -getDefaultMargin());
+ fd.bottom = new FormAttachment(100, -getDefaultMargin());
+ this.tblModels.setLayoutData(fd);
+
+ TableColumn colModelName = new TableColumn(this.tblModels, SWT.NONE);
+ colModelName.setText("Model name");
+ colModelName.setWidth(250);
+ colModelName.setData("sortDirection", 1);
+ colModelName.addListener(SWT.Selection, new Listener() {
+ @Override
+ public void handleEvent(Event e) {
+ // sort column 1
+ TableItem[] items = DBGuiImportModel.this.tblModels.getItems();
+ int sortOrder = (int)colModelName.getData("sortDirection");
+ colModelName.setData("sortDirection", -sortOrder);
+ Collator collator = Collator.getInstance(Locale.getDefault());
+ for (int i = 1; i < items.length; i++) {
+ String value1 = items[i].getText(0);
+ for (int j = 0; j < i; j++) {
+ String value2 = items[j].getText(0);
+ if (collator.compare(value1, value2)*sortOrder < 0) {
+ String col0 = items[i].getText(0);
+ String col1 = items[i].getText(1);
+ String id = (String)items[i].getData("id");
+ Date date = (Date)items[i].getData("date");
+ items[i].dispose();
+ TableItem newItem = new TableItem(DBGuiImportModel.this.tblModels, SWT.NONE, j);
+ newItem.setText(0, col0);
+ newItem.setText(1, col1);
+ newItem.setData("id", id);
+ newItem.setData("date", date);
+ items = DBGuiImportModel.this.tblModels.getItems();
+ break;
+ }
+ }
+ }
+ }
+ });
+
+ TableColumn colModelDate = new TableColumn(this.tblModels, SWT.NONE);
+ colModelDate.setText("Date");
+ colModelDate.setWidth(120);
+ colModelDate.setData("sortDirection", 1);
+ colModelDate.addListener(SWT.Selection, new Listener() {
+ @Override
+ public void handleEvent(Event e) {
+ // sort column 1
+ TableItem[] items = DBGuiImportModel.this.tblModels.getItems();
+ int sortOrder = (int)colModelDate.getData("sortDirection");
+ colModelDate.setData("sortDirection", -sortOrder);
+ for (int i = 1; i < items.length; i++) {
+ Date date1 = (Date)items[i].getData("date");
+ for (int j = 0; j < i; j++) {
+ Date date2 = (Date)items[j].getData("date");
+ if (date1.compareTo(date2)*sortOrder < 0) {
+ String col0 = items[i].getText(0);
+ String col1 = items[i].getText(1);
+ String id = (String)items[i].getData("id");
+ Date date = (Date)items[i].getData("date");
+ items[i].dispose();
+ TableItem newItem = new TableItem(DBGuiImportModel.this.tblModels, SWT.NONE, j);
+ newItem.setText(0, col0);
+ newItem.setText(1, col1);
+ newItem.setData("id", id);
+ newItem.setData("date", date);
+ items = DBGuiImportModel.this.tblModels.getItems();
+ break;
+ }
+ }
+ }
+ }
+ });
+
+ this.grpModelVersions = new Group(this.compoRightBottom, SWT.SHADOW_ETCHED_IN);
+ this.grpModelVersions.setBackground(GROUP_BACKGROUND_COLOR);
+ this.grpModelVersions.setFont(GROUP_TITLE_FONT);
+ this.grpModelVersions.setText("Versions of selected model: ");
+ fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(50, 5);
+ fd.right = new FormAttachment(100);
+ fd.bottom = new FormAttachment(100);
+ this.grpModelVersions.setLayoutData(fd);
+ this.grpModelVersions.setLayout(new FormLayout());
+
+ this.tblModelVersions = new Table(this.grpModelVersions, SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL);
+ this.tblModelVersions.setBackground(TABLE_BACKGROUND_COLOR);
+ this.tblModelVersions.setLinesVisible(true);
+ this.tblModelVersions.setHeaderVisible(true);
+ this.tblModelVersions.addListener(SWT.Selection, new Listener() {
+ @Override
+ public void handleEvent(Event e) {
+ if ( (DBGuiImportModel.this.tblModelVersions.getSelection() != null) && (DBGuiImportModel.this.tblModelVersions.getSelection().length > 0) && (DBGuiImportModel.this.tblModelVersions.getSelection()[0] != null) ) {
+ DBGuiImportModel.this.txtReleaseNote.setText((String) DBGuiImportModel.this.tblModelVersions.getSelection()[0].getData("note"));
+ DBGuiImportModel.this.txtPurpose.setText((String) DBGuiImportModel.this.tblModelVersions.getSelection()[0].getData("purpose"));
+ DBGuiImportModel.this.txtModelName.setText((String) DBGuiImportModel.this.tblModelVersions.getSelection()[0].getData("name"));
+ DBGuiImportModel.this.btnDoAction.setEnabled(true);
+ } else {
+ DBGuiImportModel.this.btnDoAction.setEnabled(false);
+ }
+ }
+ });
+ this.tblModelVersions.addListener(SWT.MouseDoubleClick, new Listener() {
+ @Override
+ public void handleEvent(Event e) {
+ if ( DBGuiImportModel.this.btnDoAction.getEnabled() )
+ DBGuiImportModel.this.btnDoAction.notifyListeners(SWT.Selection, new Event());
+ }
+ });
+ fd = new FormData();
+ fd.top = new FormAttachment(0, getDefaultMargin());
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ fd.right = new FormAttachment(100, -getDefaultMargin());
+ fd.bottom = new FormAttachment(50);
+ this.tblModelVersions.setLayoutData(fd);
+
+ TableColumn colVersion = new TableColumn(this.tblModelVersions, SWT.NONE);
+ colVersion.setText("#");
+ colVersion.setWidth(50);
+
+ TableColumn colCreatedOn = new TableColumn(this.tblModelVersions, SWT.NONE);
+ colCreatedOn.setText("Date");
+ colCreatedOn.setWidth(120);
+
+ TableColumn colCreatedBy = new TableColumn(this.tblModelVersions, SWT.NONE);
+ colCreatedBy.setText("Author");
+ colCreatedBy.setWidth(150);
+
+ this.lblModelName = new Label(this.grpModelVersions, SWT.NONE);
+ this.lblModelName.setBackground(GROUP_BACKGROUND_COLOR);
+ this.lblModelName.setText("Model name:");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.tblModelVersions, getDefaultMargin());
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ this.lblModelName.setLayoutData(fd);
+
+ this.txtModelName = new Text(this.grpModelVersions, SWT.BORDER);
+ this.txtModelName.setBackground(GROUP_BACKGROUND_COLOR);
+ this.txtModelName.setEnabled(false);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.lblModelName);
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ fd.right = new FormAttachment(100, -getDefaultMargin());
+ this.txtModelName.setLayoutData(fd);
+
+ this.lblPurpose = new Label(this.grpModelVersions, SWT.NONE);
+ this.lblPurpose.setBackground(GROUP_BACKGROUND_COLOR);
+ this.lblPurpose.setText("Purpose:");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.txtModelName, getDefaultMargin());
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ this.lblPurpose.setLayoutData(fd);
+
+ this.txtPurpose = new Text(this.grpModelVersions, SWT.BORDER);
+ this.txtPurpose.setBackground(GROUP_BACKGROUND_COLOR);
+ this.txtPurpose.setEnabled(false);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.lblPurpose);
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ fd.right = new FormAttachment(100, -getDefaultMargin());
+ fd.bottom = new FormAttachment(80, -5);
+ this.txtPurpose.setLayoutData(fd);
+
+ this.lblReleaseNote = new Label(this.grpModelVersions, SWT.NONE);
+ this.lblReleaseNote.setBackground(GROUP_BACKGROUND_COLOR);
+ this.lblReleaseNote.setText("Release note:");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.txtPurpose, getDefaultMargin());
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ this.lblReleaseNote.setLayoutData(fd);
+
+ this.txtReleaseNote = new Text(this.grpModelVersions, SWT.BORDER);
+ this.txtReleaseNote.setBackground(GROUP_BACKGROUND_COLOR);
+ this.txtReleaseNote.setEnabled(false);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.lblReleaseNote);
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ fd.right = new FormAttachment(100, -getDefaultMargin());
+ fd.bottom = new FormAttachment(100, -getDefaultMargin());
+ this.txtReleaseNote.setLayoutData(fd);
+ }
+
+ /**
+ * Creates a group displaying details about the imported model's components
+ */
+ private void createGrpComponents() {
+ this.grpComponents = new Group(this.compoRightBottom, SWT.SHADOW_ETCHED_IN);
+ this.grpComponents.setVisible(false);
+ this.grpComponents.setBackground(GROUP_BACKGROUND_COLOR);
+ this.grpComponents.setFont(GROUP_TITLE_FONT);
+ this.grpComponents.setText("Your model's components: ");
+
+ // we calculate the required height of the grpComponents group
+ int requiredHeight = 10 * (getDefaultLabelHeight() + getDefaultMargin());
+
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(100, -requiredHeight);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ fd.bottom = new FormAttachment(100);
+ this.grpComponents.setLayoutData(fd);
+ this.grpComponents.setLayout(new FormLayout());
+
+ Label lblProfiles = new Label(this.grpComponents, SWT.NONE);
+ lblProfiles.setBackground(GROUP_BACKGROUND_COLOR);
+ lblProfiles.setText("Specializations:");
+ fd = new FormData();
+ fd.top = new FormAttachment(0, 25);
+ fd.left = new FormAttachment(0, 30);
+ lblProfiles.setLayoutData(fd);
+
+ Label lblElements = new Label(this.grpComponents, SWT.NONE);
+ lblElements.setBackground(GROUP_BACKGROUND_COLOR);
+ lblElements.setText("Elements:");
+ fd = new FormData();
+ fd.top = new FormAttachment(lblProfiles, getDefaultMargin());
+ fd.left = new FormAttachment(0, 30);
+ lblElements.setLayoutData(fd);
+
+ Label lblRelationships = new Label(this.grpComponents, SWT.NONE);
+ lblRelationships.setBackground(GROUP_BACKGROUND_COLOR);
+ lblRelationships.setText("Relationships:");
+ fd = new FormData();
+ fd.top = new FormAttachment(lblElements, getDefaultMargin());
+ fd.left = new FormAttachment(0, 30);
+ lblRelationships.setLayoutData(fd);
+
+ Label lblFolders = new Label(this.grpComponents, SWT.NONE);
+ lblFolders.setBackground(GROUP_BACKGROUND_COLOR);
+ lblFolders.setText("Folders:");
+ fd = new FormData();
+ fd.top = new FormAttachment(lblRelationships, getDefaultMargin());
+ fd.left = new FormAttachment(0, 30);
+ lblFolders.setLayoutData(fd);
+
+ Label lblViews = new Label(this.grpComponents, SWT.NONE);
+ lblViews.setBackground(GROUP_BACKGROUND_COLOR);
+ lblViews.setText("Views:");
+ fd = new FormData();
+ fd.top = new FormAttachment(lblFolders, getDefaultMargin());
+ fd.left = new FormAttachment(0, 30);
+ lblViews.setLayoutData(fd);
+
+ Label lblViewObjects = new Label(this.grpComponents, SWT.NONE);
+ lblViewObjects.setBackground(GROUP_BACKGROUND_COLOR);
+ lblViewObjects.setText("Objects:");
+ fd = new FormData();
+ fd.top = new FormAttachment(lblViews, getDefaultMargin());
+ fd.left = new FormAttachment(0, 30);
+ lblViewObjects.setLayoutData(fd);
+
+ Label lblViewConnections = new Label(this.grpComponents, SWT.NONE);
+ lblViewConnections.setBackground(GROUP_BACKGROUND_COLOR);
+ lblViewConnections.setText("Connections:");
+ fd = new FormData();
+ fd.top = new FormAttachment(lblViewObjects, getDefaultMargin());
+ fd.left = new FormAttachment(0, 30);
+ lblViewConnections.setLayoutData(fd);
+
+ Label lblImages = new Label(this.grpComponents, SWT.NONE);
+ lblImages.setBackground(GROUP_BACKGROUND_COLOR);
+ lblImages.setText("Images:");
+ fd = new FormData();
+ fd.top = new FormAttachment(lblViewConnections, getDefaultMargin());
+ fd.left = new FormAttachment(0, 30);
+ lblImages.setLayoutData(fd);
+
+ /* * * * * */
+
+ Label lblTotal = new Label(this.grpComponents, SWT.CENTER);
+ lblTotal.setBackground(GROUP_BACKGROUND_COLOR);
+ lblTotal.setText("Total");
+ fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(20, getDefaultMargin());
+ fd.right = new FormAttachment(40, -getDefaultMargin());
+ lblTotal.setLayoutData(fd);
+
+ Label lblImported = new Label(this.grpComponents, SWT.CENTER);
+ lblImported.setBackground(GROUP_BACKGROUND_COLOR);
+ lblImported.setText("Imported");
+ fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(40, getDefaultMargin());
+ fd.right = new FormAttachment(60, -getDefaultMargin());
+ lblImported.setLayoutData(fd);
+
+ /* * * * * */
+
+ this.txtTotalProfiles = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtTotalProfiles.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblProfiles, 0, SWT.CENTER);
+ fd.left = new FormAttachment(lblTotal, 0, SWT.LEFT);
+ fd.right = new FormAttachment(lblTotal, 0, SWT.RIGHT);
+ this.txtTotalProfiles.setLayoutData(fd);
+
+ this.txtImportedProfiles = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtImportedProfiles.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblProfiles, 0, SWT.CENTER);
+ fd.left = new FormAttachment(lblImported, 0, SWT.LEFT);
+ fd.right = new FormAttachment(lblImported, 0, SWT.RIGHT);
+ this.txtImportedProfiles.setLayoutData(fd);
+
+ this.txtTotalElements = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtTotalElements.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblElements, 0, SWT.CENTER);
+ fd.left = new FormAttachment(lblTotal, 0, SWT.LEFT);
+ fd.right = new FormAttachment(lblTotal, 0, SWT.RIGHT);
+ this.txtTotalElements.setLayoutData(fd);
+
+ this.txtImportedElements = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtImportedElements.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblElements, 0, SWT.CENTER);
+ fd.left = new FormAttachment(lblImported, 0, SWT.LEFT);
+ fd.right = new FormAttachment(lblImported, 0, SWT.RIGHT);
+ this.txtImportedElements.setLayoutData(fd);
+
+ this.txtTotalRelationships = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtTotalRelationships.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblRelationships, 0, SWT.CENTER);
+ fd.left = new FormAttachment(lblTotal, 0, SWT.LEFT);
+ fd.right = new FormAttachment(lblTotal, 0, SWT.RIGHT);
+ this.txtTotalRelationships.setLayoutData(fd);
+
+ this.txtImportedRelationships = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtImportedRelationships.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblRelationships, 0, SWT.CENTER);
+ fd.left = new FormAttachment(lblImported, 0, SWT.LEFT);
+ fd.right = new FormAttachment(lblImported, 0, SWT.RIGHT);
+ this.txtImportedRelationships.setLayoutData(fd);
+
+ this.txtTotalFolders = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtTotalFolders.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblFolders, 0, SWT.CENTER);
+ fd.left = new FormAttachment(lblTotal, 0, SWT.LEFT);
+ fd.right = new FormAttachment(lblTotal, 0, SWT.RIGHT);
+ this.txtTotalFolders.setLayoutData(fd);
+
+ this.txtImportedFolders = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtImportedFolders.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblFolders, 0, SWT.CENTER);
+ fd.left = new FormAttachment(lblImported, 0, SWT.LEFT);
+ fd.right = new FormAttachment(lblImported, 0, SWT.RIGHT);
+ this.txtImportedFolders.setLayoutData(fd);
+
+ this.txtTotalViews = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtTotalViews.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViews, 0, SWT.CENTER);
+ fd.left = new FormAttachment(lblTotal, 0, SWT.LEFT);
+ fd.right = new FormAttachment(lblTotal, 0, SWT.RIGHT);
+ this.txtTotalViews.setLayoutData(fd);
+
+ this.txtImportedViews = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtImportedViews.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViews, 0, SWT.CENTER);
+ fd.left = new FormAttachment(lblImported, 0, SWT.LEFT);
+ fd.right = new FormAttachment(lblImported, 0, SWT.RIGHT);
+ this.txtImportedViews.setLayoutData(fd);
+
+ this.txtTotalViewObjects = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtTotalViewObjects.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViewObjects, 0, SWT.CENTER);
+ fd.left = new FormAttachment(lblTotal, 0, SWT.LEFT);
+ fd.right = new FormAttachment(lblTotal, 0, SWT.RIGHT);
+ this.txtTotalViewObjects.setLayoutData(fd);
+
+ this.txtImportedViewObjects = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtImportedViewObjects.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViewObjects, 0, SWT.CENTER);
+ fd.left = new FormAttachment(lblImported, 0, SWT.LEFT);
+ fd.right = new FormAttachment(lblImported, 0, SWT.RIGHT);
+ this.txtImportedViewObjects.setLayoutData(fd);
+
+ this.txtTotalViewConnections = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtTotalViewConnections.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViewConnections, 0, SWT.CENTER);
+ fd.left = new FormAttachment(lblTotal, 0, SWT.LEFT);
+ fd.right = new FormAttachment(lblTotal, 0, SWT.RIGHT);
+ this.txtTotalViewConnections.setLayoutData(fd);
+
+ this.txtImportedViewConnections = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtImportedViewConnections.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblViewConnections, 0, SWT.CENTER);
+ fd.left = new FormAttachment(lblImported, 0, SWT.LEFT);
+ fd.right = new FormAttachment(lblImported, 0, SWT.RIGHT);
+ this.txtImportedViewConnections.setLayoutData(fd);
+
+ this.txtTotalImages = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtTotalImages.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblImages, 0, SWT.CENTER);
+ fd.left = new FormAttachment(lblTotal, 0, SWT.LEFT);
+ fd.right = new FormAttachment(lblTotal, 0, SWT.RIGHT);
+ this.txtTotalImages.setLayoutData(fd);
+
+ this.txtImportedImages = new Text(this.grpComponents, SWT.BORDER | SWT.CENTER);
+ this.txtImportedImages.setEditable(false);
+ fd = new FormData(26,18);
+ fd.top = new FormAttachment(lblImages, 0, SWT.CENTER);
+ fd.left = new FormAttachment(lblImported, 0, SWT.LEFT);
+ fd.right = new FormAttachment(lblImported, 0, SWT.RIGHT);
+ this.txtImportedImages.setLayoutData(fd);
+ }
+
+ /**
+ * Called when the user clicks on the "import" button
+ */
+ public void doImport() {
+ String modelName = this.tblModels.getSelection()[0].getText();
+ String modelId = (String)this.tblModels.getSelection()[0].getData("id");
+
+ hideGrpDatabase();
+ createProgressBar("Importing model \""+modelName+"\"", 0, 100);
+
+
+ this.grpModels.setVisible(false);
+ this.grpComponents.setVisible(true);
+
+ // we reorganize the grpModelVersion widget
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ fd.bottom = new FormAttachment(this.grpComponents, -getDefaultMargin());
+ this.grpModelVersions.setLayoutData(fd);
+
+ fd = new FormData();
+ fd.top = new FormAttachment(0, getDefaultMargin());
+ fd.left = new FormAttachment(0, getDefaultMargin());
+ fd.right = new FormAttachment(40, -getDefaultMargin());
+ fd.bottom = new FormAttachment(100, -getDefaultMargin());
+ this.tblModelVersions.setLayoutData(fd);
+
+ fd = new FormData();
+ fd.top = new FormAttachment(0, getDefaultMargin());
+ fd.left = new FormAttachment(40, 0);
+ this.lblModelName.setLayoutData(fd);
+
+ fd = new FormData();
+ fd.top = new FormAttachment(this.lblModelName, 0, SWT.CENTER);
+ fd.left = new FormAttachment(this.lblModelName, 80, SWT.LEFT);
+ fd.right = new FormAttachment(100, -getDefaultMargin());
+ this.txtModelName.setLayoutData(fd);
+
+ fd = new FormData();
+ fd.top = new FormAttachment(this.txtModelName, getDefaultMargin());
+ fd.left = new FormAttachment(40, 0);
+ this.lblPurpose.setLayoutData(fd);
+
+ fd = new FormData();
+ fd.top = new FormAttachment(this.txtModelName, 5);
+ fd.left = new FormAttachment(this.txtModelName, 0, SWT.LEFT);
+ fd.right = new FormAttachment(100, -getDefaultMargin());
+ fd.bottom = new FormAttachment(55, -5);
+ this.txtPurpose.setLayoutData(fd);
+
+ fd = new FormData();
+ fd.top = new FormAttachment(this.txtPurpose, getDefaultMargin());
+ fd.left = new FormAttachment(40, 0);
+ this.lblReleaseNote.setLayoutData(fd);
+
+ fd = new FormData();
+ fd.top = new FormAttachment(this.txtPurpose, 5);
+ fd.left = new FormAttachment(this.txtModelName, 0, SWT.LEFT);
+ fd.right = new FormAttachment(100, -getDefaultMargin());
+ fd.bottom = new FormAttachment(100, -getDefaultMargin());
+ this.txtReleaseNote.setLayoutData(fd);
+
+ this.compoRightBottom.layout();
+
+ setActiveAction(ACTION.Two);
+
+ // we create the model (but do not create standard folder as they will be imported from the database)
+ this.modelToImport = (DBArchimateModel)DBArchimateFactory.eINSTANCE.createArchimateModel();
+ this.modelToImport.setId(modelId);
+
+ try {
+ // import properties, features and profiles from the database
+ this.importConnection.importModel(this.modelToImport);
+
+ // we get the selected model version to import
+ // if the value is empty, this means that the user selected the "Now" line, so we must load the latest version of the views
+ if ( !this.tblModelVersions.getSelection()[0].getText(0).isEmpty() ) {
+ this.modelToImport.getInitialVersion().setVersion(Integer.valueOf(this.tblModelVersions.getSelection()[0].getText(0)));
+ this.modelToImport.setLatestVersionImported(false);
+ } else {
+ this.modelToImport.getInitialVersion().setVersion(Integer.valueOf(this.tblModelVersions.getItem(1).getText(0)));
+ this.modelToImport.setLatestVersionImported(true);
+ }
+
+ // we add the new model in the manager
+ IEditorModelManager.INSTANCE.registerModel(this.modelToImport);
+
+ // count components to be imported from the database
+ int importSize = this.importConnection.countModelComponents(this.modelToImport);
+
+ setProgressBarMinAndMax(0, importSize);
+
+ this.txtTotalProfiles.setText(toString(this.importConnection.getCountProfilesToImport()));
+ this.txtTotalElements.setText(toString(this.importConnection.getCountElementsToImport()));
+ this.txtTotalRelationships.setText(toString(this.importConnection.getCountRelationshipsToImport()));
+ this.txtTotalFolders.setText(toString(this.importConnection.getCountFoldersToImport()));
+ this.txtTotalViews.setText(toString(this.importConnection.getCountViewsToImport()));
+ this.txtTotalViewObjects.setText(toString(this.importConnection.getCountViewObjectsToImport()));
+ this.txtTotalViewConnections.setText(toString(this.importConnection.getCountViewConnectionsToImport()));
+ this.txtTotalImages.setText(toString(this.importConnection.getCountImagesToImport()));
+
+ this.txtImportedProfiles.setText("0");
+ this.txtImportedElements.setText("0");
+ this.txtImportedRelationships.setText("0");
+ this.txtImportedFolders.setText("0");
+ this.txtImportedViews.setText("0");
+ this.txtImportedViewObjects.setText("0");
+ this.txtImportedViewConnections.setText("0");
+ this.txtImportedImages.setText("0");
+
+ // Import the model components from the database
+
+ logger.info("Importing specializations ...");
+ this.importConnection.prepareImportProfiles(this.modelToImport);
+ while ( this.importConnection.importProfiles(this.modelToImport) ) {
+ this.txtImportedProfiles.setText(toString(this.importConnection.getCountProfilesImported()));
+ increaseProgressBar();
+ }
+
+ logger.info("Importing folders ...");
+ this.importConnection.prepareImportFolders(this.modelToImport);
+ while ( this.importConnection.importFolders(this.modelToImport) ) {
+ this.txtImportedFolders.setText(toString(this.importConnection.getCountFoldersImported()));
+ increaseProgressBar();
+ }
+
+ logger.info("Importing elements ...");
+ this.importConnection.prepareImportElements(this.modelToImport);
+ while ( this.importConnection.importElements(this.modelToImport) ) {
+ this.txtImportedElements.setText(toString(this.importConnection.getCountElementsImported()));
+ increaseProgressBar();
+ }
+
+ logger.info("Importing relationships ...");
+ this.importConnection.prepareImportRelationships(this.modelToImport);
+ while ( this.importConnection.importRelationships(this.modelToImport) ) {
+ this.txtImportedRelationships.setText(toString(this.importConnection.getCountRelationshipsImported()));
+ increaseProgressBar();
+ }
+ this.modelToImport.resolveSourceAndTargetRelationships();
+
+ logger.info("Importing views ...");
+ this.importConnection.prepareImportViews(this.modelToImport);
+ while ( this.importConnection.importViews(this.modelToImport) ) {
+ this.txtImportedViews.setText(toString(this.importConnection.getCountViewsImported()));
+ increaseProgressBar();
+ }
+
+ logger.info("Importing view objects ...");
+ for (IDiagramModel view: this.modelToImport.getAllViews().values()) {
+ this.importConnection.prepareImportViewsObjects(view.getId(), this.modelToImport.getDBMetadata(view).getInitialVersion().getVersion());
+ while ( this.importConnection.importViewsObjects(this.modelToImport, view) ) {
+ this.txtImportedViewObjects.setText(toString(this.importConnection.getCountViewObjectsImported()));
+ increaseProgressBar();
+ }
+ }
+ this.txtImportedElements.setText(toString(this.importConnection.getCountElementsImported()));
+
+ logger.info("Importing view connections ...");
+ for (IDiagramModel view: this.modelToImport.getAllViews().values()) {
+ this.importConnection.prepareImportViewsConnections(view.getId(), this.modelToImport.getDBMetadata(view).getInitialVersion().getVersion());
+ while ( this.importConnection.importViewsConnections(this.modelToImport) ) {
+ this.txtImportedViewConnections.setText(toString(this.importConnection.getCountViewConnectionsImported()));
+ increaseProgressBar();
+ }
+ }
+ this.modelToImport.resolveSourceAndTargetConnections();
+ this.txtImportedRelationships.setText(toString(this.importConnection.getCountRelationshipsImported()));
+
+ closeMessage();
+
+ logger.info("Importing images ...");
+ for (String path: this.importConnection.getAllImagePaths()) {
+ this.importConnection.importImage(this.modelToImport, path);
+ this.txtImportedImages.setText(toString(this.importConnection.getCountImagesImported()));
+ increaseProgressBar();
+ }
+
+ // If the model contains a view called "default view", we open it.
+ for ( IDiagramModel view: this.modelToImport.getDiagramModels() ) {
+ if ( DBPlugin.areEqual(view.getName().toLowerCase(), "default view") ) {
+ setMessage("Opening default view");
+ EditorManager.openDiagramEditor(view);
+ closeMessage();
+ break;
+ }
+ }
+ } catch (Exception err) {
+ closeMessage();
+ if ( isClosedByUser() ) {
+ // we close the partially imported model
+ CommandStack stack = (CommandStack)this.modelToImport.getAdapter(CommandStack.class);
+ stack.markSaveLocation();
+ try {
+ IEditorModelManager.INSTANCE.closeModel(this.modelToImport);
+ } catch (@SuppressWarnings("unused") IOException ign) {
+ // there is nothing we can do
+ }
+ popup(Level.WARN, "The import has been cancelled.");
+ } else {
+ popup(Level.ERROR, "Failed to import model from database.", err);
+ setActiveAction(STATUS.Error);
+ doShowResult(err);
+ }
+ return;
+ }
+
+ if ( (this.dialog != null) && !this.dialog.isDisposed() ) {
+ setActiveAction(STATUS.Ok);
+ doShowResult(null);
+ }
+ return;
+ }
+
+ protected void doShowResult(Exception err) {
+ logger.debug("Showing result.");
+ if ( this.grpProgressBar != null ) this.grpProgressBar.setVisible(false);
+
+ setActiveAction(ACTION.Three);
+ this.btnClose.setText("Close");
+
+ Color statusColor = GREEN_COLOR;
+
+ if ( logger.isDebugEnabled() ) {
+ logger.debug(" "+this.importConnection.getCountProfilesImported()+"/"+this.importConnection.getCountProfilesToImport()+" specializations imported");
+ logger.debug(" "+this.importConnection.getCountElementsImported()+"/"+this.importConnection.getCountElementsToImport()+" elements imported");
+ logger.debug(" "+this.importConnection.getCountRelationshipsImported()+"/"+this.importConnection.getCountRelationshipsToImport()+" relationships imported");
+ logger.debug(" "+this.importConnection.getCountFoldersImported()+"/"+this.importConnection.getCountFoldersToImport()+" folders imported");
+ logger.debug(" "+this.importConnection.getCountViewsImported()+"/"+this.importConnection.getCountViewsToImport()+" views imported");
+ logger.debug(" "+this.importConnection.getCountViewObjectsImported()+"/"+this.importConnection.getCountViewObjectsToImport()+" views objects imported");
+ logger.debug(" "+this.importConnection.getCountViewConnectionsImported()+"/"+this.importConnection.getCountViewConnectionsToImport()+" views connections imported");
+ logger.debug(" "+this.importConnection.getCountImagesImported()+"/"+this.importConnection.getCountImagesToImport()+" images imported");
+ }
+
+ this.txtImportedProfiles.setForeground( (this.importConnection.getCountProfilesImported() == this.importConnection.getCountProfilesToImport()) ? GREEN_COLOR : (statusColor=RED_COLOR) );
+ this.txtImportedElements.setForeground( (this.importConnection.getCountElementsImported() == this.importConnection.getCountElementsToImport()) ? GREEN_COLOR : (statusColor=RED_COLOR) );
+ this.txtImportedRelationships.setForeground( (this.importConnection.getCountRelationshipsImported() == this.importConnection.getCountRelationshipsToImport()) ? GREEN_COLOR : (statusColor=RED_COLOR) );
+ this.txtImportedFolders.setForeground( (this.importConnection.getCountFoldersImported() == this.importConnection.getCountFoldersToImport()) ? GREEN_COLOR : (statusColor=RED_COLOR) );
+ this.txtImportedViews.setForeground( (this.importConnection.getCountViewsImported() == this.importConnection.getCountViewsToImport()) ? GREEN_COLOR : (statusColor=RED_COLOR) );
+ this.txtImportedViewObjects.setForeground( (this.importConnection.getCountViewObjectsImported() == this.importConnection.getCountViewObjectsToImport()) ? GREEN_COLOR : (statusColor=RED_COLOR) );
+ this.txtImportedViewConnections.setForeground( (this.importConnection.getCountViewConnectionsImported() == this.importConnection.getCountViewConnectionsToImport()) ? GREEN_COLOR : (statusColor=RED_COLOR) );
+ this.txtImportedImages.setForeground( (this.importConnection.getCountImagesImported() == this.importConnection.getCountImagesToImport()) ? GREEN_COLOR : (statusColor=RED_COLOR) );
+
+ if ( err == null ) {
+ // if all the counters are equals to the expected values
+ if ( statusColor == GREEN_COLOR ) {
+ setMessage("*** Import successful ***", statusColor);
+
+ // We open the Model in the Editor
+ IEditorModelManager.INSTANCE.openModel(this.modelToImport);
+
+ try {
+ ITreeModelView treeModelView = (ITreeModelView)ViewManager.showViewPart(ITreeModelView.ID, true);
+ if(treeModelView != null) {
+ List elements;
+
+ // we select the view folder in order to show the model folders in the tree
+ elements = new ArrayList();
+ IFolder viewsFolder = this.modelToImport.getFolder(FolderType.DIAGRAMS);
+ if ( viewsFolder != null ) {
+ elements.add(viewsFolder);
+ treeModelView.getViewer().setSelection(new StructuredSelection(elements), true);
+ }
+
+ // We select back the model in the tree
+ elements.clear();
+ elements.add(this.modelToImport);
+ treeModelView.getViewer().setSelection(new StructuredSelection(elements), true);
+ }
+ } catch (@SuppressWarnings("unused") IllegalStateException ign) {
+ // nothing to do as the workbench is not created when the import is done with ACLI
+ }
+
+ if ( DBPlugin.INSTANCE.getPreferenceStore().getBoolean("closeIfSuccessful") ) {
+ if ( logger.isDebugEnabled() ) logger.debug("Automatically closing the window as set in preferences");
+ close();
+ return;
+ }
+ } else {
+ // if some counters are different from the expected values
+ statusColor = RED_COLOR;
+ setMessage("No error has been raised during the import process,\nbut the count of imported components is not correct !", RED_COLOR);
+ }
+ } else {
+ statusColor = RED_COLOR;
+ setMessage("Error while importing model:\n"+err.getMessage(), RED_COLOR);
+ }
+
+ if ( statusColor == RED_COLOR ) {
+ if ( DBPlugin.INSTANCE.getPreferenceStore().getBoolean("deleteIfImportError") ) {
+ try {
+ // we remove the 'dirty' flag (i.e. we consider the model as saved) because we do not want the closeModel() method ask to save it
+ CommandStack stack = (CommandStack)this.modelToImport.getAdapter(CommandStack.class);
+ stack.markSaveLocation();
+
+ IEditorModelManager.INSTANCE.closeModel(this.modelToImport);
+ } catch (IOException e) {
+ popup(Level.FATAL, "Failed to close the model partially imported.\n\nWe suggest you close and restart Archi.", e);
+ }
+ } else {
+ popup(Level.ERROR, "Please be warn that the model you just imported is not concistent.\n\nYou choosed to keep it in the preferences, but should you export it back to the database, you may loose data.\n\nDo it at your own risk !");
+ }
+ }
+ }
+}
diff --git a/sources/src/org/archicontribs/database/GUI/DBGuiPasswordDialog.java b/sources/src/org/archicontribs/database/GUI/DBGuiPasswordDialog.java
new file mode 100644
index 00000000..51a93258
--- /dev/null
+++ b/sources/src/org/archicontribs/database/GUI/DBGuiPasswordDialog.java
@@ -0,0 +1,117 @@
+/**
+ * This program and the accompanying materials
+ * are made available under the terms of the License
+ * which accompanies this distribution in the file LICENSE.txt
+ */
+
+package org.archicontribs.database.GUI;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.layout.FormLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * This class opens up an input dialog and asks for a password
+ *
+ * @author Herve Jouin
+ */
+public class DBGuiPasswordDialog extends Dialog {
+ private Text txtPassword;
+ Button btnShowPassword;
+ private String password = "";
+
+
+ /**
+ * Creates the dialog
+ * @param parentShell
+ */
+ public DBGuiPasswordDialog(Shell parentShell) {
+ super(parentShell);
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ Composite composite = (Composite) super.createDialogArea(parent);
+ FormLayout layout = new FormLayout();
+ composite.setLayout(layout);
+
+ Label lblPassword = new Label(composite, SWT.NONE);
+ lblPassword.setText("Password:");
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(0, 20);
+ fd.left = new FormAttachment(0, 10);
+ lblPassword.setLayoutData(fd);
+
+ this.btnShowPassword = new Button(composite, SWT.TOGGLE);
+ this.btnShowPassword.setImage(DBGui.LOCK_ICON);
+ this.btnShowPassword.setSelection(true);
+ fd = new FormData();
+ fd.top = new FormAttachment(lblPassword, 0, SWT.CENTER);
+ fd.right = new FormAttachment(100, -20);
+ this.btnShowPassword.setLayoutData(fd);
+ this.btnShowPassword.addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent e) { showOrHidePasswordCallback(); }
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); }
+ });
+
+ this.txtPassword = new Text(composite, SWT.BORDER| SWT.PASSWORD);
+ this.txtPassword.setText(this.password);
+ fd = new FormData();
+ fd.top = new FormAttachment(lblPassword, 0, SWT.CENTER);
+ fd.left = new FormAttachment(lblPassword, 10);
+ fd.right = new FormAttachment(this.btnShowPassword, -10);
+ this.txtPassword.setLayoutData(fd);
+
+
+
+ return composite;
+ }
+
+ /**
+ * Called when the "showPassword" button is pressed
+ */
+ public void showOrHidePasswordCallback() {
+ this.txtPassword.setEchoChar(this.btnShowPassword.getSelection() ? 0x25cf : '\0' );
+ this.btnShowPassword.setImage(this.btnShowPassword.getSelection() ? DBGui.LOCK_ICON : DBGui.UNLOCK_ICON);
+ }
+
+ @Override
+ protected Point getInitialSize() {
+ return new Point(450, 300);
+ }
+
+ @Override
+ protected void okPressed() {
+ this.password = this.txtPassword.getText();
+ super.okPressed();
+ }
+
+ /**
+ * Get password
+ * @return the password
+ */
+ public String getPassword() {
+ return this.password;
+ }
+
+ /**
+ * Set password
+ * @param passwrd
+ */
+ public void setPassword(String passwrd) {
+ this.password = passwrd;
+ }
+}
diff --git a/sources/src/org/archicontribs/database/GUI/DBGuiReplaceElement.java b/sources/src/org/archicontribs/database/GUI/DBGuiReplaceElement.java
new file mode 100644
index 00000000..3a553951
--- /dev/null
+++ b/sources/src/org/archicontribs/database/GUI/DBGuiReplaceElement.java
@@ -0,0 +1,56 @@
+/**
+ * This program and the accompanying materials
+ * are made available under the terms of the License
+ * which accompanies this distribution in the file LICENSE.txt
+ */
+
+package org.archicontribs.database.GUI;
+
+import org.apache.log4j.Level;
+import org.archicontribs.database.DBLogger;
+import org.archicontribs.database.model.DBArchimateModel;
+import org.archicontribs.database.model.DBMetadata;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+
+import com.archimatetool.model.IArchimateElement;
+
+/**
+ * This class manages the GUI that allows to replace a component by another one
+ *
+ * @author Herve Jouin
+ */
+public class DBGuiReplaceElement extends DBGuiImportComponents {
+ @SuppressWarnings("hiding")
+ protected static final DBLogger logger = new DBLogger(DBGuiReplaceElement.class);
+
+ IArchimateElement selectedElement;
+
+ public DBGuiReplaceElement(DBArchimateModel model, IArchimateElement element, String title) throws Exception {
+ super(model, null, null, title);
+
+ this.selectedElement = element;
+
+ // we ensure that the element tab is selected and the only one shown
+
+
+ // we replace the "import" button by a "replace" button
+ setBtnAction("Replace", new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent event) {
+ DBGuiReplaceElement.this.btnDoAction.setEnabled(false);
+ try {
+ doReplace();
+ } catch (Exception err) {
+ DBGui.popup(Level.ERROR, "An exception has been raised during import.", err);
+ }
+ }
+ @Override
+ public void widgetDefaultSelected(SelectionEvent event) { widgetSelected(event); }
+ });
+ }
+
+ void doReplace() {
+ logger.info("Replacing "+DBMetadata.getDBMetadata(this.selectedElement).getDebugName());
+ }
+}
diff --git a/sources/src/org/archicontribs/database/GUI/DBGuiShowDebug.java b/sources/src/org/archicontribs/database/GUI/DBGuiShowDebug.java
new file mode 100644
index 00000000..bf9d8987
--- /dev/null
+++ b/sources/src/org/archicontribs/database/GUI/DBGuiShowDebug.java
@@ -0,0 +1,575 @@
+/**
+ * This program and the accompanying materials
+ * are made available under the terms of the License
+ * which accompanies this distribution in the file LICENSE.txt
+ */
+package org.archicontribs.database.GUI;
+
+import java.sql.SQLException;
+
+import org.apache.log4j.Level;
+import org.archicontribs.database.connection.DBDatabaseExportConnection;
+import org.archicontribs.database.data.DBVersion;
+import org.archicontribs.database.model.DBArchimateModel;
+import org.archicontribs.database.model.DBMetadata;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.layout.FormLayout;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+
+import com.archimatetool.model.IArchimateConcept;
+import com.archimatetool.model.IArchimateModelObject;
+import com.archimatetool.model.IDiagramModel;
+import com.archimatetool.model.IDiagramModelArchimateComponent;
+import com.archimatetool.model.IDiagramModelArchimateObject;
+import com.archimatetool.model.IDiagramModelConnection;
+import com.archimatetool.model.IDiagramModelObject;
+import com.archimatetool.model.IIdentifier;
+
+/**
+ * This class manages the GUI that shows debug information about an archimate component
+ *
+ * @author Herve Jouin
+ */
+public class DBGuiShowDebug extends DBGui {
+ //private static final DBLogger logger = new DBLogger(DBGuiExportModel.class);
+
+ private EObject selectedObject;
+ private DBMetadata selectedMetadata;
+ private DBArchimateModel model;
+
+ private DBDatabaseExportConnection exportConnection = null;
+
+ private Group grpDebug;
+
+ private Label selectedComponentLbl;
+ private Label selectedComponentNameLbl;
+ private Label selectedComponentNameValueLbl;
+ private Label selectedComponentIdLbl;
+ private Label selectedComponentIdValueLbl;
+ private Label selectedComponentClassLbl;
+ private Label selectedComponentClassValueLbl;
+ private Label selectedComponentImagePathLbl;
+ private Label selectedComponentImagePathValueLbl;
+ private Label selectedComponentDatabaseStatusLbl;
+ private Label selectedComponentDatabaseStatusValueLbl;
+ private Table selectedComponentDebugTable;
+
+ private Label correspondingConceptLbl;
+ private Label correspondingConceptNameLbl;
+ private Label correspondingConceptNameValueLbl;
+ private Label correspondingConceptIdLbl;
+ private Label correspondingConceptIdValueLbl;
+ private Label correspondingConceptClassLbl;
+ private Label correspondingConceptClassValueLbl;
+ private Label correspondingConceptDatabaseStatusLbl;
+ private Label correspondingConceptDatabaseStatusValueLbl;
+ private Table correspondingConceptDebugTable;
+
+ /**
+ * Creates the GUI that shows the debug information
+ *
+ * @param obj the component which we want the debug information
+ * @param title the title of the window
+ */
+ public DBGuiShowDebug(EObject obj, String title) {
+ // We call the DBGui constructor that will create the underlying form and expose the compoRight, compoRightUp and compoRightBottom composites
+ super(title);
+
+ this.selectedObject = obj;
+ // in Archi 4.2 and previous, we need to separate the two cases
+ if ( obj instanceof IArchimateModelObject ) {
+ this.model = (DBArchimateModel) ((IArchimateModelObject)obj).getArchimateModel();
+ this.selectedMetadata = DBMetadata.getDBMetadata(obj);
+ } else if ( obj instanceof IDiagramModelArchimateObject ) {
+ this.model = (DBArchimateModel) ((IDiagramModelArchimateObject)obj).getArchimateConcept().getArchimateModel();
+ this.selectedMetadata = DBMetadata.getDBMetadata(obj);
+ } else {
+ popup(Level.ERROR, "Do not know how to get debugging information about a "+obj.getClass().getSimpleName());
+ return;
+ }
+
+ if ( logger.isDebugEnabled() ) logger.debug("Setting up GUI for showing debug information about "+DBMetadata.getDBMetadata(obj).getDebugName());
+
+ createGrpDebug();
+
+ createAction(ACTION.One, "1 - Show debug");
+
+ // we show an arrow in front of the first action
+ setActiveAction(ACTION.One);
+
+ // We activate the Eclipse Help framework
+ setHelpHref("showDebug.html");
+ }
+
+ private void createGrpDebug() {
+ this.grpDebug = new Group(this.compoRightBottom, SWT.NONE);
+ this.grpDebug.setBackground(GROUP_BACKGROUND_COLOR);
+ this.grpDebug.setText("Debug information: ");
+ this.grpDebug.setFont(GROUP_TITLE_FONT);
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(0);
+ fd.left = new FormAttachment(0);
+ fd.right = new FormAttachment(100);
+ fd.bottom = new FormAttachment(100);
+ this.grpDebug.setLayoutData(fd);
+ this.grpDebug.setLayout(new FormLayout());
+
+ // selected component
+ this.selectedComponentLbl = new Label(this.grpDebug, SWT.NONE);
+ this.selectedComponentLbl.setBackground(GROUP_BACKGROUND_COLOR);
+ this.selectedComponentLbl.setText("You selected the following component:");
+ fd = new FormData();
+ fd.top = new FormAttachment(0, 10);
+ fd.left = new FormAttachment(0, 20);
+ this.selectedComponentLbl.setLayoutData(fd);
+
+ // Name
+ this.selectedComponentNameLbl = new Label(this.grpDebug, SWT.NONE);
+ this.selectedComponentNameLbl.setBackground(GROUP_BACKGROUND_COLOR);
+ this.selectedComponentNameLbl.setText("Name:");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.selectedComponentLbl, 5);
+ fd.left = new FormAttachment(0, 70);
+ this.selectedComponentNameLbl.setLayoutData(fd);
+
+ this.selectedComponentNameValueLbl = new Label(this.grpDebug, SWT.NONE);
+ this.selectedComponentNameValueLbl.setBackground(GROUP_BACKGROUND_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.selectedComponentNameLbl, 0, SWT.TOP);
+ fd.left = new FormAttachment(this.selectedComponentNameLbl, 70);
+ fd.right = new FormAttachment(100, -20);
+ this.selectedComponentNameValueLbl.setLayoutData(fd);
+
+ // Id
+ this.selectedComponentIdLbl = new Label(this.grpDebug, SWT.NONE);
+ this.selectedComponentIdLbl.setBackground(GROUP_BACKGROUND_COLOR);
+ this.selectedComponentIdLbl.setText("Id:");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.selectedComponentNameLbl, 2);
+ fd.left = new FormAttachment(this.selectedComponentNameLbl, 0, SWT.LEFT);
+ this.selectedComponentIdLbl.setLayoutData(fd);
+
+ this.selectedComponentIdValueLbl = new Label(this.grpDebug, SWT.NONE);
+ this.selectedComponentIdValueLbl.setBackground(GROUP_BACKGROUND_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.selectedComponentIdLbl, 0, SWT.TOP);
+ fd.left = new FormAttachment(this.selectedComponentNameValueLbl, 0, SWT.LEFT);
+ fd.right = new FormAttachment(100, -20);
+ this.selectedComponentIdValueLbl.setLayoutData(fd);
+
+ // Class
+ this.selectedComponentClassLbl = new Label(this.grpDebug, SWT.NONE);
+ this.selectedComponentClassLbl.setBackground(GROUP_BACKGROUND_COLOR);
+ this.selectedComponentClassLbl.setText("Class:");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.selectedComponentIdLbl, 2);
+ fd.left = new FormAttachment(this.selectedComponentNameLbl, 0, SWT.LEFT);
+ this.selectedComponentClassLbl.setLayoutData(fd);
+
+ this.selectedComponentClassValueLbl = new Label(this.grpDebug, SWT.NONE);
+ this.selectedComponentClassValueLbl.setBackground(GROUP_BACKGROUND_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.selectedComponentClassLbl, 0, SWT.TOP);
+ fd.left = new FormAttachment(this.selectedComponentNameValueLbl, 0, SWT.LEFT);
+ fd.right = new FormAttachment(100, -20);
+ this.selectedComponentClassValueLbl.setLayoutData(fd);
+
+ // Image Path
+ this.selectedComponentImagePathLbl = new Label(this.grpDebug, SWT.NONE);
+ this.selectedComponentImagePathLbl.setBackground(GROUP_BACKGROUND_COLOR);
+ this.selectedComponentImagePathLbl.setText("Image Path:");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.selectedComponentClassLbl, 2);
+ fd.left = new FormAttachment(this.selectedComponentNameLbl, 0, SWT.LEFT);
+ this.selectedComponentImagePathLbl.setLayoutData(fd);
+
+ this.selectedComponentImagePathValueLbl = new Label(this.grpDebug, SWT.NONE);
+ this.selectedComponentImagePathValueLbl.setBackground(GROUP_BACKGROUND_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.selectedComponentImagePathLbl, 0, SWT.TOP);
+ fd.left = new FormAttachment(this.selectedComponentNameValueLbl, 0, SWT.LEFT);
+ fd.right = new FormAttachment(100, -20);
+ this.selectedComponentImagePathValueLbl.setLayoutData(fd);
+
+ // Database status
+ this.selectedComponentDatabaseStatusLbl = new Label(this.grpDebug, SWT.BOLD);
+ this.selectedComponentDatabaseStatusLbl.setBackground(GROUP_BACKGROUND_COLOR);
+ this.selectedComponentDatabaseStatusLbl.setText("Database status:");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.selectedComponentImagePathLbl, 2);
+ fd.left = new FormAttachment(0, 70);
+ this.selectedComponentDatabaseStatusLbl.setLayoutData(fd);
+
+ this.selectedComponentDatabaseStatusValueLbl = new Label(this.grpDebug, SWT.BOLD);
+ this.selectedComponentDatabaseStatusValueLbl.setBackground(GROUP_BACKGROUND_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.selectedComponentDatabaseStatusLbl, 0, SWT.TOP);
+ fd.left = new FormAttachment(this.selectedComponentNameValueLbl, 0, SWT.LEFT);
+ fd.right = new FormAttachment(100, -20);
+ this.selectedComponentDatabaseStatusValueLbl.setLayoutData(fd);
+
+ // Table
+ this.selectedComponentDebugTable = new Table(this.grpDebug, SWT.BORDER | SWT.FULL_SELECTION);
+ this.selectedComponentDebugTable.setLinesVisible(true);
+ this.selectedComponentDebugTable.setHeaderVisible(true);
+ this.selectedComponentDebugTable.setBackground(TABLE_BACKGROUND_COLOR);
+ this.selectedComponentDebugTable.setHeaderBackground(COMPO_LEFT_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.selectedComponentDatabaseStatusValueLbl, 10);
+ fd.left = new FormAttachment(0, 20);
+ fd.right = new FormAttachment(100, -20);
+ fd.bottom = new FormAttachment(50, -10);
+ this.selectedComponentDebugTable.setLayoutData(fd);
+
+ TableColumn column = new TableColumn(this.selectedComponentDebugTable, SWT.NONE);
+ column.setWidth(100);
+ column = new TableColumn(this.selectedComponentDebugTable, SWT.CENTER);
+ column.setText("Version");
+ column.setWidth(50);
+ column = new TableColumn(this.selectedComponentDebugTable, SWT.CENTER);
+ column.setText("Container checksum");
+ column.setWidth(230);
+ column = new TableColumn(this.selectedComponentDebugTable, SWT.CENTER);
+ column.setText("Checksum");
+ column.setWidth(230);
+ column = new TableColumn(this.selectedComponentDebugTable, SWT.CENTER);
+ column.setText("Created on");
+ column.setWidth(140);
+
+ // corresponding concept
+ this.correspondingConceptLbl = new Label(this.grpDebug, SWT.NONE);
+ this.correspondingConceptLbl.setBackground(GROUP_BACKGROUND_COLOR);
+ this.correspondingConceptLbl.setText("It is related to the following concept:");
+ fd = new FormData();
+ fd.top = new FormAttachment(50, 10);
+ fd.left = new FormAttachment(0, 20);
+ this.correspondingConceptLbl.setLayoutData(fd);
+
+ // Name
+ this.correspondingConceptNameLbl = new Label(this.grpDebug, SWT.NONE);
+ this.correspondingConceptNameLbl.setBackground(GROUP_BACKGROUND_COLOR);
+ this.correspondingConceptNameLbl.setText("Name:");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.correspondingConceptLbl, 5);
+ fd.left = new FormAttachment(0, 70);
+ this.correspondingConceptNameLbl.setLayoutData(fd);
+
+ this.correspondingConceptNameValueLbl = new Label(this.grpDebug, SWT.NONE);
+ this.correspondingConceptNameValueLbl.setBackground(GROUP_BACKGROUND_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.correspondingConceptNameLbl, 0, SWT.TOP);
+ fd.left = new FormAttachment(this.correspondingConceptNameLbl, 70);
+ fd.right = new FormAttachment(100, -20);
+ this.correspondingConceptNameValueLbl.setLayoutData(fd);
+
+ // Id
+ this.correspondingConceptIdLbl = new Label(this.grpDebug, SWT.NONE);
+ this.correspondingConceptIdLbl.setBackground(GROUP_BACKGROUND_COLOR);
+ this.correspondingConceptIdLbl.setText("Id:");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.correspondingConceptNameLbl, 2);
+ fd.left = new FormAttachment(this.correspondingConceptNameLbl, 0, SWT.LEFT);
+ this.correspondingConceptIdLbl.setLayoutData(fd);
+
+ this.correspondingConceptIdValueLbl = new Label(this.grpDebug, SWT.NONE);
+ this.correspondingConceptIdValueLbl.setBackground(GROUP_BACKGROUND_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.correspondingConceptIdLbl, 0, SWT.TOP);
+ fd.left = new FormAttachment(this.correspondingConceptNameValueLbl, 0, SWT.LEFT);
+ fd.right = new FormAttachment(100, -20);
+ this.correspondingConceptIdValueLbl.setLayoutData(fd);
+
+ // Class
+ this.correspondingConceptClassLbl = new Label(this.grpDebug, SWT.NONE);
+ this.correspondingConceptClassLbl.setBackground(GROUP_BACKGROUND_COLOR);
+ this.correspondingConceptClassLbl.setText("Class:");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.correspondingConceptIdLbl, 2);
+ fd.left = new FormAttachment(this.correspondingConceptNameLbl, 0, SWT.LEFT);
+ this.correspondingConceptClassLbl.setLayoutData(fd);
+
+ this.correspondingConceptClassValueLbl = new Label(this.grpDebug, SWT.NONE);
+ this.correspondingConceptClassValueLbl.setBackground(GROUP_BACKGROUND_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.correspondingConceptClassLbl, 0, SWT.TOP);
+ fd.left = new FormAttachment(this.correspondingConceptNameValueLbl, 0, SWT.LEFT);
+ fd.right = new FormAttachment(100, -20);
+ this.correspondingConceptClassValueLbl.setLayoutData(fd);
+
+ this.correspondingConceptDatabaseStatusLbl = new Label(this.grpDebug, SWT.BOLD);
+ this.correspondingConceptDatabaseStatusLbl.setBackground(GROUP_BACKGROUND_COLOR);
+ this.correspondingConceptDatabaseStatusLbl.setText("Database status:");
+ fd = new FormData();
+ fd.top = new FormAttachment(this.correspondingConceptClassLbl, 2);
+ fd.left = new FormAttachment(this.correspondingConceptNameLbl, 0, SWT.LEFT);
+ this.correspondingConceptDatabaseStatusLbl.setLayoutData(fd);
+
+ this.correspondingConceptDatabaseStatusValueLbl = new Label(this.grpDebug, SWT.BOLD);
+ this.correspondingConceptDatabaseStatusValueLbl.setBackground(GROUP_BACKGROUND_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.correspondingConceptDatabaseStatusLbl, 0, SWT.TOP);
+ fd.left = new FormAttachment(this.correspondingConceptNameValueLbl, 0, SWT.LEFT);
+ fd.right = new FormAttachment(100, -20);
+ this.correspondingConceptDatabaseStatusValueLbl.setLayoutData(fd);
+
+ // Table
+ this.correspondingConceptDebugTable = new Table(this.grpDebug, SWT.BORDER | SWT.FULL_SELECTION);
+ this.correspondingConceptDebugTable.setLinesVisible(true);
+ this.correspondingConceptDebugTable.setHeaderVisible(true);
+ this.correspondingConceptDebugTable.setBackground(TABLE_BACKGROUND_COLOR);
+ this.correspondingConceptDebugTable.setHeaderBackground(COMPO_LEFT_COLOR);
+ fd = new FormData();
+ fd.top = new FormAttachment(this.correspondingConceptDatabaseStatusValueLbl, 10);
+ fd.left = new FormAttachment(0, 20);
+ fd.right = new FormAttachment(100, -20);
+ fd.bottom = new FormAttachment(100, -10);
+ this.correspondingConceptDebugTable.setLayoutData(fd);
+
+ column = new TableColumn(this.correspondingConceptDebugTable, SWT.NONE);
+ column.setWidth(100);
+ column = new TableColumn(this.correspondingConceptDebugTable, SWT.CENTER);
+ column.setText("Version");
+ column.setWidth(50);
+ column = new TableColumn(this.correspondingConceptDebugTable, SWT.CENTER);
+ column.setText("Container checksum");
+ column.setWidth(230);
+ column = new TableColumn(this.correspondingConceptDebugTable, SWT.CENTER);
+ column.setText("Checksum");
+ column.setWidth(230);
+ column = new TableColumn(this.correspondingConceptDebugTable, SWT.CENTER);
+ column.setText("Created on");
+ column.setWidth(140);
+ }
+
+ @Override
+ public void run() {
+ super.run();
+
+ try {
+ this.model.countObject(this.selectedObject, true);
+ if ( this.selectedObject instanceof IDiagramModelArchimateComponent )
+ this.model.countObject(((IDiagramModelArchimateComponent)this.selectedObject).getArchimateConcept(), true);
+ } catch (Exception e) {
+ popup(Level.ERROR, "Failed to calculate checksum for selected component.", e);
+ close();
+ return;
+ }
+
+ this.selectedComponentNameValueLbl.setText(this.selectedMetadata.getName());
+ this.selectedComponentIdValueLbl.setText(this.selectedMetadata.getId());
+ this.selectedComponentClassValueLbl.setText(this.selectedObject.getClass().getSimpleName());
+ String imagePath = this.selectedMetadata.getImagePath();
+ if ( imagePath == null ) {
+ this.selectedComponentImagePathLbl.setVisible(false);
+ this.selectedComponentImagePathValueLbl.setVisible(false);
+
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(this.selectedComponentClassLbl, 2);
+ fd.left = new FormAttachment(0, 70);
+ this.selectedComponentDatabaseStatusLbl.setLayoutData(fd);
+ } else {
+ this.selectedComponentImagePathLbl.setVisible(true);
+ this.selectedComponentImagePathValueLbl.setVisible(true);
+
+ FormData fd = new FormData();
+ fd.top = new FormAttachment(this.selectedComponentImagePathLbl, 2);
+ fd.left = new FormAttachment(0, 70);
+ this.selectedComponentDatabaseStatusLbl.setLayoutData(fd);
+ this.selectedComponentImagePathValueLbl.setText(imagePath);
+ }
+
+ this.grpDebug.layout();
+
+ this.selectedComponentDebugTable.removeAll();
+ this.correspondingConceptDebugTable.removeAll();
+
+ if ( this.selectedObject instanceof IDiagramModelArchimateComponent ) {
+ this.correspondingConceptLbl.setVisible(true);
+ this.correspondingConceptNameLbl.setVisible(true);
+ this.correspondingConceptNameValueLbl.setVisible(true);
+ this.correspondingConceptIdLbl.setVisible(true);
+ this.correspondingConceptIdValueLbl.setVisible(true);
+ this.correspondingConceptClassLbl.setVisible(true);
+ this.correspondingConceptClassValueLbl.setVisible(true);
+ this.correspondingConceptDatabaseStatusLbl.setVisible(true);
+ this.correspondingConceptDatabaseStatusValueLbl.setVisible(true);
+ this.correspondingConceptDebugTable.setVisible(true);
+
+ IArchimateConcept concept = ((IDiagramModelArchimateComponent)this.selectedObject).getArchimateConcept();
+ this.correspondingConceptNameValueLbl.setText(concept.getName());
+ this.correspondingConceptIdValueLbl.setText(concept.getId());
+ this.correspondingConceptClassValueLbl.setText(concept.getClass().getSimpleName());
+ } else {
+ this.correspondingConceptLbl.setVisible(false);
+ this.correspondingConceptNameLbl.setVisible(false);
+ this.correspondingConceptNameValueLbl.setVisible(false);
+ this.correspondingConceptIdLbl.setVisible(false);
+ this.correspondingConceptIdValueLbl.setVisible(false);
+ this.correspondingConceptClassLbl.setVisible(false);
+ this.correspondingConceptClassValueLbl.setVisible(false);
+ this.correspondingConceptDatabaseStatusLbl.setVisible(false);
+ this.correspondingConceptDatabaseStatusValueLbl.setVisible(false);
+ this.correspondingConceptDebugTable.setVisible(false);
+ }
+
+ if ( !(this.selectedObject instanceof IDiagramModel) ) {
+ TableColumn column = this.selectedComponentDebugTable.getColumn(2);
+ column.setResizable(false);
+ column.setText("");
+ column.setWidth(0);
+
+ column = this.correspondingConceptDebugTable.getColumn(2);
+ column.setResizable(false);
+ column.setText("");
+ column.setWidth(0);
+ }
+
+ refreshDisplay();
+
+ try {
+ getDatabases(true);
+ } catch (Exception err) {
+ popup(Level.ERROR, "Failed to get the databases.", err);
+ return;
+ }
+ }
+
+ /**
+ * This method is called each time a database is selected and a connection has been established to it.
+ *
+ * It enables the export button and starts the export if the "automatic start" is specified in the plugin preferences
+ */
+ @Override
+ protected void connectedToDatabase(boolean forceCheckDatabase) {
+ this.selectedComponentDebugTable.removeAll();
+ this.correspondingConceptDebugTable.removeAll();
+
+ this.exportConnection = new DBDatabaseExportConnection(getDatabaseConnection());
+
+ // we get the version and checksum from the database
+ try {
+ if ( this.selectedObject instanceof IArchimateModelObject )
+ this.exportConnection.getModelVersionFromDatabase((DBArchimateModel) ((IArchimateModelObject)this.selectedObject).getArchimateModel());
+ else if ( this.selectedObject instanceof IDiagramModelObject )
+ this.exportConnection.getModelVersionFromDatabase((DBArchimateModel) ((IDiagramModelObject)this.selectedObject).getDiagramModel().getArchimateModel());
+ else if ( this.selectedObject instanceof IDiagramModelConnection )
+ this.exportConnection.getModelVersionFromDatabase((DBArchimateModel) ((IDiagramModelConnection)this.selectedObject).getDiagramModel().getArchimateModel());
+
+ if ( this.selectedObject instanceof IDiagramModelArchimateComponent ) {
+ this.exportConnection.getVersionFromDatabase(((IDiagramModelArchimateComponent)this.selectedObject).getDiagramModel());
+ this.exportConnection.getVersionFromDatabase(((IDiagramModelArchimateComponent)this.selectedObject).getArchimateConcept());
+ }
+
+ this.exportConnection.getVersionFromDatabase((IIdentifier)this.selectedObject);
+ } catch (SQLException err) {
+ popup(Level.ERROR, "Failed to get information about component from the database.", err);
+ return;
+ }
+
+ // in case of a view, we check if we need to recreate the screenshot
+ if ( this.selectedObject instanceof IDiagramModel ) {
+ DBMetadata metadata = DBMetadata.getDBMetadata(this.selectedObject);
+ if ( this.connection.getDatabaseEntry().isViewSnapshotRequired() ) {
+ if ( (metadata.getScreenshot().getBytes() == null)
+ || (metadata.getScreenshot().getScaleFactor() != this.connection.getDatabaseEntry().getViewsImagesScaleFactor())
+ || (metadata.getScreenshot().getBodrderWidth() != this.connection.getDatabaseEntry().getViewsImagesBorderWidth())
+ ) {
+ logger.debug("Creating screenshot of view \""+((IDiagramModel)this.selectedObject).getName()+"\"");
+ createImage((IDiagramModel)this.selectedObject, this.connection.getDatabaseEntry().getViewsImagesScaleFactor(), this.connection.getDatabaseEntry().getViewsImagesBorderWidth());
+ }
+ metadata.getScreenshot().setScreenshotActive(true);
+ } else
+ metadata.getScreenshot().setScreenshotActive(false);
+
+ // we recalculate the view checksum
+ try {
+ // we force the presence of the view in the allView map in order to keep the screenshot in the checksum calculation
+ this.model.getAllViews().put(((IDiagramModel)this.selectedObject).getId(), (IDiagramModel)this.selectedObject);
+ this.model.countObject(this.selectedObject, true);
+ } catch (Exception err) {
+ popup(Level.ERROR, "Failed to recalculate view chekcsum.", err);
+ return;
+ }
+ }
+
+ DBMetadata metadata = DBMetadata.getDBMetadata(this.selectedObject);
+
+ this.selectedComponentDatabaseStatusValueLbl.setText(metadata.getDatabaseStatus().toString());
+
+ TableItem item = new TableItem(this.selectedComponentDebugTable, SWT.NONE);
+ item.setText(0, "Initial");
+ item.setText(1, String.valueOf(metadata.getInitialVersion().getVersion()));
+ item.setText(2, metadata.getInitialVersion().getContainerChecksum());
+ item.setText(3, metadata.getInitialVersion().getChecksum());
+ item.setText(4, metadata.getInitialVersion().getTimestamp() == DBVersion.NEVER ? "" : metadata.getInitialVersion().getTimestamp().toString());
+
+ item = new TableItem(this.selectedComponentDebugTable, SWT.NONE);
+ item.setText(0, "Current");
+ item.setText(1, String.valueOf(metadata.getCurrentVersion().getVersion()));
+ item.setText(2, metadata.getCurrentVersion().getContainerChecksum());
+ item.setText(3, metadata.getCurrentVersion().getChecksum());
+ item.setText(4, metadata.getCurrentVersion().getTimestamp() == DBVersion.NEVER ? "" : metadata.getCurrentVersion().getTimestamp().toString());
+
+ item = new TableItem(this.selectedComponentDebugTable, SWT.NONE);
+ item.setText(0, "Database");
+ item.setText(1, String.valueOf(metadata.getDatabaseVersion().getVersion()));
+ item.setText(2, metadata.getDatabaseVersion().getContainerChecksum());
+ item.setText(3, metadata.getDatabaseVersion().getChecksum());
+ item.setText(4, metadata.getDatabaseVersion().getTimestamp() == DBVersion.NEVER ? "" : metadata.getLatestDatabaseVersion().getTimestamp().toString());
+
+ item = new TableItem(this.selectedComponentDebugTable, SWT.NONE);
+ item.setText(0, "Latest database");
+ item.setText(1, String.valueOf(metadata.getLatestDatabaseVersion().getVersion()));
+ item.setText(2, metadata.getLatestDatabaseVersion().getContainerChecksum());
+ item.setText(3, metadata.getLatestDatabaseVersion().getChecksum());
+ item.setText(4, metadata.getLatestDatabaseVersion().getTimestamp() == DBVersion.NEVER ? "" : metadata.getLatestDatabaseVersion().getTimestamp().toString());
+
+ if ( this.selectedObject instanceof IDiagramModelArchimateComponent ) {
+ IArchimateConcept concept = ((IDiagramModelArchimateComponent)this.selectedObject).getArchimateConcept();
+ metadata = DBMetadata.getDBMetadata(concept);
+
+ this.correspondingConceptDatabaseStatusValueLbl.setText(metadata.getDatabaseStatus().toString());
+
+ item = new TableItem(this.correspondingConceptDebugTable, SWT.NONE);
+ item.setText(0, "Initial");
+ item.setText(1, String.valueOf(metadata.getInitialVersion().getVersion()));
+ item.setText(2, metadata.getInitialVersion().getContainerChecksum());
+ item.setText(3, metadata.getInitialVersion().getChecksum());
+ item.setText(4, metadata.getInitialVersion().getTimestamp() == DBVersion.NEVER ? "" : metadata.getInitialVersion().getTimestamp().toString());
+
+ item = new TableItem(this.correspondingConceptDebugTable, SWT.NONE);
+ item.setText(0, "Current");
+ item.setText(1, String.valueOf(metadata.getCurrentVersion().getVersion()));
+ item.setText(2, metadata.getCurrentVersion().getContainerChecksum());
+ item.setText(3, metadata.getCurrentVersion().getChecksum());
+ item.setText(4, metadata.getCurrentVersion().getTimestamp() == DBVersion.NEVER ? "" : metadata.getCurrentVersion().getTimestamp().toString());
+
+ item = new TableItem(this.correspondingConceptDebugTable, SWT.NONE);
+ item.setText(0, "Database");
+ item.setText(1, String.valueOf(metadata.getDatabaseVersion().getVersion()));
+ item.setText(2, metadata.getDatabaseVersion().getContainerChecksum());
+ item.setText(3, metadata.getDatabaseVersion().getChecksum());
+ item.setText(4, metadata.getDatabaseVersion().getTimestamp() == DBVersion.NEVER ? "" : metadata.getDatabaseVersion().getTimestamp().toString());
+
+ item = new TableItem(this.correspondingConceptDebugTable, SWT.NONE);
+ item.setText(0, "Latest database");
+ item.setText(1, String.valueOf(metadata.getLatestDatabaseVersion().getVersion()));
+ item.setText(2, metadata.getLatestDatabaseVersion().getContainerChecksum());
+ item.setText(3, metadata.getLatestDatabaseVersion().getChecksum());
+ item.setText(4, metadata.getLatestDatabaseVersion().getTimestamp() == DBVersion.NEVER ? "" : metadata.getLatestDatabaseVersion().getTimestamp().toString());
+ }
+ }
+
+ @Override
+ public void notConnectedToDatabase() {
+ this.selectedComponentDebugTable.removeAll();
+ this.correspondingConceptDebugTable.removeAll();
+ }
+}
diff --git a/sources/src/org/archicontribs/database/commandline/DBImportModelProvider.java b/sources/src/org/archicontribs/database/commandline/DBImportModelProvider.java
new file mode 100644
index 00000000..f4fc93d4
--- /dev/null
+++ b/sources/src/org/archicontribs/database/commandline/DBImportModelProvider.java
@@ -0,0 +1,175 @@
+package org.archicontribs.database.commandline;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.archicontribs.database.DBLogger;
+import org.archicontribs.database.DBPlugin;
+import org.archicontribs.database.GUI.DBGuiAdminDatabase;
+import org.archicontribs.database.GUI.DBGuiImportModel;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+
+import com.archimatetool.commandline.AbstractCommandLineProvider;
+
+/**
+ * Command Line interface for importing a model from a database
+ *
+ * Typical usage:
+ * Archi [-consoleLog] -application com.archimatetool.commandline.app --import.database "database name" --import.model.name "model name" [--import.model.version "model version"]
+ *
+ * @author Herve Jouin
+ */
+public class DBImportModelProvider extends AbstractCommandLineProvider {
+ protected static final DBLogger logger = new DBLogger(DBGuiAdminDatabase.class);
+
+ static final String PREFIX = "DBPlugin";
+ static final String OPTION_IMPORT_DATABASE = "import.database";
+ static final String OPTION_IMPORT_MODEL = "import.model.name";
+ static final String OPTION_IMPORT_VERSION = "import.model.version";
+
+ /**
+ *
+ */
+ public DBImportModelProvider() {
+
+ }
+
+ @Override
+ public void run(CommandLine commandLine) throws Exception {
+ if(!hasCorrectOptions(commandLine)) {
+ logError("Bad options provided.");
+ return;
+ }
+
+ String databaseName = commandLine.getOptionValue(OPTION_IMPORT_DATABASE);
+ String modelName = commandLine.getOptionValue(OPTION_IMPORT_MODEL);
+ int modelVersion = 0;
+
+ try {
+ modelVersion = Integer.valueOf(commandLine.getOptionValue(OPTION_IMPORT_VERSION));
+ } catch (@SuppressWarnings("unused") NumberFormatException ign) {
+ if ( commandLine.hasOption("abortOnException") ) {
+ logError("Option "+OPTION_IMPORT_MODEL+" should be a number.");
+ return;
+ }
+ logMessage("Option "+OPTION_IMPORT_MODEL+" should be a number. Defaulting to zero (latest version of the model will be imported)");
+ }
+
+ if ( commandLine.hasOption(OPTION_IMPORT_VERSION) )
+ logMessage("*** Importing version "+modelVersion+" of model \""+modelName+"\" from the database \""+databaseName+"\"");
+ else
+ logMessage("*** Importing latest version "+modelVersion+" of model \""+modelName+"\" from the database \""+databaseName+"\"");
+
+
+ logMessage("Creating DBGuiImportModel window ...");
+ DBGuiImportModel guiImportModel = new DBGuiImportModel("Import model", databaseName);
+
+ logMessage("Checking if database \""+databaseName+"\" is selected");
+ int idx = guiImportModel.getComboDatabases().getSelectionIndex();
+ if ( idx == -1 ) {
+ guiImportModel.close();
+ logError("Unknown database \""+databaseName+"\"");
+ return;
+ }
+
+ String databaseSelected = guiImportModel.getComboDatabases().getItem(idx);
+ if ( !DBPlugin.areEqual(databaseSelected, databaseName) ) {
+ guiImportModel.close();
+ logError("Database \""+databaseSelected+"\" is selected instead of \""+databaseName+"\"");
+ return;
+ }
+
+ logMessage("Selecting model \""+modelName+"\"");
+ boolean modelSelected = false;
+ Table tblModels = guiImportModel.getTblModels();
+ for (int i = 0; i < tblModels.getItemCount(); ++i) {
+ TableItem item = tblModels.getItem(i);
+ if ( DBPlugin.areEqual(item.getText(0), modelName)) {
+ tblModels.select(i);
+ modelSelected = true;
+ break;
+ }
+ }
+ if ( !modelSelected ) {
+ guiImportModel.close();
+ logError("Model \""+modelName+"\" not found in the database.");
+ return;
+ }
+
+ if ( modelVersion != 0 ) {
+ logMessage("Selecting model version \""+modelVersion+"\"");
+ String modelVersionStr = String.valueOf(modelVersion);
+ Boolean versionSelected = false;
+ Table tblVersions = guiImportModel.getTblModelVersions();
+ for (int i = 0; i < tblVersions.getItemCount(); ++i) {
+ TableItem item = tblVersions.getItem(i);
+ if ( DBPlugin.areEqual(item.getText(0), modelVersionStr)) {
+ tblVersions.select(i);
+ versionSelected = true;
+ break;
+ }
+ }
+ if ( !versionSelected ) {
+ guiImportModel.close();
+ logError("Model version\""+modelVersion+"\" not found in the database.");
+ return;
+ }
+ }
+
+ logMessage("Importing model");
+ guiImportModel.doImport();
+
+ logMessage("Closing GUI");
+ guiImportModel.close();
+
+ if ( modelVersion != 0 )
+ logMessage("*** Model \""+modelName+"\" imported.");
+ else
+ logMessage("*** Model \""+modelName+"\" version \""+modelVersion+"\" imported.");
+ }
+
+ @Override
+ public Options getOptions() {
+ Options options = new Options();
+
+ Option option = Option.builder()
+ .longOpt(OPTION_IMPORT_DATABASE)
+ .hasArg().argName("database")
+ .desc("Name of the database (should already be configured in Archi through the database plugin preferences page)")
+ .build();
+ options.addOption(option);
+
+ option = Option.builder()
+ .longOpt(OPTION_IMPORT_MODEL)
+ .hasArg().argName("modelName")
+ .desc("Specifies the name of the model to import")
+ .build();
+ options.addOption(option);
+
+ option = Option.builder()
+ .longOpt(OPTION_IMPORT_VERSION)
+ .hasArg().argName("modelVersion")
+ .desc("Specifies the version of the model to import (if not specified, the latest version of the model will be imported)")
+ .build();
+ options.addOption(option);
+
+ return options;
+ }
+
+ @SuppressWarnings("static-method")
+ private boolean hasCorrectOptions(CommandLine commandLine) {
+ return commandLine.hasOption(OPTION_IMPORT_DATABASE) && !DBPlugin.isEmpty(commandLine.getOptionValue(OPTION_IMPORT_DATABASE))
+ && commandLine.hasOption(OPTION_IMPORT_MODEL) && !DBPlugin.isEmpty(commandLine.getOptionValue(OPTION_IMPORT_MODEL));
+ }
+
+ @Override
+ public int getPriority() {
+ return PRIORITY_IMPORT;
+ }
+
+ @Override
+ protected String getLogPrefix() {
+ return PREFIX;
+ }
+}
diff --git a/sources/src/org/archicontribs/database/connection/DBDatabaseConnection.java b/sources/src/org/archicontribs/database/connection/DBDatabaseConnection.java
new file mode 100644
index 00000000..15a4694e
--- /dev/null
+++ b/sources/src/org/archicontribs/database/connection/DBDatabaseConnection.java
@@ -0,0 +1,1844 @@
+/**
+ * This program and the accompanying materials
+ * are made available under the terms of the License
+ * which accompanies this distribution in the file LICENSE.txt
+ */
+
+package org.archicontribs.database.connection;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Savepoint;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+
+import org.apache.log4j.Level;
+import org.archicontribs.database.DBColumn;
+import org.archicontribs.database.DBColumnType;
+import org.archicontribs.database.DBDatabaseEntry;
+import org.archicontribs.database.DBLogger;
+import org.archicontribs.database.DBPlugin;
+import org.archicontribs.database.DBTable;
+import org.archicontribs.database.GUI.DBGui;
+import org.archicontribs.database.data.DBChecksum;
+import org.archicontribs.database.data.DBDatabase;
+import org.archicontribs.database.data.DBImportMode;
+import org.archicontribs.database.model.DBArchimateModel;
+import org.archicontribs.database.model.DBMetadata;
+import org.archicontribs.database.model.commands.DBImportViewFromIdCommand;
+import com.archimatetool.model.IDiagramModel;
+import com.archimatetool.model.IDiagramModelContainer;
+import com.archimatetool.model.IDiagramModelObject;
+
+import lombok.Getter;
+
+
+/**
+ * This class holds the information required to connect to, to import from and export to a database
+ *
+ * @author Herve Jouin
+ */
+public class DBDatabaseConnection implements AutoCloseable {
+ private static final DBLogger logger = new DBLogger(DBDatabaseConnection.class);
+
+ /**
+ * Version of the expected database model.
+ * If the value found into the columns version of the table "database_version", then the plugin will try to upgrade the datamodel.
+ */
+ public static final int databaseVersion = 490;
+
+ /**
+ * the databaseEntry corresponding to the connection
+ */
+ @Getter DBDatabaseEntry databaseEntry = null;
+
+ /**
+ * the name of the schema
+ */
+ @Getter protected String schema = "";
+
+ /**
+ * the name of the schema suffixed by a '.' if not empty
+ */
+ @Getter protected String schemaPrefix = "";
+
+ /**
+ * Connection to the database
+ */
+ @Getter protected Connection connection = null;
+
+
+ /**
+ * Configuration of the database tables
+ */
+ @Getter private List databaseVersionColumns = null;
+ @Getter private List databaseVersionPrimaryKeys = null;
+
+ @Getter private List modelsColumns = null;
+ @Getter private List modelsPrimaryKeys = null;
+
+ @Getter private List foldersColumns = null;
+ @Getter private List foldersPrimaryKeys = null;
+ @Getter private List foldersInModelColumns = null;
+ @Getter private List foldersInModelPrimaryKeys = null;
+
+ @Getter private List elementsColumns = null;
+ @Getter private List elementsPrimaryKeys = null;
+ @Getter private List elementsInModelColumns = null;
+ @Getter private List elementsInModelPrimaryKeys = null;
+
+ @Getter private List relationshipsColumns = null;
+ @Getter private List relationshipsPrimaryKeys = null;
+ @Getter private List relationshipsInModelColumns = null;
+ @Getter private List relationshipsInModelPrimaryKeys = null;
+
+ @Getter private List viewsColumns = null;
+ @Getter private List viewsPrimaryKeys = null;
+ @Getter private List viewsInModelColumns = null;
+ @Getter private List viewsInModelPrimaryKeys = null;
+
+ @Getter private List viewsObjectsColumns = null;
+ @Getter private List viewsObjectsPrimaryKeys = null;
+ @Getter private List viewsObjectsInViewColumns = null;
+ @Getter private List viewsObjectsInViewPrimaryKeys = null;
+
+ @Getter private List viewsConnectionsColumns = null;
+ @Getter private List viewsConnectionsPrimaryKeys = null;
+ @Getter private List viewsConnectionsInViewColumns = null;
+ @Getter private List viewsConnectionsInViewPrimaryKeys = null;
+
+ @Getter private List propertiesColumns = null;
+ @Getter private List propertiesPrimaryKeys = null;
+
+ @Getter private List featuresColumns = null;
+ @Getter private List featuresPrimaryKeys = null;
+
+ @Getter private List profilesColumns = null;
+ @Getter private List profilesPrimaryKeys = null;
+
+ @Getter private List profilesInModelColumns = null;
+ @Getter private List profilesInModelPrimaryKeys = null;
+
+ @Getter private List bendpointsColumns = null;
+ @Getter private List bendpointsPrimaryKeys = null;
+
+ @Getter private List metadataColumns = null;
+ @Getter private List metadataPrimaryKeys = null;
+
+ @Getter private List imagesColumns = null;
+ @Getter private List imagesPrimaryKeys = null;
+
+ @Getter private List databaseTables = null;
+
+ /**
+ * Opens a connection to a JDBC database using all the connection details
+ * @param dbEntry class containing the details of the database to connect to
+ * @throws SQLException
+ */
+ protected DBDatabaseConnection(DBDatabaseEntry dbEntry) throws SQLException {
+ assert(this.databaseEntry != null);
+ this.databaseEntry = dbEntry;
+ openConnection();
+ }
+
+ /**
+ * Used to switch between ImportConnection and ExportConnection.
+ */
+ protected DBDatabaseConnection() {
+ if ( this.databaseEntry != null ) {
+ this.schema = this.databaseEntry.getSchema();
+ this.schemaPrefix = this.databaseEntry.getSchemaPrefix();
+ }
+ }
+
+ private void openConnection() throws SQLException {
+ if ( isConnected() )
+ close();
+
+ if ( logger.isDebugEnabled() ) logger.debug("Opening connection to database "+this.databaseEntry.getName()+": driver="+this.databaseEntry.getDriver()+", server="+this.databaseEntry.getServer()+", port="+this.databaseEntry.getPort()+", database="+this.databaseEntry.getDatabase()+", schema="+this.schema+", username="+this.databaseEntry.getUsername());
+
+ String clazz = this.databaseEntry.getDriverClass();
+ if ( logger.isDebugEnabled() ) logger.debug("JDBC class = " + clazz);
+
+ String connectionString = this.databaseEntry.getJdbcConnectionString();
+ if ( logger.isDebugEnabled() ) logger.debug("JDBC connection string = " + connectionString);
+
+ this.schema = this.databaseEntry.getSchema();
+ this.schemaPrefix = this.databaseEntry.getSchemaPrefix();
+
+ try {
+ // we load the jdbc class
+ Class.forName(clazz);
+ String driver = this.databaseEntry.getDriver();
+ String username = this.databaseEntry.getUsername();
+ String encryptedPassword = this.databaseEntry.getEncryptedPassword();
+ String password = "";
+
+ if ( DBPlugin.isEmpty(username) ) {
+ if ( !DBPlugin.isEmpty(encryptedPassword) )
+ throw new SQLException("A password has been provided without a username.");
+ } else {
+ try {
+ password = this.databaseEntry.getDecryptedPassword();
+ } catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException | NoSuchAlgorithmException | NoSuchPaddingException err) {
+ DBGui.popup(Level.ERROR, "Failed to decrypt the password.", err);
+ }
+
+ // if the username is set but not the password, then we show a popup to ask for the password
+ if ( DBPlugin.isEmpty(password) ) {
+ password = DBGui.passwordDialog("Please provide the database password", "Database password:");
+ if ( password == null ) {
+ // password is null if the user clicked on cancel
+ throw new SQLException("No password provided.");
+ }
+ // we register the new password for the current session
+ try {
+ this.databaseEntry.setDecryptedPassword(password);
+ } catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException | NoSuchAlgorithmException | NoSuchPaddingException err) {
+ DBGui.popup(Level.ERROR, "Failed to decrypt the password.", err);
+ }
+ }
+ }
+
+ if ( DBPlugin.areEqual(driver, DBDatabase.MSSQL.getDriverName()) && DBPlugin.isEmpty(username) && DBPlugin.isEmpty(password) ) {
+ if ( logger.isDebugEnabled() ) logger.debug("Connecting with Windows integrated security");
+ this.connection = DriverManager.getConnection(connectionString);
+ } else {
+ if ( logger.isDebugEnabled() ) logger.debug("Connecting with username = "+username);
+ this.connection = DriverManager.getConnection(connectionString, username, password);
+ }
+ } catch (SQLException e) {
+ // if the JDBC driver fails to connect to the database using the specified driver, then it tries with all the other drivers
+ // and the exception is raised by the latest driver (log4j in our case)
+ // so we need to trap this exception and change the error message
+ // For JDBC people, this is not a bug but a functionality :(
+ if ( DBPlugin.areEqual(e.getMessage(), "JDBC URL is not correct.\nA valid URL format is: 'jdbc:neo4j:http://:'") ) {
+ if ( this.databaseEntry.getDriver().equals(DBDatabase.MSSQL.getDriverName()) ) // if SQL Server, we update the message for integrated authentication
+ throw new SQLException("Please verify the database configuration in the preferences.\n\nPlease also check that you installed the \"sqljdbc_auth.dll\" file in the JRE bin folder to enable the SQL Server integrated security mode.");
+ throw new SQLException("Please verify the database configuration in the preferences.");
+ }
+ throw e;
+ } catch (ClassNotFoundException e) {
+ throw new SQLException(e);
+ }
+
+ if ( logger.isDebugEnabled() ) {
+ if ( DBPlugin.isEmpty(this.schema) )
+ logger.debug("Will use default schema ");
+ else
+ logger.debug("Will use schema "+this.schema);
+ }
+
+
+ }
+
+ /**
+ * Closes connection to the database
+ * The current transaction must be committed or rolled back before the close.
+ */
+ @Override
+ public void close() throws SQLException {
+ if ( this.connection == null || this.connection.isClosed() ) {
+ if ( logger.isDebugEnabled() ) logger.debug("The database connection is already closed.");
+ } else {
+ if ( logger.isDebugEnabled() ) logger.debug("Closing the database connection.");
+ this.connection.close();
+ }
+
+ this.connection = null;
+ this.databaseEntry = null;
+ this.schema = "";
+ this.schemaPrefix = "";
+ }
+
+ /**
+ * Gets the status of the database connection. You may also be interested in {@link #isConnected()}
+ * @return true if the connection is connected, false if the connection is closed
+ * @throws SQLException
+ */
+ public boolean isConnected() throws SQLException {
+ return this.connection != null && !this.connection.isClosed();
+ }
+
+ /**
+ * Gets the status of the database connection. You may also be interested in {@link #isConnected()}
+ * @return true if the connection is closed, false if the connection is connected
+ * @throws SQLException
+ */
+ public boolean isClosed() throws SQLException {
+ return (this.connection == null) || this.connection.isClosed();
+ }
+
+ /**
+ * Checks the content of the "database_version" table
+ * @param dbGui the dialog that holds the graphical interface
+ * @return
+ * @throws Exception
+ * @returns true if the database version is correct, generates an Exception if not
+ */
+ public boolean checkDatabase(DBGui dbGui) throws Exception {
+ // No tables to be checked in Neo4J databases
+ if ( this.databaseEntry.getDriver().equals(DBDatabase.NEO4J.getDriverName()) )
+ return true;
+
+ if ( logger.isTraceEnabled() ) logger.trace("Checking \""+this.schemaPrefix+"database_version\" table");
+
+ int currentVersion = 0;
+ try ( DBSelect result = new DBSelect(this.databaseEntry.getName(), this.connection, "SELECT version FROM "+this.schemaPrefix+"database_version WHERE archi_plugin = ?", DBPlugin.pluginName) ) {
+ result.next();
+ currentVersion = result.getInt("version");
+ } catch (@SuppressWarnings("unused") SQLException err) {
+ // if the table does not exist
+ if ( !DBGui.question("We successfully connected to the database but it seems that it has not been initialized.\n\nDo you wish to intialize the database ?") )
+ throw new SQLException("Database not initialized.");
+
+ createTables(dbGui);
+ currentVersion = databaseVersion;
+ }
+
+ if ( (currentVersion < 200) || (currentVersion > databaseVersion) )
+ throw new SQLException("The database has got an unknown model version (is "+currentVersion+" but should be between 200 and "+databaseVersion+")");
+
+ if ( currentVersion != databaseVersion ) {
+ if ( DBGui.question("The database needs to be upgraded. You will not loose any data during this operation.\n\nDo you wish to upgrade your database ?") ) {
+ upgradeDatabase(currentVersion);
+ DBGui.popup(Level.INFO, "Database successfully upgraded.");
+ }
+ else
+ throw new SQLException("The database needs to be upgraded.");
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks the database structure
+ * @param dbGui the dialog that holds the graphical interface
+ * @return
+ * @throws Exception
+ * @returns true if the database structure is correct, false if not
+ */
+ public String checkDatabaseStructure(DBGui dbGui) throws Exception {
+ StringBuilder message = new StringBuilder();
+ boolean isDatabaseStructureCorrect = true;
+
+ this.schema = this.databaseEntry.getSchema();
+ this.schemaPrefix = this.databaseEntry.getSchemaPrefix();
+
+ if ( DBPlugin.areEqual(this.databaseEntry.getDriver(), DBDatabase.NEO4J.getDriverName()) ) {
+ // do not need to create tables
+ // shouldn't be here anyway if Neo4J database
+ return null;
+ }
+
+ try {
+ if ( dbGui != null )
+ dbGui.setMessage("Checking the database structure...");
+ else
+ DBGui.popup("Checking the database structure...");
+
+ if ( !isConnected() )
+ openConnection();
+
+ // checking if the database_version table exists
+ checkDatabase(dbGui);
+
+
+ // we check after the eventual database upgrade as database before version 212 did not have an ID
+ String databaseId = "";
+ try (DBSelect result = new DBSelect(this.databaseEntry.getName(), this.connection, "SELECT id FROM "+this.schemaPrefix+"database_version WHERE archi_plugin = ?", DBPlugin.pluginName) ) {
+ result.next();
+ databaseId = result.getString("id");
+ } // the "try" manages the result closure even in case of an exception
+
+ if ( !this.databaseEntry.getId().equals(databaseId) ) {
+ logger.info("The database ID is \""+databaseId+"\" whereas the Id we knew was \""+this.databaseEntry.getId()+"\"... Updating the databaseEntry.");
+ this.databaseEntry.setId(databaseId);
+ this.databaseEntry.persistIntoPreferenceStore();
+ }
+
+ logger.debug("Getting metadata from database connection.");
+ DatabaseMetaData metadata = this.connection.getMetaData();
+ boolean mustCheckNotNullConstraint = DBPlugin.INSTANCE.getPreferenceStore().getBoolean("checkNotNullConstraints");
+ boolean hasGotNotNullErrorsOnly = true;
+
+ initializeDatabaseTables();
+
+ // we check that all the columns in the table are expected
+ for (int t = 0; t < this.databaseTables.size() ; ++t ) {
+ String tableName = this.databaseTables.get(t).getName();
+ // oracle requires uppercase table names
+ if ( this.databaseEntry.getDriver().equals("oracle") ) {
+ tableName = tableName.toUpperCase();
+ this.schema = this.schema.toUpperCase();
+ this.schemaPrefix = this.schemaPrefix.toUpperCase();
+ }
+ List expectedColumns = this.databaseTables.get(t).getColumns();
+
+ try (ResultSet result = metadata.getColumns(null, DBPlugin.isEmpty(this.schema) ? null : this.schema.toUpperCase(), tableName, null)) {
+ boolean isTableCorrect = true;
+
+ logger.debug("Table "+this.schemaPrefix+tableName);
+
+ // we reset the columns metadata
+ for (Iterator iterator = expectedColumns.iterator(); iterator.hasNext(); ) {
+ DBColumn expectedColumn = iterator.next();
+ expectedColumn.setMetadata(null);
+ }
+
+ while( result.next() ) {
+ // we check that the table columns have got the right type
+ String columnName = result.getString("COLUMN_NAME");
+ for (Iterator iterator = expectedColumns.iterator(); iterator.hasNext(); ) {
+ DBColumn expectedColumn = iterator.next();
+ if ( columnName.equalsIgnoreCase(expectedColumn.getName()) ) {
+ DBColumn columnInTable = new DBColumn(columnName, result.getString("TYPE_NAME"), result.getInt("COLUMN_SIZE"), result.getInt("NULLABLE")==0);
+
+ if ( columnInTable.equals(expectedColumn) )
+ logger.debug(" Column "+columnInTable.toString()+" is correct");
+ else {
+ if ( columnInTable.getType().equalsIgnoreCase(expectedColumn.getType()) ) {
+ if ( mustCheckNotNullConstraint ) {
+ logger.debug(" Column "+columnInTable.getName()+": should be NOT NULL");
+ if ( isTableCorrect ) {
+ isTableCorrect = false;
+ message.append("\nTable "+this.schemaPrefix+tableName);
+ }
+ message.append("\n Column "+columnInTable.getName()+": should be NOT NULL");
+ } else
+ logger.debug(" Column "+columnInTable.getName()+": should be NOT NULL (ignored)");
+ } else {
+ logger.debug(" Column "+columnInTable.toString()+", but should be "+expectedColumn.getFullType());
+ if ( isTableCorrect ) {
+ isTableCorrect = false;
+ message.append("\nTable "+this.schemaPrefix+tableName);
+ }
+ message.append("\n Column "+columnInTable.toString()+", but should be "+expectedColumn.getFullType());
+ hasGotNotNullErrorsOnly = false;
+ }
+ }
+ expectedColumn.setMetadata(1);
+ break;
+ }
+ }
+ }
+
+ // Now, we check that all the expected columns have been found
+ for (Iterator iterator = expectedColumns.iterator(); iterator.hasNext(); ) {
+ DBColumn expectedColumn = iterator.next();
+ if ( expectedColumn.getMetadata() == null ) {
+ if ( isTableCorrect ) {
+ isTableCorrect = false;
+ message.append("\nTable "+this.schemaPrefix+tableName);
+ }
+ logger.debug(" Column "+expectedColumn.toString()+" is missing");
+ message.append("\n Column "+expectedColumn.toString()+" is missing");
+ hasGotNotNullErrorsOnly = false;
+ }
+ }
+
+ if ( !isTableCorrect )
+ isDatabaseStructureCorrect = false;
+ } catch (SQLException err) {
+ throw err;
+ }
+
+ /* TODO; check primary keys
+ logger.debug(" checking primary keys");
+ try (ResultSet result = metadata.getPrimaryKeys(null, this.schema, tableName)) {
+ while( result.next() ) {
+ String indexName = result.getString("COLUMN_NAME");
+ logger.debug(" found column "+indexName+" in primary key");
+ }
+ } catch (SQLException err) {
+ DBGui.popup(Level.ERROR, "Failed to get table primary keys.", err);
+ return;
+ }
+ */
+ }
+
+ if ( hasGotNotNullErrorsOnly )
+ message.append("\n\nYou may uncheck the \"Check for NOT NULL\" option in the plugin preferences pages should you wish to use this database.");
+
+ } catch (Exception err) {
+ rollback();
+ throw err;
+ } finally {
+ if ( dbGui != null )
+ dbGui.closeMessage();
+ else
+ DBGui.closePopup();
+ }
+
+ if ( dbGui != null ) {
+ if ( !isDatabaseStructureCorrect )
+ DBGui.popup(Level.WARN, "You may have a look to the following items in your database:\n" + message.toString());
+ else
+ DBGui.popup(Level.INFO, "Tables name successfully checked.\nColumns name and type successfully checked");
+ }
+
+ if ( isDatabaseStructureCorrect )
+ return null;
+ return message.toString();
+ }
+
+ /**
+ * Creates the necessary tables in the database
+ * @param dbGui
+ * @throws SQLException
+ */
+ private void createTables(DBGui dbGui) throws SQLException {
+ //final String[] databaseVersionColumns = {"id", "archi_plugin", "version"};
+
+ try {
+
+ if ( dbGui != null )
+ dbGui.setMessage("Creating necessary database tables ...");
+ else
+ DBGui.popup("Creating necessary database tables ...");
+
+ if ( !isConnected() )
+ openConnection();
+
+ setAutoCommit(false);
+
+ initializeDatabaseTables();
+
+ for ( int i = 0 ; i < this.databaseTables.size() ; ++i ) {
+ DBTable table = this.databaseTables.get(i);
+ if ( logger.isDebugEnabled() ) logger.debug("Creating table "+table.getFullName());
+ executeRequest(table.generateCreateStatement());
+ }
+
+ // we fill in the database_version table
+ insert(this.schemaPrefix+"database_version", DBColumn.getColumnNames(this.databaseVersionColumns), DBPlugin.createID(null), DBPlugin.pluginName, databaseVersion);
+
+ // Oracle do not implement AUTO_INCREMENT columns, so we have to manually create sequences and triggers
+ if ( DBPlugin.areEqual(this.databaseEntry.getDriver(), DBDatabase.ORACLE.getDriverName()) ) {
+ if ( logger.isDebugEnabled() ) logger.debug("Creating sequence "+this.schemaPrefix+"seq_elements");
+ executeRequest("BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "+this.schemaPrefix+"seq_elements_in_model'; EXCEPTION WHEN OTHERS THEN NULL; END;");
+ executeRequest("CREATE SEQUENCE "+this.schemaPrefix+"seq_elements_in_model START WITH 1 INCREMENT BY 1 CACHE 100");
+
+ if ( logger.isDebugEnabled() ) logger.debug("Creating trigger "+this.schemaPrefix+"trigger_elements_in_model");
+ executeRequest("CREATE OR REPLACE TRIGGER "+this.schemaPrefix+"trigger_elements_in_model "
+ + "BEFORE INSERT ON "+this.schemaPrefix+"elements_in_model "
+ + "FOR EACH ROW "
+ + "BEGIN"
+ + " SELECT "+this.schemaPrefix+"seq_elements_in_model.NEXTVAL INTO :NEW.eim_id FROM DUAL;"
+ + "END;");
+
+ if ( logger.isDebugEnabled() ) logger.debug("Creating sequence "+this.schemaPrefix+"seq_folders_in_model");
+ executeRequest("BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "+this.schemaPrefix+"seq_folders_in_model'; EXCEPTION WHEN OTHERS THEN NULL; END;");
+ executeRequest("CREATE SEQUENCE "+this.schemaPrefix+"seq_folders_in_model START WITH 1 INCREMENT BY 1 CACHE 100");
+
+ if ( logger.isDebugEnabled() ) logger.debug("Creating trigger "+this.schemaPrefix+"trigger_folders_in_model");
+ executeRequest("CREATE OR REPLACE TRIGGER "+this.schemaPrefix+"trigger_folders_in_model "
+ + "BEFORE INSERT ON "+this.schemaPrefix+"folders_in_model "
+ + "FOR EACH ROW "
+ + "BEGIN"
+ + " SELECT "+this.schemaPrefix+"seq_folders_in_model.NEXTVAL INTO :NEW.fim_id FROM DUAL;"
+ + "END;");
+
+ if ( logger.isDebugEnabled() ) logger.debug("Creating sequence "+this.schemaPrefix+"seq_relationships");
+ executeRequest("BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "+this.schemaPrefix+"seq_relationships_in_model'; EXCEPTION WHEN OTHERS THEN NULL; END;");
+ executeRequest("CREATE SEQUENCE "+this.schemaPrefix+"seq_relationships_in_model START WITH 1 INCREMENT BY 1 CACHE 100");
+
+ if ( logger.isDebugEnabled() ) logger.debug("Creating trigger "+this.schemaPrefix+"trigger_relationships_in_model");
+ executeRequest("CREATE OR REPLACE TRIGGER "+this.schemaPrefix+"trigger_relationships_in_model "
+ + "BEFORE INSERT ON "+this.schemaPrefix+"relationships_in_model "
+ + "FOR EACH ROW "
+ + "BEGIN"
+ + " SELECT "+this.schemaPrefix+"seq_relationships_in_model.NEXTVAL INTO :NEW.rim_id FROM DUAL;"
+ + "END;");
+
+ if ( logger.isDebugEnabled() ) logger.debug("Creating sequence "+this.schemaPrefix+"seq_connections_in_view");
+ executeRequest("BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "+this.schemaPrefix+"seq_connections_in_view'; EXCEPTION WHEN OTHERS THEN NULL; END;");
+ executeRequest("CREATE SEQUENCE "+this.schemaPrefix+"seq_connections_in_view START WITH 1 INCREMENT BY 1 CACHE 100");
+
+ if ( logger.isDebugEnabled() ) logger.debug("Creating trigger "+this.schemaPrefix+"trigger_connections_in_view");
+ executeRequest("CREATE OR REPLACE TRIGGER "+this.schemaPrefix+"trigger_connections_in_view "
+ + "BEFORE INSERT ON "+this.schemaPrefix+"views_connections_in_view "
+ + "FOR EACH ROW "
+ + "BEGIN"
+ + " SELECT "+this.schemaPrefix+"seq_connections_in_view.NEXTVAL INTO :NEW.civ_id FROM DUAL;"
+ + "END;");
+
+ if ( logger.isDebugEnabled() ) logger.debug("Creating sequence "+this.schemaPrefix+"seq_views");
+ executeRequest("BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "+this.schemaPrefix+"seq_views_in_model'; EXCEPTION WHEN OTHERS THEN NULL; END;");
+ executeRequest("CREATE SEQUENCE "+this.schemaPrefix+"seq_views_in_model START WITH 1 INCREMENT BY 1 CACHE 100");
+
+ if ( logger.isDebugEnabled() ) logger.debug("Creating trigger "+this.schemaPrefix+"trigger_views_in_model");
+ executeRequest("CREATE OR REPLACE TRIGGER "+this.schemaPrefix+"trigger_views_in_model "
+ + "BEFORE INSERT ON "+this.schemaPrefix+"views_in_model "
+ + "FOR EACH ROW "
+ + "BEGIN"
+ + " SELECT "+this.schemaPrefix+"seq_views_in_model.NEXTVAL INTO :NEW.vim_id FROM DUAL;"
+ + "END;");
+
+ if ( logger.isDebugEnabled() ) logger.debug("Creating sequence "+this.schemaPrefix+"seq_objects_in_view");
+ executeRequest("BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "+this.schemaPrefix+"seq_objects_in_view'; EXCEPTION WHEN OTHERS THEN NULL; END;");
+ executeRequest("CREATE SEQUENCE "+this.schemaPrefix+"seq_objects_in_view START WITH 1 INCREMENT BY 1 CACHE 100");
+
+ if ( logger.isDebugEnabled() ) logger.debug("Creating trigger "+this.schemaPrefix+"trigger_objects_in_view");
+ executeRequest("CREATE OR REPLACE TRIGGER "+this.schemaPrefix+"trigger_objects_in_view "
+ + "BEFORE INSERT ON "+this.schemaPrefix+"views_objects_in_view "
+ + "FOR EACH ROW "
+ + "BEGIN"
+ + " SELECT "+this.schemaPrefix+"seq_objects_in_view.NEXTVAL INTO :NEW.oiv_id FROM DUAL;"
+ + "END;");
+ }
+
+ commit();
+ setAutoCommit(true);
+
+ DBGui.popup(Level.INFO,"The database has been successfully initialized.");
+
+ } catch (SQLException err) {
+ rollback();
+ setAutoCommit(true);
+ throw err;
+ } finally {
+ if ( dbGui != null )
+ dbGui.closeMessage();
+ else
+ DBGui.closePopup();
+ }
+
+ }
+
+ /**
+ * @param tableName
+ * @throws SQLException
+ */
+ public void dropTableIfExists(String tableName) throws SQLException {
+ if ( logger.isDebugEnabled() ) logger.debug("Dropping table "+tableName+" if it exists");
+
+ if ( DBPlugin.areEqual(this.databaseEntry.getDriver(), DBDatabase.ORACLE.getDriverName()) )
+ executeRequest("BEGIN EXECUTE IMMEDIATE 'DROP TABLE "+tableName+"'; EXCEPTION WHEN OTHERS THEN NULL; END;");
+ else if ( DBPlugin.areEqual(this.databaseEntry.getDriver(), DBDatabase.MSSQL.getDriverName()) )
+ executeRequest("IF OBJECT_ID('"+tableName+"', 'U') IS NOT NULL DROP TABLE "+tableName);
+ else
+ executeRequest("DROP TABLE IF EXISTS "+tableName);
+ }
+
+ /**
+ * @param tableName
+ * @param columnName
+ * @throws SQLException
+ */
+ public void dropColumn(String tableName, String columnName) throws SQLException {
+ if ( logger.isDebugEnabled() ) logger.debug("Altering table "+tableName+", dropping column "+columnName);
+
+ // sqlite has got very limited alter table support. Especially, it does not allow to drop a column
+ if ( !DBPlugin.areEqual(this.databaseEntry.getDriver(), DBDatabase.SQLITE.getDriverName()) ) {
+ StringBuilder requestString = new StringBuilder();
+ requestString.append("ALTER TABLE ");
+ requestString.append(tableName);
+ if ( DBPlugin.areEqual(this.databaseEntry.getDriver(), DBDatabase.MYSQL.getDriverName()) )
+ requestString.append(" DROP ");
+ else
+ requestString.append(" DROP COLUMN ");
+ requestString.append(columnName);
+
+ executeRequest(requestString.toString());
+ } else {
+ StringBuilder createTableRequest = new StringBuilder();
+ StringBuilder columnNames = new StringBuilder();
+ StringBuilder primaryKeys = new StringBuilder();
+
+ // just in case
+ dropTableIfExists(tableName+"_old");
+
+ String tableInfoRequest = "PRAGMA TABLE_INFO("+tableName+")";
+ try (PreparedStatement pstmt = this.connection.prepareStatement(tableInfoRequest, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY) ) {
+ if ( logger.isTraceSQLEnabled() ) logger.trace(" --> "+tableInfoRequest);
+ try (ResultSet result = pstmt.executeQuery() ) {
+ createTableRequest.append("CREATE TABLE "+tableName+" (");
+ boolean columnsNeedComma = false;
+ boolean primaryKeysNeedComma = false;
+ while ( result.next() ) {
+ // if the column is not the column to drop, then we create it
+ if ( !DBPlugin.areEqual(columnName, result.getString("name")) ) {
+ if ( columnsNeedComma ) {
+ createTableRequest.append(", ");
+ columnNames.append(", ");
+ }
+ createTableRequest.append(result.getString("name"));
+ createTableRequest.append(" ");
+ createTableRequest.append(result.getString("type"));
+
+ columnNames.append(result.getString("name"));
+
+ columnsNeedComma = true;
+ }
+
+ if ( result.getInt("pk") != 0 ) {
+ if ( primaryKeysNeedComma ) {
+ primaryKeys.append(", ");
+ }
+ primaryKeys.append(result.getString("name"));
+ primaryKeysNeedComma = true;
+ }
+ }
+ if ( primaryKeys.length() != 0 ) {
+ createTableRequest.append(", PRIMARY KEY (");
+ createTableRequest.append(primaryKeys.toString());
+ createTableRequest.append(")");
+ }
+
+ createTableRequest.append(")");
+ }
+ }
+
+ executeRequest("ALTER TABLE "+tableName+" RENAME TO "+tableName+"_old");
+ executeRequest(createTableRequest.toString());
+ executeRequest("INSERT INTO "+tableName+" SELECT "+columnNames+" FROM "+tableName+"_old");
+
+ dropTableIfExists(tableName+"_old");
+ }
+ }
+
+ /**
+ * @param tableName
+ * @param columnName
+ * @param columnType
+ * @throws SQLException
+ */
+ public void addColumn(String tableName, String columnName, String columnType) throws SQLException {
+ addColumn(tableName, columnName, columnType, true, null);
+ }
+
+ /**
+ * @param
+ * @param tableName
+ * @param columnName
+ * @param columnType
+ * @param canBeNull
+ * @param defaultValue
+ * @throws SQLException
+ */
+ public void addColumn(String tableName, String columnName, String columnType, boolean canBeNull, T defaultValue) throws SQLException {
+ if ( logger.isDebugEnabled() ) logger.debug("Altering table "+tableName+", adding column "+columnName+" type "+ columnType);
+
+ StringBuilder requestString = new StringBuilder();
+ requestString.append("ALTER TABLE ");
+ requestString.append(tableName);
+ if ( DBPlugin.areEqual(this.databaseEntry.getDriver(), DBDatabase.MYSQL.getDriverName()) || DBPlugin.areEqual(this.databaseEntry.getDriver(), DBDatabase.MSSQL.getDriverName()) )
+ requestString.append(" ADD ");
+ else if ( DBPlugin.areEqual(this.databaseEntry.getDriver(), DBDatabase.ORACLE.getDriverName()) )
+ requestString.append(" ADD ( ");
+ else
+ requestString.append(" ADD COLUMN ");
+ requestString.append(columnName);
+ requestString.append(" ");
+ requestString.append(columnType);
+
+ if ( defaultValue != null ) {
+ requestString.append(" DEFAULT ");
+ if ( defaultValue instanceof Integer )
+ requestString.append(defaultValue);
+ else if ( defaultValue instanceof Timestamp ) {
+ if ( DBPlugin.areEqual(this.databaseEntry.getDriver(), DBDatabase.ORACLE.getDriverName()) )
+ requestString.append("TO_DATE(");
+ requestString.append("'");
+ requestString.append(defaultValue.toString().substring(0, 19)); // we remove the milliseconds
+ requestString.append("'");
+ if ( DBPlugin.areEqual(this.databaseEntry.getDriver(), DBDatabase.ORACLE.getDriverName()) )
+ requestString.append(",'YYYY-MM-DD HH24:MI.SS')");
+ } else {
+ requestString.append("'");
+ requestString.append(defaultValue);
+ requestString.append("'");
+ }
+ }
+
+ if ( !canBeNull )
+ requestString.append(" NOT NULL");
+
+ if ( DBPlugin.areEqual(this.databaseEntry.getDriver(), DBDatabase.ORACLE.getDriverName()) )
+ requestString.append(" )");
+
+ executeRequest(requestString.toString());
+ }
+
+ /**
+ * @param tableName
+ * @param oldColumnName
+ * @param newColumnName
+ * @param columnType
+ * @throws SQLException
+ */
+ public void renameColumn(String tableName, String oldColumnName, String newColumnName, String columnType) throws SQLException {
+ if ( logger.isDebugEnabled() ) logger.debug("Altering table "+tableName+", renaming column "+oldColumnName+" to "+ newColumnName);
+
+ if ( DBPlugin.areEqual(this.databaseEntry.getDriver(), DBDatabase.SQLITE.getDriverName()) )
+ executeRequest("ALTER TABLE "+tableName+" RENAME COLUMN "+oldColumnName+" TO "+newColumnName);
+
+ else if ( DBPlugin.areEqual(this.databaseEntry.getDriver(), DBDatabase.MSSQL.getDriverName()) )
+ executeRequest("EXEC sp_rename '"+tableName+"."+oldColumnName+"','"+newColumnName+"','COLUMN'");
+
+ else if ( DBPlugin.areEqual(this.databaseEntry.getDriver(), DBDatabase.POSTGRESQL.getDriverName()) )
+ executeRequest("ALTER TABLE "+tableName+" RENAME "+oldColumnName+" TO "+newColumnName);
+
+ else if ( DBPlugin.areEqual(this.databaseEntry.getDriver(), DBDatabase.MYSQL.getDriverName()) )
+ executeRequest("ALTER TABLE "+tableName+" CHANGE COLUMN "+oldColumnName+" "+newColumnName+" "+columnType);
+
+ else if ( DBPlugin.areEqual(this.databaseEntry.getDriver(), DBDatabase.ORACLE.getDriverName()) )
+ executeRequest("ALTER TABLE "+tableName+" RENAME COLUMN "+oldColumnName+" TO "+newColumnName);
+ }
+
+ /**
+ * Upgrades the database
+ * @param version
+ * @throws Exception
+ */
+ private void upgradeDatabase(int version) throws Exception {
+ int dbVersion = version;
+
+ DBColumn booleanColumn = new DBColumn("", this.databaseEntry, DBColumnType.BOOLEAN, false);
+ DBColumn integerColumn = new DBColumn("", this.databaseEntry, DBColumnType.INTEGER, false);
+ DBColumn textColumn = new DBColumn("", this.databaseEntry, DBColumnType.TEXT, false);
+ DBColumn imageColumn = new DBColumn("", this.databaseEntry, DBColumnType.IMAGE, false);
+ DBColumn objectIDColumn = new DBColumn("", this.databaseEntry, DBColumnType.OBJECTID, false);
+ DBColumn objNameColumn = new DBColumn("", this.databaseEntry, DBColumnType.OBJ_NAME, false);
+ DBColumn userNameColumn = new DBColumn("", this.databaseEntry, DBColumnType.USERNAME, false);
+ DBColumn datetimeColumn = new DBColumn("", this.databaseEntry, DBColumnType.DATETIME, false);
+ DBColumn autoIncrementColumn = new DBColumn("", this.databaseEntry, DBColumnType.AUTO_INCREMENT, false);
+ DBColumn strengthColumn = new DBColumn("", this.databaseEntry, DBColumnType.STRENGTH, false);
+
+ setAutoCommit(false);
+
+ initializeDatabaseTables();
+
+ // convert from version 200 to 201:
+ // - add a blob column into the views table
+ if ( dbVersion == 200 ) {
+ addColumn(this.schemaPrefix+"views", "screenshot", imageColumn.getFullType()); // executeRequest("ALTER TABLE "+this.schemaPrefix+"views ADD "+COLUMN+" screenshot "+this.IMAGE);
+
+ dbVersion = 201;
+ }
+
+ // convert from version 201 to 202:
+ // - add text_position column in the views_connections table
+ // - add source_connections and target_connections to views_objects and views_connections tables
+ if ( dbVersion == 201 ) {
+
+ addColumn(this.schemaPrefix+"views", "text_position", integerColumn.getType()); // executeRequest("ALTER TABLE "+this.schemaPrefix+"views_connections ADD "+COLUMN+" text_position "+this.INTEGER);
+ addColumn(this.schemaPrefix+"views_objects", "source_connections", textColumn.getType()); // executeRequest("ALTER TABLE "+this.schemaPrefix+"views_objects ADD "+COLUMN+" source_connections "+this.TEXT);
+ addColumn(this.schemaPrefix+"views_objects", "target_connections", textColumn.getType()); // executeRequest("ALTER TABLE "+this.schemaPrefix+"views_objects ADD "+COLUMN+" target_connections "+this.TEXT);
+ addColumn(this.schemaPrefix+"views_connections", "source_connections", textColumn.getType()); // executeRequest("ALTER TABLE "+this.schemaPrefix+"views_connections ADD "+COLUMN+" source_connections "+this.TEXT);
+ addColumn(this.schemaPrefix+"views_connections", "target_connections", textColumn.getType()); // executeRequest("ALTER TABLE "+this.schemaPrefix+"views_connections ADD "+COLUMN+" target_connections "+this.TEXT);
+
+ dbVersion = 202;
+ }
+
+ // convert from version 202 to 203:
+ // - add element_version column to the views_objects table
+ // - add relationship_version column to the views_connections table
+ if ( dbVersion == 202 ) {
+ addColumn(this.schemaPrefix+"views_connections", "relationship_version", integerColumn.getType(), false, 1); // executeRequest("ALTER TABLE "+this.schemaPrefix+"views_connections ADD "+COLUMN+" relationship_version "+this.INTEGER);
+ addColumn(this.schemaPrefix+"views_objects", "element_version", integerColumn.getType(), false, 1); // executeRequest("ALTER TABLE "+this.schemaPrefix+"views_objects ADD "+COLUMN+" element_version "+this.INTEGER);
+
+ dbVersion = 203;
+ }
+
+ // convert from version 203 to 204:
+ // - add a checksum to the model
+ //
+ if ( dbVersion == 203 ) {
+ addColumn(this.schemaPrefix+"models", "checksum", objectIDColumn.getType(), false, "");
+
+ if ( logger.isDebugEnabled() ) logger.debug("Calculating models checksum");
+ try ( DBSelect result = new DBSelect(this.databaseEntry.getName(), this.connection, "SELECT id, version, name, note, purpose FROM "+this.schemaPrefix+"models") ) {
+ while ( result.next() ) {
+ StringBuilder checksumBuilder = new StringBuilder();
+ DBChecksum.append(checksumBuilder, "id", result.getString("id"));
+ DBChecksum.append(checksumBuilder, "name", result.getString("name"));
+ DBChecksum.append(checksumBuilder, "purpose", result.getString("purpose"));
+ DBChecksum.append(checksumBuilder, "note", result.getString("note"));
+ String checksum;
+ try {
+ checksum = DBChecksum.calculateChecksum(checksumBuilder);
+ } catch (Exception err) {
+ DBGui.popup(Level.FATAL, "Failed to calculate models checksum.", err);
+ rollback();
+ return;
+ }
+ executeRequest("UPDATE "+this.schemaPrefix+"models SET checksum = ? WHERE id = ? AND version = ?", checksum, result.getString("id"), result.getInt("version"));
+ }
+ }
+
+ dbVersion = 204;
+ }
+
+ // convert from version 204 to 205:
+ // - add a container_checksum column in the views table
+ //
+ if ( dbVersion == 204 ) {
+ addColumn(this.schemaPrefix+"views", "container_checksum", objectIDColumn.getType(), false, "");
+
+ DBGui.popup("Please wait while calculating new checksum on views table.");
+
+ DBArchimateModel tempModel = new DBArchimateModel();
+ try ( DBDatabaseImportConnection importConnection = new DBDatabaseImportConnection(this) ) {
+ if ( logger.isDebugEnabled() ) logger.debug("Calculating containers checksum");
+ try ( DBSelect result = new DBSelect(this.databaseEntry.getName(), this.connection, "SELECT id, version FROM "+this.schemaPrefix+"views") ) {
+ while ( result.next() ) {
+ IDiagramModel view;
+ DBImportViewFromIdCommand command = new DBImportViewFromIdCommand(importConnection, tempModel, null, result.getString("id"), result.getInt("version"), DBImportMode.templateMode, false);
+ if ( command.canExecute() )
+ command.execute();
+ if ( command.getException() != null )
+ throw command.getException();
+
+ view = command.getImported();
+
+ executeRequest("UPDATE "+this.schemaPrefix+"views SET container_checksum = ? WHERE id = ? AND version = ?", DBChecksum.calculateChecksum(view), result.getString("id"), result.getInt("version"));
+ }
+ }
+ }
+ tempModel = null;
+
+ DBGui.closePopup();
+
+ dbVersion = 205;
+ }
+
+ // convert from version 205 to 206:
+ // - add the created_by and created_on columns in the views_connections and views_objects tables
+ // - create tables views_connections_in_view and views_objects_in_view
+ // - remove the rank, view_id and view_version columns from the views_connections and views_objects tables
+ //
+ if ( dbVersion == 205 ) {
+ Timestamp now = new Timestamp(0);
+
+ addColumn(this.schemaPrefix+"views_connections", "created_by", userNameColumn.getType(), false, "databasePlugin"); // we set dummy value to satisfy the NOT NULL condition
+ addColumn(this.schemaPrefix+"views_connections", "created_on", datetimeColumn.getType(), false, now); // we set dummy value to satisfy the NOT NULL condition
+
+ if ( DBPlugin.areEqual(this.databaseEntry.getDriver(), DBDatabase.ORACLE.getDriverName()) )
+ executeRequest("UPDATE "+this.schemaPrefix+"views_connections c SET (created_on, created_by) = (SELECT created_on, created_by FROM "+this.schemaPrefix+"views WHERE id = c.view_id AND version = c.view_version)");
+ else
+ executeRequest("UPDATE "+this.schemaPrefix+"views_connections SET created_on = j.created_on, created_by = j.created_by FROM (SELECT c.id, v.created_on, v.created_by FROM "+this.schemaPrefix+"views_connections c JOIN "+this.schemaPrefix+"views v ON v.id = c.view_id AND v.version = c.view_version) j WHERE "+this.schemaPrefix+"views_connections.id = j.id");
+
+
+
+
+
+
+ addColumn(this.schemaPrefix+"views_objects", "created_by", userNameColumn.getType(), false, "databasePlugin"); // we set dummy value to satisfy the NOT NULL condition
+ addColumn(this.schemaPrefix+"views_objects", "created_on", datetimeColumn.getType(), false, now); // we set dummy value to satisfy the NOT NULL condition
+
+ if ( DBPlugin.areEqual(this.databaseEntry.getDriver(), DBDatabase.ORACLE.getDriverName()) )
+ executeRequest("UPDATE "+this.schemaPrefix+"views_objects o SET (created_on, created_by) = (SELECT created_on, created_by FROM "+this.schemaPrefix+"views WHERE id = o.view_id AND version = o.view_version)");
+ else
+ executeRequest("UPDATE "+this.schemaPrefix+"views_objects SET created_on = j.created_on, created_by = j.created_by FROM (SELECT c.id, v.created_on, v.created_by FROM "+this.schemaPrefix+"views_objects c JOIN "+this.schemaPrefix+"views v ON v.id = c.view_id AND v.version = c.view_version) j WHERE "+this.schemaPrefix+"views_objects.id = j.id");
+
+
+
+ if ( logger.isDebugEnabled() ) logger.debug("Creating table "+this.schemaPrefix+"views_connections_in_view");
+ executeRequest("CREATE TABLE "+this.schemaPrefix+"views_connections_in_view ("
+ + "civ_id " + autoIncrementColumn.getType()+", "
+ + "connection_id " + objectIDColumn.getType() +" NOT NULL, "
+ + "connection_version " + integerColumn.getType() +" NOT NULL, "
+ + "view_id " + objectIDColumn.getType() +" NOT NULL, "
+ + "view_version " + integerColumn.getType() +" NOT NULL, "
+ + "pos " + integerColumn.getType() +" NOT NULL"
+ + ", PRIMARY KEY (civ_id)"
+ + ")");
+ if ( DBPlugin.areEqual(this.databaseEntry.getDriver(), DBDatabase.ORACLE.getDriverName()) ) {
+ if ( logger.isDebugEnabled() ) logger.debug("Creating sequence "+this.schemaPrefix+"seq_connections_in_view");
+ executeRequest("BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "+this.schemaPrefix+"seq_connections_in_view'; EXCEPTION WHEN OTHERS THEN NULL; END;");
+ executeRequest("CREATE SEQUENCE "+this.schemaPrefix+"seq_connections_in_view START WITH 1 INCREMENT BY 1 CACHE 100");
+
+ if ( logger.isDebugEnabled() ) logger.debug("Creating trigger "+this.schemaPrefix+"trigger_connections_in_view");
+ executeRequest("CREATE OR REPLACE TRIGGER "+this.schemaPrefix+"trigger_connections_in_view "
+ + "BEFORE INSERT ON "+this.schemaPrefix+"views_connections_in_view "
+ + "FOR EACH ROW "
+ + "BEGIN"
+ + " SELECT "+this.schemaPrefix+"seq_connections_in_view.NEXTVAL INTO :NEW.civ_id FROM DUAL;"
+ + "END;");
+ }
+
+ // we fill in the views_connections_in_view table
+ if ( logger.isDebugEnabled() ) logger.debug("Copying data from "+this.schemaPrefix+"views_connections table to "+this.schemaPrefix+"views_connections_in_view table");
+ executeRequest("INSERT INTO "+this.schemaPrefix+"views_connections_in_view "
+ +"(connection_id, connection_version, view_id, view_version, pos) "
+ +"SELECT id, version, view_id, view_version, pos FROM "+this.schemaPrefix+"views_connections"
+ );
+
+ if ( logger.isDebugEnabled() ) logger.debug("Creating table "+this.schemaPrefix+"views_objects_in_view");
+ executeRequest("CREATE TABLE "+this.schemaPrefix+"views_objects_in_view ("
+ + "oiv_id " + autoIncrementColumn.getType()+", "
+ + "object_id " + objectIDColumn.getType() +" NOT NULL, "
+ + "object_version " + integerColumn.getType() +" NOT NULL, "
+ + "view_id " + objectIDColumn.getType() +" NOT NULL, "
+ + "view_version " + integerColumn.getType() +" NOT NULL, "
+ + "pos " + integerColumn.getType() +" NOT NULL"
+ + ", PRIMARY KEY (oiv_id)"
+ + ")");
+ if ( DBPlugin.areEqual(this.databaseEntry.getDriver(), DBDatabase.ORACLE.getDriverName()) ) {
+ if ( logger.isDebugEnabled() ) logger.debug("Creating sequence "+this.schemaPrefix+"seq_objects_in_view");
+ executeRequest("BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "+this.schemaPrefix+"seq_objects_in_view'; EXCEPTION WHEN OTHERS THEN NULL; END;");
+ executeRequest("CREATE SEQUENCE "+this.schemaPrefix+"seq_objects_in_view START WITH 1 INCREMENT BY 1 CACHE 100");
+
+ if ( logger.isDebugEnabled() ) logger.debug("Creating trigger "+this.schemaPrefix+"trigger_objects_in_view");
+ executeRequest("CREATE OR REPLACE TRIGGER "+this.schemaPrefix+"trigger_objects_in_view "
+ + "BEFORE INSERT ON "+this.schemaPrefix+"views_objects_in_view "
+ + "FOR EACH ROW "
+ + "BEGIN"
+ + " SELECT "+this.schemaPrefix+"seq_objects_in_view.NEXTVAL INTO :NEW.oiv_id FROM DUAL;"
+ + "END;");
+ }
+
+ // we fill in the views_objects_in_view table
+ if ( logger.isDebugEnabled() ) logger.debug("Copying data from "+this.schemaPrefix+"views_objects table to "+this.schemaPrefix+"views_objects_in_view table");
+ if ( logger.isDebugEnabled() ) logger.debug("Copying data from "+this.schemaPrefix+"views_connections table to "+this.schemaPrefix+"views_connections_in_view table");
+ executeRequest("INSERT INTO "+this.schemaPrefix+"views_objects_in_view "
+ +"(object_id, object_version, view_id, view_version, pos) "
+ +"SELECT id, version, view_id, view_version, pos FROM "+this.schemaPrefix+"views_objects"
+ );
+
+ dropColumn(this.schemaPrefix+"views_connections", "view_id");
+ dropColumn(this.schemaPrefix+"views_connections", "view_version");
+ dropColumn(this.schemaPrefix+"views_connections", "pos");
+
+ dropColumn(this.schemaPrefix+"views_objects", "view_id");
+ dropColumn(this.schemaPrefix+"views_objects", "view_version");
+ dropColumn(this.schemaPrefix+"views_objects", "pos");
+
+ dbVersion = 206;
+ }
+
+ // convert from version 206 to 207:
+ // - remove the checksum column from the images table
+ //
+ if ( dbVersion == 206 ) {
+ dropColumn(this.schemaPrefix+"images", "checksum");
+
+ dbVersion = 207;
+ }
+
+ // convert from version 207 to 208
+ // - create metadata table
+ // - drop columns source_connections and target_connections from views_objects and views_connections tables
+ if ( dbVersion == 207 ) {
+ DBGui.popup("Please wait while converting data.");
+
+ if ( logger.isDebugEnabled() ) logger.debug("Creating table "+this.schemaPrefix+"metadata");
+ executeRequest("CREATE TABLE "+this.schemaPrefix+"metadata ("
+ + "parent_id "+objectIDColumn.getType() +" NOT NULL, "
+ + "parent_version " + integerColumn.getType() +" NOT NULL, "
+ + "pos " + integerColumn.getType() +" NOT NULL, "
+ + "name " + objNameColumn.getType() + ", "
+ + "value " + textColumn.getType()+ ", "
+ + "PRIMARY KEY (parent_id, parent_version, pos)"
+ + ")");
+
+ dropColumn(this.schemaPrefix+"views_objects", "source_connections");
+ dropColumn(this.schemaPrefix+"views_objects", "target_connections");
+
+ dropColumn(this.schemaPrefix+"views_connections", "source_connections");
+ dropColumn(this.schemaPrefix+"views_connections", "target_connections");
+
+ DBGui.closePopup();
+
+ dbVersion = 208;
+ }
+
+ // convert from version 208 to 209
+ // - add checkedin_by, checkedin_on, deleted_by and deleted_on columns in folders, views, views_connections and views_objects
+ // (they're not yet used, but they're created for uniformity purpose)
+ // - add alpha column in views_objects table
+ if ( dbVersion == 208 ) {
+ addColumn(this.schemaPrefix+"folders", "checkedin_by", userNameColumn.getType());
+ addColumn(this.schemaPrefix+"folders", "checkedin_on", datetimeColumn.getType());
+ addColumn(this.schemaPrefix+"folders", "deleted_by", userNameColumn.getType());
+ addColumn(this.schemaPrefix+"folders", "deleted_on", datetimeColumn.getType());
+
+ addColumn(this.schemaPrefix+"views", "checkedin_by", userNameColumn.getType());
+ addColumn(this.schemaPrefix+"views", "checkedin_on", datetimeColumn.getType());
+ addColumn(this.schemaPrefix+"views", "deleted_by", userNameColumn.getType());
+ addColumn(this.schemaPrefix+"views", "deleted_on", datetimeColumn.getType());
+
+ addColumn(this.schemaPrefix+"views_connections", "checkedin_by", userNameColumn.getType());
+ addColumn(this.schemaPrefix+"views_connections", "checkedin_on", datetimeColumn.getType());
+ addColumn(this.schemaPrefix+"views_connections", "deleted_by", userNameColumn.getType());
+ addColumn(this.schemaPrefix+"views_connections", "deleted_on", datetimeColumn.getType());
+
+ addColumn(this.schemaPrefix+"views_objects", "checkedin_by", userNameColumn.getType());
+ addColumn(this.schemaPrefix+"views_objects", "checkedin_on", datetimeColumn.getType());
+ addColumn(this.schemaPrefix+"views_objects", "deleted_by", userNameColumn.getType());
+ addColumn(this.schemaPrefix+"views_objects", "deleted_on", datetimeColumn.getType());
+
+ addColumn(this.schemaPrefix+"views_objects", "alpha", integerColumn.getType());
+
+ dbVersion = 209;
+ }
+
+ // convert from version 209 to 210
+ // - add screenshot_scale_factor and screenshot_border_width in views table
+ if ( dbVersion == 209 ) {
+ addColumn(this.schemaPrefix+"views", "screenshot_scale_factor", integerColumn.getType());
+ addColumn(this.schemaPrefix+"views", "screenshot_border_width", integerColumn.getType());
+
+ dbVersion = 210;
+ }
+
+ // convert from version 210 to 211
+ // - remove hint_title and hint_content from the views and views_objects table
+ if ( dbVersion == 210 ) {
+ dropColumn(this.schemaPrefix+"views", "hint_title");
+ dropColumn(this.schemaPrefix+"views", "hint_content");
+
+ dropColumn(this.schemaPrefix+"views_objects", "hint_title");
+ dropColumn(this.schemaPrefix+"views_objects", "hint_content");
+
+ // we need to recalculate the checksums
+ DBGui.popup("Please wait while re-calculating checksums on views_objects and views tables.");
+
+ DBArchimateModel tempModel = new DBArchimateModel();
+
+ try ( DBDatabaseImportConnection importConnection = new DBDatabaseImportConnection(this) ) {
+ try ( DBSelect result = new DBSelect(this.databaseEntry.getName(), this.connection, "SELECT id, version FROM "+this.schemaPrefix+"views") ) {
+ while ( result.next() ) {
+ IDiagramModel view;
+
+ DBImportViewFromIdCommand command = new DBImportViewFromIdCommand(importConnection, tempModel, null, result.getString("id"), result.getInt("version"), DBImportMode.forceSharedMode, false);
+ if ( command.canExecute() )
+ command.execute();
+ if ( command.getException() != null )
+ throw command.getException();
+
+ view = command.getImported();
+ DBMetadata dbMetadata = DBMetadata.getDBMetadata(view);
+
+ tempModel.countObject(view, true);
+
+ executeRequest("UPDATE "+this.schemaPrefix+"views SET checksum = ?, container_checksum = ? WHERE id = ? AND version = ?", dbMetadata.getCurrentVersion().getChecksum(), dbMetadata.getCurrentVersion().getContainerChecksum(), result.getString("id"), result.getInt("version"));
+
+ for ( IDiagramModelObject obj: view.getChildren() ) {
+ updateChecksum(obj);
+ }
+ }
+ }
+ }
+ tempModel = null;
+
+ DBGui.closePopup();
+
+ dbVersion = 211;
+ }
+
+ // convert from version 211 to 212
+ // - create table features
+ // - add columns "properties" and "features" to all component tables
+ // - add column "bendpoints" to "views_connections" table
+ // - add column "is_directed" to "relationships" table
+ // - add column "id" to "database_version table
+ if ( dbVersion == 211 ) {
+ if ( logger.isDebugEnabled() ) logger.debug("Creating table "+this.schemaPrefix+"features");
+ executeRequest("CREATE TABLE "+this.schemaPrefix+"features ("
+ + "parent_id "+objectIDColumn.getType()+" NOT NULL, "
+ + "parent_version " + integerColumn.getType() +" NOT NULL, "
+ + "pos " + integerColumn.getType() +" NOT NULL, "
+ + "name " + objNameColumn.getType() + ", "
+ + "value " + textColumn.getType() + ", "
+ + "PRIMARY KEY (parent_id, parent_version, pos)"
+ + ")");
+
+ String[] tableNames = {"models", "folders", "elements", "relationships", "views", "views_objects", "views_connections"};
+ for (String tableName: tableNames) {
+ // we initialise the value to true as we do not know if the components have got properties, so we reproduce the previous behaviour
+ addColumn(this.schemaPrefix+tableName, "properties", integerColumn.getType(), true, 1);
+
+ // we initialise the value to false as we're sure that the components do not have features yet
+ addColumn(this.schemaPrefix+tableName, "features", integerColumn.getType(), true, 1);
+ }
+
+ // we initialise the value to true as we do not know if the connection have got bendpoints, so we reproduce the previous behaviour
+ addColumn(this.schemaPrefix+"views_connections", "bendpoints", integerColumn.getType(), true, 1);
+
+ // we do not initialise the value, as NULL will be treated as false which is the default value (association relationships are not directed by default)
+ addColumn(this.schemaPrefix+"relationships", "is_directed", booleanColumn.getType(), true, 0);
+
+ // we add the new id column with a generated ID and save this ID in the preferences file for later use
+ addColumn(this.schemaPrefix+"database_version", "id", objectIDColumn.getType(), false, "");
+
+ this.databaseEntry.setId(DBPlugin.createID(null));
+ executeRequest("UPDATE "+this.schemaPrefix+"database_version SET id = '"+this.databaseEntry.getId()+"' WHERE archi_plugin = '"+DBPlugin.pluginName+"'");
+ // if the databaseEntry.index is different from -1, then the databaseEntry is persisted in the database, so we persist the new ID in the preference store
+ if ( this.databaseEntry.getIndex() != -1 )
+ this.databaseEntry.persistIntoPreferenceStore();
+
+ dbVersion = 212;
+ }
+
+ // convert from version 212 to 213
+ // - rename "rank" column to "pos" in all tables
+ // - change "strength" column from varchar(20) to blob
+ if ( dbVersion == 212 ) {
+ if ( logger.isDebugEnabled() ) logger.debug("Renaming \"rank\" column to \"pos\" in all tables.");
+ renameColumn(this.schemaPrefix+"properties", "rank", "pos", integerColumn.getType());
+ renameColumn(this.schemaPrefix+"metadata", "rank", "pos", integerColumn.getType());
+ renameColumn(this.schemaPrefix+"features", "rank", "pos", integerColumn.getType());
+ renameColumn(this.schemaPrefix+"elements_in_model", "rank", "pos", integerColumn.getType());
+ renameColumn(this.schemaPrefix+"relationships_in_model", "rank", "pos", integerColumn.getType());
+ renameColumn(this.schemaPrefix+"folders_in_model", "rank", "pos", integerColumn.getType());
+ renameColumn(this.schemaPrefix+"views_in_model", "rank", "pos", integerColumn.getType());
+ renameColumn(this.schemaPrefix+"views_objects_in_view", "rank", "pos", integerColumn.getType());
+ renameColumn(this.schemaPrefix+"views_connections_in_view", "rank", "pos", integerColumn.getType());
+ renameColumn(this.schemaPrefix+"bendpoints", "rank", "pos", integerColumn.getType());
+
+ if ( logger.isDebugEnabled() ) logger.debug("Changing strength column of relationships table from varchr(20) to clob.");
+ renameColumn(this.schemaPrefix+"relationships", "strength", "old_strength", strengthColumn.getType());
+ addColumn(this.schemaPrefix+"relationships", "strength", textColumn.getType());
+ executeRequest("UPDATE "+this.schemaPrefix+"relationships SET strength = old_strength");
+ dropColumn(this.schemaPrefix+"relationships", "old_strength");
+
+ dbVersion = 213;
+ }
+
+ // convert from version 213 to 490
+ // - create profiles and profiles_in_model tables
+ // - add profile column in elements and relationships tables
+ if ( dbVersion == 213 ) {
+ // create profiles and profiles_in_model tables
+ for ( int i = 0 ; i < this.databaseTables.size() ; ++i ) {
+ DBTable table = this.databaseTables.get(i);
+ if ( table.getName().equals("profiles") ) {
+ if ( logger.isDebugEnabled() ) logger.debug("Creating profiles table");
+ executeRequest(table.generateCreateStatement());
+ }
+ if ( table.getName().equals("profiles_in_model") ) {
+ if ( logger.isDebugEnabled() ) logger.debug("Creating profiles_in_model table");
+ executeRequest(table.generateCreateStatement());
+ }
+ }
+
+ // add profile column in elements and relationships tables
+ addColumn(this.schemaPrefix+"elements", "profile", objectIDColumn.getType());
+ addColumn(this.schemaPrefix+"relationships", "profile", objectIDColumn.getType());
+
+ dbVersion = 490;
+ }
+
+ if ( logger.isTraceEnabled() ) logger.trace("Updating database version to 490");
+ executeRequest("UPDATE "+this.schemaPrefix+"database_version SET version = "+dbVersion+" WHERE archi_plugin = '"+DBPlugin.pluginName+"'");
+ commit();
+
+ setAutoCommit(true);
+ }
+
+ private void updateChecksum(IDiagramModelObject obj) throws SQLException {
+ DBMetadata dbMetadata = DBMetadata.getDBMetadata(obj);
+
+ executeRequest("UPDATE "+this.schemaPrefix+"views_object SET checksum = ? WHERE id = ? AND version = ?", dbMetadata.getCurrentVersion().getChecksum(), obj.getId(), dbMetadata.getInitialVersion().getVersion());
+
+ if ( obj instanceof IDiagramModelContainer ) {
+ for ( IDiagramModelObject subObj: ((IDiagramModelContainer)obj).getChildren() ) {
+ updateChecksum(subObj);
+ }
+ }
+ }
+
+ /**
+ * wrapper to generate and execute a INSERT request in the database
+ * One may just provide the column names and the corresponding values as parameters
+ * the wrapper automatically generates the VALUES part of the request
+ * @param table
+ * @param columns
+ * @param parameters
+ * @param
+ * @return The number of lines inserted in the table
+ * @throws SQLException
+ */
+ @SafeVarargs
+ public final int insert(String table, String[] columns, T...parameters) throws SQLException {
+ assert ( isConnected() );
+
+ StringBuilder cols = new StringBuilder();
+ StringBuilder values = new StringBuilder();
+ ArrayList newParameters = new ArrayList();
+
+ for (int i=0 ; i < columns.length ; ++i) {
+ if ( parameters[i] != null ) {
+ if ( cols.length() != 0 ) {
+ cols.append(", ");
+ values.append(", ");
+ }
+ cols.append(columns[i]);
+ values.append("?");
+ newParameters.add(parameters[i]);
+ }
+ }
+
+ if ( (cols.length() == 0) || (values.length() == 0) )
+ throw new SQLException("SQL request cannot have all its parameters null.");
+
+ @SuppressWarnings("resource")
+ DBRequest request = new DBRequest(this.databaseEntry.getName(), this.connection, "INSERT INTO "+table+" ("+cols.toString()+") VALUES ("+values.toString()+")", newParameters.toArray());
+ int rowCount = request.getRowCount();
+ request.close();
+
+ return rowCount;
+ }
+
+ /**
+ * Gets the list of models in the current database
+ * @param filter (use "%" as wildcard)
+ * @throws Exception
+ * @return a list of Hashtables, each containing the name and the id of one model
+ */
+ public ArrayList> getModels(String filter) throws Exception {
+ ArrayList> list = new ArrayList>();
+
+ this.schema = this.databaseEntry.getSchema();
+ this.schemaPrefix = this.databaseEntry.getSchemaPrefix();
+
+ DBSelect result = null;
+ try {
+ // We do not use a GROUP BY because it does not give the expected result on PostGresSQL ...
+ if ( filter==null || filter.length()==0 )
+ result = new DBSelect(this.databaseEntry.getName(), this.connection, "SELECT id, name, version, created_on FROM "+this.schemaPrefix+"models m WHERE version = (SELECT MAX(version) FROM "+this.schemaPrefix+"models WHERE id = m.id) ORDER BY name");
+ else
+ result = new DBSelect(this.databaseEntry.getName(), this.connection, "SELECT id, name, version, created_on FROM "+this.schemaPrefix+"models m WHERE version = (SELECT MAX(version) FROM "+this.schemaPrefix+"models WHERE id = m.id) AND UPPER(name) like UPPER(?) ORDER BY name", filter);
+
+ while ( result.next() && result.getString("id") != null ) {
+ if (logger.isTraceEnabled() ) logger.trace("Found model \""+result.getString("name")+"\"");
+ Hashtable table = new Hashtable();
+ table.put("name", result.getString("name"));
+ table.put("id", result.getString("id"));
+ table.put("created_on", result.getDate("created_on"));
+ list.add(table);
+ }
+ } finally {
+ if ( result != null ) {
+ result.close();
+ result = null;
+ }
+ }
+
+ return list;
+ }
+
+ /**
+ * @param modelName
+ * @param ignoreCase
+ * @return
+ * @throws Exception
+ */
+ public String getModelId(String modelName, boolean ignoreCase) throws Exception {
+ String whereClause = ignoreCase ? "UPPER(name) = UPPER(?)" : "name = ?";
+
+ try ( DBSelect result = new DBSelect(this.databaseEntry.getName(), this.connection,"SELECT id FROM "+this.schemaPrefix+"models m WHERE "+whereClause, modelName) ) {
+ if ( result.next() )
+ return (result.getString("id"));
+ }
+
+ return null;
+ }
+
+ /**
+ * Gets the list of versions on a model in the current database
+ * @param id the id of the model
+ * @throws Exception
+ * @return a list of Hashtables, each containing the version, created_on, created_by, name, note and purpose of one version of the model
+ */
+ public ArrayList> getModelVersions(String id) throws Exception {
+ ArrayList> list = new ArrayList>();
+
+ try ( DBSelect result = new DBSelect(this.databaseEntry.getName(), this.connection,"SELECT version, created_by, created_on, name, note, purpose, checksum FROM "+this.schemaPrefix+"models WHERE id = ? ORDER BY version DESC", id) ) {
+ while ( result.next() ) {
+ if (logger.isTraceEnabled() ) logger.trace("Found model \""+result.getString("name")+"\" version \""+result.getString("version")+"\" checksum=\""+result.getString("checksum")+"\"");
+ Hashtable table = new Hashtable();
+ table.put("version", result.getString("version"));
+ table.put("created_by", result.getString("created_by"));
+ table.put("created_on", result.getTimestamp("created_on"));
+ table.put("name", result.getString("name"));
+ table.put("note", result.getString("note") == null ? "" : result.getString("note"));
+ table.put("purpose", result.getString("purpose") == null ? "" : result.getString("purpose"));
+ list.add(table);
+ }
+ }
+ return list;
+ }
+
+
+ /**
+ * Sets the auto-commit mode of the database
+ * @param autoCommit
+ * @throws SQLException
+ */
+ public void setAutoCommit(boolean autoCommit) throws SQLException {
+ if ( logger.isDebugEnabled() ) logger.debug("Setting database auto commit to "+String.valueOf(autoCommit));
+ this.connection.setAutoCommit(autoCommit);
+ }
+
+ /**
+ * Commits the current transaction
+ * @throws SQLException
+ */
+ public void commit() throws SQLException {
+ if ( logger.isDebugEnabled() ) logger.debug("Committing database transaction.");
+ this.connection.commit();
+ }
+
+ /**
+ * Rollbacks the current transaction
+ * @param savepoint
+ * @throws SQLException
+ */
+ public void rollback(Savepoint savepoint) throws SQLException {
+ if ( this.connection == null ) {
+ logger.warn("Cannot rollback as there is no database connection opened.");
+ } else {
+ if ( this.connection.getAutoCommit() ) {
+ if ( logger.isDebugEnabled() ) logger.debug("Do not rollback as database is in auto commit mode.");
+ } else {
+ if ( logger.isDebugEnabled() ) logger.debug("Rollbacking database transaction.");
+ if ( savepoint == null )
+ this.connection.rollback();
+ else
+ this.connection.rollback(savepoint);
+ }
+ }
+ }
+
+ /**
+ * @throws SQLException
+ */
+ public void rollback() throws SQLException {
+ rollback(null);
+ }
+
+ /**
+ * @param
+ * @param request
+ * @param parameters
+ * @return
+ * @throws SQLException
+ */
+ @SafeVarargs
+ final public int executeRequest(String request, T... parameters) throws SQLException {
+ int rowCount = 0;
+
+ @SuppressWarnings("resource")
+ DBRequest dbRequest = new DBRequest(this.databaseEntry.getName(), this.connection, request, parameters);
+ rowCount = dbRequest.getRowCount();
+ dbRequest.close();
+
+ return rowCount;
+ }
+
+ private void initializeDatabaseTables() throws SQLException {
+ // DatabaseVersions table
+ this.databaseVersionColumns = new ArrayList();
+ this.databaseVersionColumns.add(new DBColumn("id", this.databaseEntry, DBColumnType.OBJECTID, true));
+ this.databaseVersionColumns.add(new DBColumn("archi_plugin", this.databaseEntry, DBColumnType.OBJECTID, true));
+ this.databaseVersionColumns.add(new DBColumn("version", this.databaseEntry, DBColumnType.INTEGER, true));
+
+ this.modelsColumns = new ArrayList();
+ this.modelsColumns.add(new DBColumn("id", this.databaseEntry, DBColumnType.OBJECTID, true));
+ this.modelsColumns.add(new DBColumn("version", this.databaseEntry, DBColumnType.INTEGER, true));
+ this.modelsColumns.add(new DBColumn("name", this.databaseEntry, DBColumnType.OBJ_NAME, true));
+ this.modelsColumns.add(new DBColumn("note", this.databaseEntry, DBColumnType.TEXT, false));
+ this.modelsColumns.add(new DBColumn("purpose", this.databaseEntry, DBColumnType.TEXT, false));
+ this.modelsColumns.add(new DBColumn("created_by", this.databaseEntry, DBColumnType.USERNAME, true));
+ this.modelsColumns.add(new DBColumn("created_on", this.databaseEntry, DBColumnType.DATETIME, true));
+ this.modelsColumns.add(new DBColumn("checkedin_by", this.databaseEntry, DBColumnType.USERNAME, false));
+ this.modelsColumns.add(new DBColumn("checkedin_on", this.databaseEntry, DBColumnType.DATETIME, false));
+ this.modelsColumns.add(new DBColumn("deleted_by", this.databaseEntry, DBColumnType.USERNAME, false));
+ this.modelsColumns.add(new DBColumn("deleted_on", this.databaseEntry, DBColumnType.DATETIME, false));
+ this.modelsColumns.add(new DBColumn("properties", this.databaseEntry, DBColumnType.INTEGER, false));
+ this.modelsColumns.add(new DBColumn("features", this.databaseEntry, DBColumnType.INTEGER, false));
+ this.modelsColumns.add(new DBColumn("checksum", this.databaseEntry, DBColumnType.OBJECTID, true));
+
+ this.modelsPrimaryKeys = new ArrayList();
+ this.modelsPrimaryKeys.add("id");
+ this.modelsPrimaryKeys.add("version");
+
+ // Folders table
+ this.foldersColumns = new ArrayList();
+ this.foldersColumns.add(new DBColumn("id", this.databaseEntry, DBColumnType.OBJECTID, true));
+ this.foldersColumns.add(new DBColumn("version", this.databaseEntry, DBColumnType.INTEGER, true));
+ this.foldersColumns.add(new DBColumn("type", this.databaseEntry, DBColumnType.INTEGER, true));
+ this.foldersColumns.add(new DBColumn("root_type", this.databaseEntry, DBColumnType.INTEGER, true));
+ this.foldersColumns.add(new DBColumn("name", this.databaseEntry, DBColumnType.OBJ_NAME, true));
+ this.foldersColumns.add(new DBColumn("documentation", this.databaseEntry, DBColumnType.TEXT, false));
+ this.foldersColumns.add(new DBColumn("created_by", this.databaseEntry, DBColumnType.USERNAME, true));
+ this.foldersColumns.add(new DBColumn("created_on", this.databaseEntry, DBColumnType.DATETIME, true));
+ this.foldersColumns.add(new DBColumn("checkedin_by", this.databaseEntry, DBColumnType.USERNAME, false));
+ this.foldersColumns.add(new DBColumn("checkedin_on", this.databaseEntry, DBColumnType.DATETIME, false));
+ this.foldersColumns.add(new DBColumn("deleted_by", this.databaseEntry, DBColumnType.USERNAME, false));
+ this.foldersColumns.add(new DBColumn("deleted_on", this.databaseEntry, DBColumnType.DATETIME, false));
+ this.foldersColumns.add(new DBColumn("properties", this.databaseEntry, DBColumnType.INTEGER, false));
+ this.foldersColumns.add(new DBColumn("features", this.databaseEntry, DBColumnType.INTEGER, false));
+ this.foldersColumns.add(new DBColumn("checksum", this.databaseEntry, DBColumnType.OBJECTID, true));
+
+ this.foldersPrimaryKeys = new ArrayList();
+ this.foldersPrimaryKeys.add("id");
+ this.foldersPrimaryKeys.add("version");
+
+ // FoldersInModel table
+ this.foldersInModelColumns = new ArrayList();
+ this.foldersInModelColumns.add(new DBColumn("fim_id", this.databaseEntry, DBColumnType.AUTO_INCREMENT, true));
+ this.foldersInModelColumns.add(new DBColumn("folder_id", this.databaseEntry, DBColumnType.OBJECTID, true));
+ this.foldersInModelColumns.add(new DBColumn("folder_version", this.databaseEntry, DBColumnType.INTEGER, true));
+ this.foldersInModelColumns.add(new DBColumn("parent_folder_id", this.databaseEntry, DBColumnType.OBJECTID, false));
+ this.foldersInModelColumns.add(new DBColumn("model_id", this.databaseEntry, DBColumnType.OBJECTID, true));
+ this.foldersInModelColumns.add(new DBColumn("model_version", this.databaseEntry, DBColumnType.INTEGER, true));
+ this.foldersInModelColumns.add(new DBColumn("pos", this.databaseEntry, DBColumnType.INTEGER, true));
+
+ this.foldersInModelPrimaryKeys = new ArrayList();
+ this.foldersInModelPrimaryKeys.add("fim_id");
+
+ // Elements table
+ this.elementsColumns = new ArrayList();
+ this.elementsColumns.add(new DBColumn("id", this.databaseEntry, DBColumnType.OBJECTID, true));
+ this.elementsColumns.add(new DBColumn("version", this.databaseEntry, DBColumnType.INTEGER, true));
+ this.elementsColumns.add(new DBColumn("class", this.databaseEntry, DBColumnType.OBJECTID, true));
+ this.elementsColumns.add(new DBColumn("name", this.databaseEntry, DBColumnType.OBJ_NAME, false));
+ this.elementsColumns.add(new DBColumn("documentation", this.databaseEntry, DBColumnType.TEXT, false));
+ this.elementsColumns.add(new DBColumn("type", this.databaseEntry, DBColumnType.TYPE, false));
+ this.elementsColumns.add(new DBColumn("profile", this.databaseEntry, DBColumnType.OBJECTID, false));
+ this.elementsColumns.add(new DBColumn("created_by", this.databaseEntry, DBColumnType.USERNAME, true));
+ this.elementsColumns.add(new DBColumn("created_on", this.databaseEntry, DBColumnType.DATETIME, true));
+ this.elementsColumns.add(new DBColumn("checkedin_by", this.databaseEntry, DBColumnType.USERNAME, false));
+ this.elementsColumns.add(new DBColumn("checkedin_on", this.databaseEntry, DBColumnType.DATETIME, false));
+ this.elementsColumns.add(new DBColumn("deleted_by", this.databaseEntry, DBColumnType.USERNAME, false));
+ this.elementsColumns.add(new DBColumn("deleted_on", this.databaseEntry, DBColumnType.DATETIME, false));
+ this.elementsColumns.add(new DBColumn("properties", this.databaseEntry, DBColumnType.INTEGER, false));
+ this.elementsColumns.add(new DBColumn("features", this.databaseEntry, DBColumnType.INTEGER, false));
+ this.elementsColumns.add(new DBColumn("checksum", this.databaseEntry, DBColumnType.OBJECTID, true));
+
+ this.elementsPrimaryKeys = new ArrayList();
+ this.elementsPrimaryKeys.add("id");
+ this.elementsPrimaryKeys.add("version");
+
+ // ElementsInModel table
+ this.elementsInModelColumns = new ArrayList();
+ this.elementsInModelColumns.add(new DBColumn("eim_id", this.databaseEntry, DBColumnType.AUTO_INCREMENT, true));
+ this.elementsInModelColumns.add(new DBColumn("element_id", this.databaseEntry, DBColumnType.OBJECTID, true));
+ this.elementsInModelColumns.add(new DBColumn("element_version", this.databaseEntry, DBColumnType.INTEGER, true));
+ this.elementsInModelColumns.add(new DBColumn("parent_folder_id", this.databaseEntry, DBColumnType.OBJECTID, true));
+ this.elementsInModelColumns.add(new DBColumn("model_id", this.databaseEntry, DBColumnType.OBJECTID, true));
+ this.elementsInModelColumns.add(new DBColumn("model_version", this.databaseEntry, DBColumnType.INTEGER, true));
+ this.elementsInModelColumns.add(new DBColumn("pos", this.databaseEntry, DBColumnType.INTEGER, true));
+
+ this.elementsInModelPrimaryKeys = new ArrayList();
+ this.elementsInModelPrimaryKeys.add("eim_id");
+
+ // Relationships table
+ this.relationshipsColumns = new ArrayList();
+ this.relationshipsColumns.add(new DBColumn("id", this.databaseEntry, DBColumnType.OBJECTID, true));
+ this.relationshipsColumns.add(new DBColumn("version", this.databaseEntry, DBColumnType.INTEGER, true));
+ this.relationshipsColumns.add(new DBColumn("class", this.databaseEntry, DBColumnType.OBJECTID, true));
+ this.relationshipsColumns.add(new DBColumn("name", this.databaseEntry, DBColumnType.OBJ_NAME, false));
+ this.relationshipsColumns.add(new DBColumn("documentation", this.databaseEntry, DBColumnType.TEXT, false));
+ this.relationshipsColumns.add(new DBColumn("source_id", this.databaseEntry, DBColumnType.OBJECTID, false));
+ this.relationshipsColumns.add(new DBColumn("target_id", this.databaseEntry, DBColumnType.OBJECTID, false));
+ this.relationshipsColumns.add(new DBColumn("strength", this.databaseEntry, DBColumnType.TEXT, false));
+ this.relationshipsColumns.add(new DBColumn("access_type", this.databaseEntry, DBColumnType.INTEGER, false));
+ this.relationshipsColumns.add(new DBColumn("is_directed", this.databaseEntry, DBColumnType.BOOLEAN, false));
+ this.relationshipsColumns.add(new DBColumn("profile", this.databaseEntry, DBColumnType.OBJECTID, false));
+ this.relationshipsColumns.add(new DBColumn("created_by", this.databaseEntry, DBColumnType.USERNAME, true));
+ this.relationshipsColumns.add(new DBColumn("created_on", this.databaseEntry, DBColumnType.DATETIME, true));
+ this.relationshipsColumns.add(new DBColumn("checkedin_by", this.databaseEntry, DBColumnType.USERNAME, false));
+ this.relationshipsColumns.add(new DBColumn("checkedin_on", this.databaseEntry, DBColumnType.DATETIME, false));
+ this.relationshipsColumns.add(new DBColumn("deleted_by", this.databaseEntry, DBColumnType.USERNAME, false));
+ this.relationshipsColumns.add(new DBColumn("deleted_on", this.databaseEntry, DBColumnType.DATETIME, false));
+ this.relationshipsColumns.add(new DBColumn("properties", this.databaseEntry, DBColumnType.INTEGER, false));
+ this.relationshipsColumns.add(new DBColumn("features", this.databaseEntry, DBColumnType.INTEGER, false));
+ this.relationshipsColumns.add(new DBColumn("checksum", this.databaseEntry, DBColumnType.OBJECTID, true));
+
+ this.relationshipsPrimaryKeys = new ArrayList