====== Eclipse - Rich Client Platform (RCP) ======
==== Documents ====
^What ^Where^
|1. Introduction | [[http://www.vogella.com/articles/EclipseRCP/article.html|Vogella]]|
|2. Tutorial | [[http://eclipsesource.com/fileadmin/doc/tutorial/Eclipse_4_Tutorial_-_Part_1-4.pdf|Eclipse_4_Tutorial_-_Part_1-4.pdf]]|
|3. Tutorial | [[http://www.bestsolution.at/en/download.php?cat=01_Services&file=Eclipse4Tutorial_WritingApplicationWithE4_BestSolution.pdf|Eclipse4Tutorial_WritingApplicationWithE4_BestSolution.pdf]]|
|4. Tutorial | [[http://manumitting.com/resources/presentations/2012-EclipseCon-CSS.pdf|CSS And Eclipse Application]]|
==== Fallpits ====
* Die Annotations wie @Inject und Lifecylce-Annotations werden nicht getriggert, solange sie betroffenen Klassen nicht eingebunden werden in der Application.e4xmi
* When defining a keybinding - do not forget to define a context where the binding will worl, as described [[http://www.vogella.com/articles/EclipseRCP/article.html#keybindings|here]] \\ The Bindings wont work until they have a mehtod @CanExecute boolean canExec(){return true}
* When using Declarative Services - the services may only be injected by **Interface** not by Implementation class
* **Annotations**
* There only can by ONE method per lifeCycle annotation: @PostCreate, @Focust, @PreDestroy...
* **Inheritance**
* The GUI is now created in //@PostConstruct// annotated methods, not in overridden methods!
* Given part classes A,B. B inherits from A. Both implement an @onFocus annotated method "focusMethod". Only B.focusMethod is called then! Thus the onFocus does not work with inheritance. Indeed if both implement @PostConstruct annotated method - then both methods are called: first A.postConstruct(), then B.postConstruct()!
===== Eclipse RCP common=====
==!! ATTENTION !!==
* Write the **ids** allways small - no camel case.
* **Run Configuration** is re-generated when the "Run As Eclipse Plugin" Link is clicked. \\ {{http://i.imgur.com/u8hQp.png}} \\ This means that yout run-configuration are gone after clicking on that Link.
*
\\
\\
\\
== Where to find what ==
^What ^Where^
|Commands| A list of Eclipse's native commands, which can be used in toolbars, menus etc. is [[http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fui%2Factions%2FActionFactory.html|here]] |
| Extension Points | A list of all Eclipse Extension-Points is [[http://help.eclipse.org/juno/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fextension-points%2Forg_eclipse_ui_installationPages.html|here]] |
|The platform URLs |Are listed [[http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fmisc%2Fplatform-scheme-uri.html|here]]|
==Literature==
^Info ^Location ^
|1. Learn the concepts from the first chapters in a nice book like: | [[http://www.amazon.com/Eclipse-Rich-Client-Platform-Edition/dp/0321603788 | Eclipse Rich Client Platform 2nd Edition]] |
|2. Get the first praxis expirience from the tutorials | [[http://www.vogella.com/articles/EclipseRCP/article.html| Tutorials by Lars Vogel]] |
|3. learn the details from the rest of the book and the Eclipse articles| [[http://www.eclipse.org/articles/?sort=date&category=RCP | Eclipse articles]] |
|4. To learn about single concepts like "commands" or "actions use the wiki"| [[http://wiki.eclipse.org/Rich_Client_Platform | Eclipse WIKI]] |
|5. Als Nachschlagewerk nutze das deutsche Ebook| [[ http://www.ralfebert.de/eclipse_rcp/EclipseRCP.pdf | RCP Ebook]] |
|6. UI Guidelines| [[ http://wiki.eclipse.org/User_Interface_Guidelines | wiki.eclipse.org/User_Interface_Guidelines ]] |
==Nice to know==
* Note that every Eclipse plug-in is essentially an OSGi bundle with some additional Eclipse-specific code.
==Differnent ways to define dependencies ==
^File ^Aim^ Examples^ Links^
|MANIFEST.MF| Covers Information about the plugin on bundle level. | Bundle-Name:
%Bundle-Name
Bundle-SymbolicName: de.ivu.fare.rcp.plugin;singleton:=true
Require-Bundle: org.eclipse.ui - bundle dependencies
Export-Package: de.ivu.fare.rcp.spi - externally visible packages
| [[http://pic.dhe.ibm.com/infocenter/wasinfo/v8r5/index.jsp?topic=%2Fcom.ibm.websphere.osgi.nd.doc%2Ftopics%2Fra_bundle_mf.html|Explanations]] and [[http://help.eclipse.org/juno/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fmisc%2Fbundle_manifest.html|Examples]] |
|plugin.xml, feature.xml| Any Extension and Extension-Point declaration, dependency. Plugins and features can be imported here. ||[[http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fmisc%2Ffeature_manifest.html|plugin.xml documentation]], [[http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fmisc%2Ffeature_manifest.html|feature.xml documentation]]|
|Run Configuration|**Additionally** to definin the plugin dependency in the plugin.xml or feature.xml the dependant plugins must be available during runtime. The Environment must be launched together with the plugins.| {{http://i.imgur.com/3mX7v.png?400}} ||
|Target Platform| To make the plugins available for enabling - they must be added to plugin's target platform, which is enabled over preferences. | {{http://i.imgur.com/mUkU0.png?400}} {{http://i.imgur.com/yCL3s.png?400}} ||
==== RCP Basis ====
===Eclipse RCP Glossar===
**Eclipse concepts**
* **Fragment projects** - subprojects, which do work inside of a host project. Will be merged at runtime with it's parent project. \\ Used for organizing unittests, because can access all resources, even those which are not a part of the external API. \\ Used for organizing unittests localization files. \\ DON'T FORGET TO ADD THE NEW FRAGMENT PROJECT THE RUN CONFIGURATION
*
**RCP concepts**
* **Eclipse Plugin** - alias Component. alias Bundle in OSGi. In Eclipse everything is a plugin. The Plugin is the smallest logical unit. The Eclipse IDE allows the developer to extend the IDE functionality via plug-ins. Its a module, which implements some logic. It can be added or removed at runtime. Multiple plugin versions can be installed simularily. From the technical point of view a plugin is a set of files and a manifest.
* **Dependencies** - list of jar libs, which are required for this project
* **Extenson points** - Plugins define them. If a plugin defines an extension point - it allows other plugins to extend it's functionality by using the predefined contract. The contract is defined in form of an interface.
* **Extensions** - Plugins define them. To contribute functionality to another, extension-point defining host-plugin, the code is injected in form of an extension. Host-plugin knows, how to use the plugins' contributed functionality. Host-plugin talks to sub-plugins through an interface, defined by the host-plugn during the definition of the extension point.
* **[[http://www.vogella.com/articles/EclipseFeatureProject/article.html|Feature]]** - Contains a list of plugins and other features. Feature combines plugins and other features to a logical unit.
* **[[http://www.vogella.com/articles/EclipseCommands/article.html|Command]]** - Command is a declarative (created in an xml, using a wizard) describtion of a component, which will be executed by this command. The implementation is inside the handler, independant from the component. Commands can be assigned to menus, toolbars, key bindings. Actions is the old pre-command concept, where the execution is not outsourced into a handler.
* **RCP Application** - A RCP Application is made of RCP plugins + the eclipse framework on which they run + custom plugins.
* Applications are like the Java main() method. They are found and started by Equinox (OSGi implementation on Eclipse)
* Applications seem to be like Activities in Android, because they implement a logically separated part of logic and work together in a branded product.
* Applications are defined via the extension point org.eclipse.core.runtime.applications and must extend IApplication.
* **Product** - is one level above the applcation. A product has 1 to many applications, adds branding, icons, jar libraries to the product! A product allways points to an application, which will be started first, on product start. Since Eclipse RCP 4 a product is required to launch Appplications, before that a product was optional.
**GUI**
The details about what GUI part own what are listed [[http://www.eclipse.org/articles/Article-UI-Workbench/workbench.html|here]]. \\
**An Introduction into GUI extensions, which are listed below is found [[http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Fguide%2Fworkbench.htm|on eclipse's own page]]**
* **Views** - GUI parts with a concrete functionality. (E.g. the view "Project Explorer" to display project's structure)
* adding views as Standalone vs. non-Standalone - Views can become standalone, when they are added to the perspective. Views can be detached from the workbench and become an own window. \\ (declaratively in a wizard or in code) \\ {{http://i520.photobucket.com/albums/w327/schajtan/2012-06-18_13-19-20.png?800}} \\ The difference is:
* the standalone views can't be put together, so that the View-Tabs are side by side.
* the standalone views can hide own view-Toolbars by setting View's constructor parameter showTitle=false
* **Editors** - GUI parts for editing files of different types. (E.g. Text or HTML Editor). Contrary to the Views - Editors can't be detached from the Workbench.
* **Perspective** - defines the position, layout of views, editors needed for this perspective's purpose (E.g. Java-perspective). Perspectives are contained in workbenches. \\ Think of perspectives as a set of layout hints for windows - they do not own the Views and Editor, just the layout Information. The WorkbenchWindow consults the perspective to do the initial layout.
* **Workbench** - the main Windows in Eclipse, which contains one or more persepectives. The Lifecycle and more info is found [[http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Fguide%2Frcp_advisor.htm|found here]] initialize - called first; before any windows; use to register things
preStartup - called second; after initialize but before first window is opened; use to temporarily disable things during startup or restore
postStartup - called third; after first window is opened; use to reenable things temporarily disabled in previous step
postRestore - called after the workbench and its windows have been recreated from a previously saved state; use to adjust the restored workbench
preWindowOpen - called as each window is being opened; use to configure aspects of the window other than action bars
fillActionBars - called after preWindowOpen to configure a window's action bars
postWindowRestore - called after a window has been recreated from a previously saved state; use to adjust the restored window
postWindowCreate - called after a window has been created, either from an initial state or from a restored state; used to adjust the window
openIntro - called immediately before a window is opened in order to create the introduction component, if any.
postWindowOpen - called after a window has been opened; use to hook window listeners, etc.
preWindowShellClose - called when a window's shell is closed by the user; use to pre-screen window closings
eventLoopException - called to handle the case where the event loop has crashed; use to inform the user that things are not well
eventLoopIdle - called when there are currently no more events to be processed; use to perform other work or to yield until new events enter the queue
preShutdown - called just after event loop has terminated but before any windows have been closed; allows the application to veto the shutdown
postShutdown - called last; after event loop has terminated and all windows have been closed; use to deregister things registered during initialize
* **Coolbar** alias **Application Toolbar** alias **WorkbenchWindowToolbar** - the main toolbar with command buttons at the top. \\ {{http://i520.photobucket.com/albums/w327/schajtan/2012-06-18_12-35-31.png}}
* **View Toolbar** - every View can have its own toolbar \\ {{http://i520.photobucket.com/albums/w327/schajtan/2012-06-18_12-35-57.png}} {{http://i520.photobucket.com/albums/w327/schajtan/2012-06-18_12-37-08.png}}
== An overview over the Workbench hierarchy ==
{{http://i237.photobucket.com/albums/ff137/skipidar/Screenshot-2012-06-13_154642.png}}
{{http://i47.tinypic.com/5yf0wl.png}}
{{http://i237.photobucket.com/albums/ff137/skipidar/Screenshot-2012-06-15_115221.png}}
**SYSTEM**
* **[[http://help.eclipse.org/indigo/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/ui/application/WorkbenchAdvisor.html|WorkbenchAdvisor]]** - is the invisible component, which controlls the apearance of the application \\ (menus, toolbars, persepctives..)
* initialize
* preStartup
* postStartup
* postRestore
* preWindowOpen
* fillActionBars
* postWindowRestore
* postWindowCreate
* postWindowOpen
* preWindowShellClose
* eventLoopException
* eventLoopIdle
* preShutdown
* postShutdown
* **[[http://help.eclipse.org/indigo/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/ui/application/WorkbenchWindowAdvisor.html|WorkbenchWindowAdvisor ]]** - is the invisible component, which controlls the window. Every window has one.
* preWindowOpen, which can set the window size, disable toolbars etc.
* postWindowCreate, which has the knowledge about the existing window
* postWindowOpen, which can add listeners to the existing window
* preWindowShellClose, clean up
* **[[http://help.eclipse.org/indigo/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/ui/application/ActionBarAdvisor.html|ActionBarAdvisor]]** - can add actions (commands) to any actionbar (menubar, toolbar etc.) inside the workbench
* **BundleActivator Activator** - Activator controls the plugin lifetime. This class gets events, when the plugin is loaded, installed, deleted etc.
* **IApplication Application** - classes, which implement this interface - represent a main entry point, means this class can be executed, if it was defined inside of the plugin.xml
==== Configuring the IDE for a new Project ====
When creating a new Eclipse RCP project, it is a good idea to do the following:
Go to **Eclipse Menu> Run> Run Configurations**
^What to do ^Illustration ^
|Let the Eclipse clear the **workspace data** on every launch, by setting the checkbox to clear on the "Main" Tab. Workspace data are everything, what is cached inside of the project. The cache is workspace dependant in Eclipse and is saved in .metadata folder. | {{http://i520.photobucket.com/albums/w327/schajtan/2012-07-29_21-06-51.png?400}} |
|Enable "all workspace and required plugins"| {{http://i520.photobucket.com/albums/w327/schajtan/2012-07-29_21-11-28.png?400}}|
|
Let Eclipse clear the **configuration area** before launching.
This is the location where Eclipse stores essential runtime metadata and cached data in general.
* Plug-ins may choose to store data here that should be available regardless the workspace in use (for instance, help index files).
* User settings shared across workspaces are also stored under this location.
| {{http://i520.photobucket.com/albums/w327/schajtan/2012-07-29_21-13-06.png?400}} |
|Save the configuration as a persistent "shared file" in a separate Eclipse-Project (Common Tab)| {{http://i520.photobucket.com/albums/w327/schajtan/2012-07-29_21-15-06.png?400}} |
==== Eclipse RCP Plugin Structure ====
* **Extension Registry** - Eclipse defines //extension points// (hooks) which Extensions use to hook in (contribute). \\ The Information is added by using XML Manifests \\ When the hook is activated - Equinox (OSGi) instantiates the class, which implements a predefined interface and calls //run()//
// extension point is defined by Eclipse
// org.eclipse.ui/plugin.xml
">
{{http://i46.tinypic.com/2ypkbbt.png}}
==== Dependencies Management in Eclipse ====
Documentation:
^Location ^Documentation^
|**feature.xml**|[[http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fmisc%2Ffeature_manifest.html|Documentation]]|
|**plugin.xml**|
[[http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fmisc%2Ffeature_manifest.html|Documentation]] \\
[[http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.pde.doc.user%2Fguide%2Ftools%2Feditors%2Fmanifest_editor%2Fdependencies.htm|Dependencies per GUI]]
|
|**MANIFEST.MF**|[[http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fmisc%2Ffeature_manifest.html|Documentation]]|
Eclipse Dependencies have different Levels:
^Level ^ Describtion ^ Configuration File^
|OSGI| The OSGI is a specification, which defines possible jars attributes: visibility, dependency from other jars. Jars are called **bundles** here. In Eclipse **bundles=plugins** | **OSGI-INF/Manifest.MF** |
|Eclipse RCP| Eclipse Introduces Concepts like **Product, Feature, Application, Target**. Those are only configuration files which help to manager resources and dependencies. They do not exist after exporting the Eclipse Application to a Java Programm. | **product.xml, plugin.xml, feature.xml, target.xml**|
{{http://i520.photobucket.com/albums/w327/schajtan/2014-02-23_23-20-35_zps6785b520.png}}
|OSGI Level dependencies| All OSGI dependencies - are dependencies that are defined in **MANIFEST.MF**'s **Require-Bundle** area. This is the importand dependency, which will remain after product export.|{{http://i520.photobucket.com/albums/w327/schajtan/2014-02-23_23-47-17_zpsfd611cda.png?300}}|
|Describes Product in Extension Point| The Product.xml is just a configuration files to enable forms to manage icons, and stuff. The framework retrieves the product not from this file, but from an **an associated plugin.xml**. There the product describtion is saved under an **extension point org.eclipse.core.runtime.products** |{{http://i520.photobucket.com/albums/w327/schajtan/2014-02-23_23-43-22_zpsaa1ec223.png?300}} {{http://i520.photobucket.com/albums/w327/schajtan/2014-02-23_23-41-34_zpse6acdf38.png?300}}|
|Contains any plugin which will be used in Product.| Plugins/Features **from Workspace** are "added", not inserted as dependencies.|{{http://i520.photobucket.com/albums/w327/schajtan/2014-02-23_23-35-04_zps2f9309de.png?300}}|
|Depends on foreign features| Dependencies to features/plugins **on remote repositories**, resolved via target platform - are defined on **Dependencies-Tab**. They can be computed automatically, by pushint the **Compute** button. | {{http://i520.photobucket.com/albums/w327/schajtan/2014-02-23_23-30-41_zpse361dfe8.png?300}}|
||||
=== Libs dependencies in Project ===
If a project requires an external libraries
* create a new **plugin-project** and add those libraries to the subfolder, e.g. "lib"
* add the "lib" subfolder to the **classpath**
* and **export all packages** which should be visible from outside
This will allow to check in the libs to the version control and make the project completely portable, avoiding problems with unavailable external repos. So it can be checked out even years later and compiled again!
{{http://i520.photobucket.com/albums/w327/schajtan/2014-02-23_23-53-12_zpse3fee24b.png?800}}
=== Storing Libs in a local repository ===
A local p2 repository can be set up, by exporting a project.
The local repository can then be references from the product as
"file://d:/Temp/E4Produkt/repository/"
[[http://www.bsiag.com/scout/local-p2-mirrors-to-work-offline/|Here]] is the describtion about how to do it.
Using a p2-repository will allow Maven-Tycho (the headless build plugin) to resolve dependencies automatically.
[[https://wiki.eclipse.org/Tycho/Target_Platform|It is capable to resolve dependencies from p2-sites, plugins. Not from directories.]]
=== Tool ===
To analyse the dependencies there is a tool: Plug-in Dependency Visualization
Here is a p2 repository to install the tool which is aplugin: http://www.eclipse.org/pde/incubator/dependency-visualization/
Open the View "Graph Plug-In Dependency"
{{http://i520.photobucket.com/albums/w327/schajtan/2014-03-24_22-12-01_zpscaad609a.png}}
==== Dependency resolutions ====
^What ^ Konzept ^ Can Dependend from^
|Plugin | Is an OSGI Bundle | Plugins|
|Features| Is a Container | Plugins, Features|
|Product | Is a UI representation for an Application in a Plugin. Needs concrete Application from Plugin maybe in a Feature | Plugins OR Features|
During the compile time the compiler searches in this dependencies for the needed classes.
**Run Configurations** - are an Eclipse concept. Here the define Plugins, which your bundle depends on, **when run in IDE**. Run Configurations are independant from what the dependencies, which are defined on OSGI level (in Plugins, Features, Products).
The run configuration must contain the same dependencies as the dependencies on OSGI level.
== Runtime configuration ==
The runtime configuration is an often seen error source. \\
For the new Project use the follwing run-configurations settings: \\
Go to Eclipse Menu > Run > Run Configurations > [your configuration]
* Set Eclipse to automatically validate the plugin dependencies on every run. \\ Eclipse will see the missing plugins and warn you.
* Launch with "all workspace and enabled plug-ins" \\ Eclipse will use all available plug-ins.
{{http://i.imgur.com/NsHtJ.png?600}}
Alternatively you can choose needed plugins by doing "Add Required Plug-Ins", instead of importing everything by choosing "all workspace and enabled plug-ins".
== In Features ==
In plugin.xml > Dependencies-Tab.
== In Plugins ==
In plugin.xml > Dependencies-Tab.
== In MANIFEST.MF ==
Here the dependencies are entered on OSGI level. (as Bundles) \\
Here you can define dependiencies on bundles (plugins are bundles) by adding them to the **Require-Bundle** Point.
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
de.ivu.fare.libs;bundle-version="0.0.0"
== In Maven ==
Maven maintains dependencies on its own. By using different extensions it can read dependencies from:
- MANIFEST.MF
- Eclipse RCP Plugins
- Eclipse RCP Fragments
- Eclipse RCP Features etc.
For the the right type should be defined inside of maven's onfig file "pom.xml". [[http://wiki.eclipse.org/Tycho/Packaging_Types|Here]] is the full list of plugin types.
== Managing application dependencies ==
**VERY IMPORTANT**
-
During the development the plugins are managed inside of the Eclipse IDE.
When executed - the plugins are imported from the launch configuration.
**[Eclipse > Run > Run Configurations]**
There the plugins can be imported automagically by pushing [Plugin-Ins Tab > Add required Plugins]
-
Then, to be able to export the Eclipse application as standalone you have to add all dependant plugins to your applicaiton, without a Launch Configuration.
For that export the plguin dependencies from the Runtime-Configurations to a feature and ad the feature to application dependencies.
* go to **[Eclipse > Run > Run Configurations > Common Tab]**
* share the run configuration by specifying a directory (it gives it a name automatically), apply and close the dialog.
* Create a new Feature Project, call it something like 'org.com.product.dependencies'
* Select Initialise from Launch Configuration and choose the one you just shared. Then include this feature in your Product Configuration. Voila!
==== Eclipse RCP Target Platform ====
a collection of Eclipse plugins, required for the own plugins. See this as a storage, with all libraries needed for your project.\\
A new Target is created as following:
{{ http://i49.tinypic.com/25ahnx2.png }}
- Create a new project, to store the target
- Create minimum two folders in the project: for the **delta-pack** and the **rcp-sdk** and maybe further folders for further plugins.
- Delta-pack is needed needed to make the new plugin cross platform executable. Available under [[http://download.eclipse.org/eclipse/downloads/drops/R-3.7.2-201202080800/#DeltaPack|delta-pack zip]].
- Eclipse RCP-SDK, needed to use the rcp api. Available under [[http://download.eclipse.org/eclipse/downloads/drops/R-3.7.2-201202080800/#RCPSDK| RCP-SDK]].
- ATTENTION: the delta-pack and the sdk must have the same version!
- Create a new Target Definition: New > Plug-In Development > Target Definition
- Add the delta-pack and the rcp-sdk Directories to the locations, by using double-clicking on the new Target Definition.
The Target Platform is normally stored in a separate Eclipse project, to see the libaries in Eclipse's GUI. \\
The Target Platform can be switched for the whole IDE only:
{{http://i237.photobucket.com/albums/ff137/skipidar/Preferences-2012-06-13_152128.png?600}}
==== Adding Views and Editors ====
The Views can be added in a special wizard or programmatically.
Two steps are needed to create a new View:
- Definition (definition in the wizard, backing by a View class)
- Appending to a perspective, since perspectives do layout views
Editors are layed out automatically, by the workbench. For that reason they are not appended to the perspective.
The initial, main perspective can only set Editors as visible or invisible.
==1. Instantiation / creation==
Views are defined declarative, in the plugin.xml, by using a wizard: \\
Go to plugin.xml in your Eclipse RCP Project, \\
Go to the "Extensions Tab" \\
Use add to create a new "org.eclipse.ui.views" Extension , if there is none\\
{{http://i237.photobucket.com/albums/ff137/skipidar/Screenshot-2012-06-14_090503.png?600}}
Use Richtclick on "org.eclipse.ui.views" > New to create a new View.
{{http://i237.photobucket.com/albums/ff137/skipidar/Screenshot-2012-06-14_090744.png }}
Fill in the id an name and click on the "class" Link, to create a new Class. It is a good Idea to add a Static String "ID" to the new Class, with the dublicated id, which you have chosen in this step.
{{http://i237.photobucket.com/albums/ff137/skipidar/Screenshot-2012-06-14_090911.png}}
{{http://i237.photobucket.com/albums/ff137/skipidar/Screenshot-2012-06-14_091152.png?600}}
==2. Appending to a perspective==
Views are added inside of the Perspective, altrough the Workbenchpage is the GUI part, which owns Views. The Perspective is responsible for views layout, so Views are added inside of the perspective.
**Appending a View programmatically to the perspective:**
package de.vogella.rcp.intro.view;
import org.eclipse.ui.IPageLayout;
import org.eclipse.ui.IPerspectiveFactory;
public class Perspective implements IPerspectiveFactory {
public void createInitialLayout(IPageLayout layout) {
layout.addView("de.vogella.rcp.intro.first.MyView", IPageLayout.TOP,
IPageLayout.RATIO_MAX, IPageLayout.ID_EDITOR_AREA);
//multiple instances of a view can be added to one Workbench, if allowMultiple="true" is set in plugin.xml
layout.addView(View.ID+":1", IPageLayout.LEFT, 0.5f, IPageLayout.ID_EDITOR_AREA);
layout.addView(View.ID+":2", IPageLayout.RIGHT, 0.5f, IPageLayout.ID_EDITOR_AREA);
}
}
**Appending a View declaratively, inside of the wizard:**
Inside of plugin.xml, on "Extensions Tab" add a new "org.eclipse.ui.perspectiveExtensions" Extension \\
Append a new "perspectiveExtension" under the "perspectiveExtension**s**" \\
Append a new "view" with the previously defined id under the "perspectiveExtension"
{{http://i237.photobucket.com/albums/ff137/skipidar/Screenshot-2012-06-14_092343.png?600}}
==== Eclipse RCP Product ====
Product can be creates as a
- feature based
- plugin based
{{http://i.imgur.com/jexwN.png?600}}
=== Dependencies between Product related files ===
{{http://i.imgur.com/dgFC8.png?800}}
^What^ Describtion^
|Product Definition| is located in a ***.product file**. Defines the application, which is started on launch (entrypoint). Defines .exe Icons, Licenses etc. for the product. The product points on a plugin, which contains the configuration itselfe. It is based on a feature, which contains the plugin.|
|Feature | is located in a **feature.xml**. Groups the plugins, so that they can be imported into Apps as a unit. Contains the entrypoint among other plugins |
|Plugin (Entrypoint)| is located in a **plugin.xml**. Contains the product definition in the Extensionpoint "org.eclipse.core.runtime.products". There is defined the application, which is started on launch of a product. |
|Launch Configuration| Is an Eclipse IDE concept, is located under **Toolbar > Run > Run Configurations.** Starts a Product. Defines required plugins, which are loaded on launch. The required plugins are listed in the plugin.xml too. So the required plugins in launch configuration are redundant. |
=== Create an Eclipse RCP Product ===
The products should be maintained in separated projects. \\
This are the necessary points for product creation:
* create a "Plugin Project" for Products
* create a new "Product Configuration" inside the new project
* Product Configuration - contains product definitions inside of: plugin.xml > org.eclipse.core.runtime.products Extension
* Product Definitions in Product Configuration:
* do know about the application, which will be executed on Product start / know
* do know about the plugin, which is used to brand the product
* Choose wether your plugin is Feature or plugin based. Dependencies are resolved differently.
* feature based produkt (Dependencies are managed by features) Feature based plugins need the **org.eclipse.rcp** in their Included-Features. Or there may be:
- plugin-validation problems (plugin dependency problems)
- //java.lang.ClassNotFoundException: org.eclipse.core.runtime.adaptor.EclipseStarter ..// problems \\ {{http://i.imgur.com/OYXwn.png?600}}
* plugin based produkt (Dependencies are managed by plugins, can be resolved automatically)
* automatic dependencies resolution: product > Dependencies > "Add required Plugins" Button
=== Make changes in a Product ===
The *.product is a come-together of many files, like ocnfig.ini, defining plugin and feature files.
These files are not synchronized automatically with the plugin, which means that changing the product doesn't automatically change the files below.
Explicite Synchronizing is required, which is done as following:
- Push the "Synchronize" link inside of the product editor \\ {{http://i.imgur.com/h28wG.png?600}}
- Push one of the "Launch" Links inside of the product editor. The Plugin Development Environment will synchronize the product automatically.
==== Exporting the product to a separate application ====
before exporting add the required resources, since the eclipse adds automatically the java files only.
To add the other resources, like images, css, icons, Application.e4xmi(in Eclipse RCP 4) set the hooks for required resources in the **Build** section of the **build.properties**
{{ http://i237.photobucket.com/albums/ff137/skipidar/Screenshot-2012-06-12_131842.png }}
After that click "Eclipse Product export wizard" in the product Oberview-Tab.
{{ http://i237.photobucket.com/albums/ff137/skipidar/Screenshot-2012-06-12_132806.png }}
==== Editors ====
Initial View can set Editors as
* visible or invisible,
* fixed or draggable
* or add the Views to the Editor? (why since, Views are not owned by Editors but by workbenchWindows?)
Example : \\
public class Perspective implements IPerspectiveFactory {
public void createInitialLayout(IPageLayout layout) {
String editorArea = layout.getEditorArea();
layout.setEditorAreaVisible(true);
layout.setFixed(true);
layout.addStandaloneView(View.ID, false, IPageLayout.LEFT, 1.0f, editorArea);
}
}
==== Commands ====
* The details about the command creation are listed [[http://www.vogella.com/articles/EclipseCommands/article.html#menus_extensionpoint|here]].
* The full list of Eclipse Command is listed [[http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fui%2Factions%2FActionFactory.html|here]]
Relevand Extension Points:
* //org.eclipse.ui.command// - define new commands here
* //org.eclipse.ui.menu// - define in which menues the command will be visible
* the location is defined by the locationURI. LocationURIs are listed [[http://www.vogella.com/articles/EclipseCommands/article.html#menus_extensionpoint|here]]
* //org.eclipse.ui.handler// - the Handler defines the behaviour of the command
== Define commands ==
The following steps are needed to define a new command:
* use an Extension Point **org.eclipse.ui.commands**
* add a new "Command"
* define a "defaultHandler" Class by clicking on the "defaultHandler"-Link. The Handler will implement the functionality of the command.
* override the command method **isEnabled()** to return **true**. Otherwise the command will be greyed out.
* override the command method **isHandled()** to return **true**. Otherwise the handler will not be called and an //org.eclipse.core.commands.NotHandledException// exception will be thrown
After that the command is defined, but will not appear anywhere yet. It should be explicitely added to the Toolbar or MenuBar.
{{http://i520.photobucket.com/albums/w327/schajtan/2012-06-18_12-20-20.png?600}}
== Add commands to the MenuBar ==
The following steps are needed, to add command to a Menu on the MenuBar (the MenuBar on the Workbench-Window):
- use an Extension Point **org.eclipse.ui.menus**
- add a new "MenuControbution" with the following locationURI: //menu:org.eclipse.ui.main.menu//
- add a new "Menu"
- add a new "Command" to the menu. "New command", because the command is added by doing rightClick>new>command. \\ The "command" entry itself is not really defined here. It is only a crossreference(by id) to the previously defined command. \\ The comands can be predefined by Eclipse or it can be your own commands.
**Important:** The following is done, when the comand is added to the menu, not when the command is created:
- Icon definition is done every time, when the command is added to the menu
- "Command Name" is done every time, when the command is added to the menu
{{http://i520.photobucket.com/albums/w327/schajtan/2012-06-18_12-01-36.png?600}}
On the picture two commands are added to the menu:
* previously defined "Say Hello" command
* eclipse defined "Exit" command
== Add commands to the CoolBar (WorkbenchWindow toolbar) ==
The following steps are needed to add the command to the ToolBar:
- first make the Toolbar with the coolbar (toolbar with command-buttons at the top) visible by doing the following inside of the //WorkbenchAdvisor.preWindowOpen//:
public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {
...
public void preWindowOpen() {
configurer.setShowCoolBar(true);
...
}
}
- use an Extension Point **org.eclipse.ui.menus**
- add a new "MenuControbution" with the following locationURI: //menu:org.eclipse.ui.main.menu//
- add a new "toolbar"
- add a new "Command" to the toolbar as. just as it can be done to teh menu. "New command", because the command is added by doing rightClick>new>command. \\ The "command" entry itself is not really defined here. It is only a crossreference(by id) to the previously defined command. \\ The comands can be predefined by Eclipse or it can be your own commands.
{{http://i520.photobucket.com/albums/w327/schajtan/2012-06-18_12-19-36.png?600}} {{http://i520.photobucket.com/albums/w327/schajtan/2012-06-18_12-35-31.png}}
== Add commands to the View's own ToolBar ==
To add a command to an exisiting, visible view do the following:
- use an Extension Point **org.eclipse.ui.menus**
- add a new "MenuControbution" with the following locationURI: //toolbar://
- add a new "Toolbar"
- add a new "Command" to the toolbar as. just as it can be done to teh menu. "New command", because the command is added by doing rightClick>new>command. \\ The "command" entry itself is not really defined here. It is only a crossreference(by id) to the previously defined command. \\ The comands can be predefined by Eclipse or it can be your own commands.
{{http://i520.photobucket.com/albums/w327/schajtan/2012-06-18_13-51-40.png}}
{{http://i520.photobucket.com/albums/w327/schajtan/2012-06-18_12-35-57.png}}
== Add dropdown's instead of buttons ==
The dropdowns are represented by a fake-command with an ID //fake-commandID// in the toolbar. \\
The container, which contains the real commands is a MenuContribution with the id
- The new fake-command is added to the toolbar (WorkbenchWindow or View's own toolbar)
- The container, which contains the dropdown commands themselfes - is a MenuContribution with the locationURI "menu://fake-commandID//".
{{http://i520.photobucket.com/albums/w327/schajtan/2012-06-18_15-27-08.png?600}}
So 3 things are necessary to create a dropdown:
- use an Extension Point **org.eclipse.ui.commands** to create a new fake-command, which will represent the dropdown
- add the fake-command to the toolbar in some menu
- create a new "menuContribution" with a locationURI //toolbar:org.eclipse.ui.main.toolbar//
- add a new "toolbar" to the defined "menuContribution"
- add the fake-command to the new toolbar
- add a "menuContribution" to Menus with a locationURI //menu://. \\ Here the commands, which should appear in the dropdown are added.
{{http://i520.photobucket.com/albums/w327/schajtan/2012-06-18_15-18-21.png}} {{http://i520.photobucket.com/albums/w327/schajtan/2012-06-18_15-18-54.png}}
== Add commands to View's conteextmenu ==
Every View can hava a context-menu. The describtion about the context-menu creation is [[http://www.vogella.com/articles/EclipseCommands/article.html#contextmenu|here]].
{{http://i520.photobucket.com/albums/w327/schajtan/2012-06-18_17-20-09.png}}
==== Extension Points ====
The details about Extension Points definition are [[http://www.vogella.com/articles/EclipseExtensionPoint/article.html|here]]
In short, to define an extension point do: \\
- define the extension-point
- Add a new extenson-point **inside of the plugin.xml wizard > inside of the "Extension Points" Tab**.
- The Wizard will link an ***.exsd file**, where the requirenments for the Extensions are defined at least. (e.g Extension should contribute a class, which implements Interface X)
- If the users of this extension-point will contribute a classes you will have to **define an Interface** for those classes to fulfill.
- Don't forget to make the package with the new **interface public, by exporting it**. \\ {{http://i.imgur.com/AsLzb.png}}
- Write code to load the contributed functionality, which will be injected through the new extension point
- use the loaded functionality inside of the extension-point provider (load views, tables, classes - whatever you need from external components)
- implement plugins, which will contribute functionality, though the new extension-point
==Definition==
- **Inside of the plugin.xml wizard > inside of the "Extension Points" Tab** define a new Extension Point \\ {{http://i.imgur.com/zvLx2.png?600}}
- Inside the **Schema-exsd-file** create a new element, which will contain some requirements(required attributes) for the contributors to fullfill. \\ {{http://i.imgur.com/QTKtb.png?600}}
==Loading contributors ==
Loading the plugins, which contribute functionality by using my extension point.
For example inside of the Activator.start() you can do:
public class Activator extends AbstractUIPlugin {
...
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
//Evaluation of the extensions
System.out.println("Evaluation of Extensions in "+this.getClass().getName());
//getting the Registry with the contributing extensions all existing extensions for the defined extension-point-ID
final IConfigurationElement[] config = RegistryFactory.getRegistry()
.getConfigurationElementsFor(
IGreeter.IDS.EXTENSION_POINT_ID);
...
}
...
}
==Use the loaded contributors ==
Evaluate the contributed information. Do something with the new functionality.
In the same class, where the loading was done do:
public class Activator extends AbstractUIPlugin {
...
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
//Evaluation of the extensions
System.out.println("Evaluation of Extensions in "+this.getClass().getName());
//getting the Registry with the contributing extensions all existing extensions for the defined extension-point-ID
final IConfigurationElement[] config = RegistryFactory.getRegistry()
.getConfigurationElementsFor(
IGreeter.IDS.EXTENSION_POINT_ID);
try {
for (IConfigurationElement e : config) {
System.out.println("Evaluating extension");
final Object o =
e.createExecutableExtension("class");
if (o instanceof IGreeter) {
executeExtension(o);
}
}
} catch (CoreException ex) {
System.out.println(ex.getMessage());
}
}
...
}
== Create a contributing plugin, which will use the extension ==
Use the new extension-point as you used eclipse-own extension points.
**ATTENTION:** \\
When defining own contributors and trying to run the Extension-Point Plugin with a new contributor-Plugin: \\
include the new contributor-plugin into the run-configuration:
{{http://i.imgur.com/tgTCo.png}}
==== Eclipse preferences ====
In detail preferences are explained [[http://www.vogella.com/articles/EclipsePreferences/article.html|at Vogella]] and in an [[http://www.eclipse.org/articles/Article-Field-Editors/field_editors.html|Eclipse Article]]
== Basics ==
* Preferences are key/value pairs
* Abstract preferences are organized into into **nodes** in Eclipse. The root node is followed by special nodes, which are called scopes {{http://i.imgur.com/ynzxk.png}}
* Nodes are accessed as following:
Preferences preferences1 = Platform.getPreferencesService().getRootNode().node(ConfigurationScope.SCOPE).node("pluginid");
Preferences preferences2 = new ConfigurationScope().getNode("pluginid"); //same node is accessed
* Scopes are special Nodes. There 3 kind of scopes.
* **INSTANCE** scope - If the user runs the same program twice, the settings between the two programs may be different.
* **CONFIGURATION** scope - If the user runs the same program twice then the settings between the two programs are the same.
* **DEFAULT** scope - Default values which can not be changed. Supplied via configuration files in plugins and product definitions.
*
To add preferences to your extension per Extension-Points:
- use the extenson-point **org.eclipse.ui.preferencePages** to add preferences to the plugin
- use the extension-point **org.eclipse.core.runtime.preferences** to add default values to the preferences, by introducing an initializer class
- add a new Dependency **org.eclipse.equinox.security** to add **secure, encrypted** preferences to the plugin
- own password provider can be registered by using the extension point **org.eclipse.equinox.security.secureStorage**
- create a new menu-entry to make preferences accessable, the details are explained under [[eclipse:eclipse_rcp#commands|Eclipse - Rich Client Platform (RCP)]]
- use Extension Point **org.eclipse.ui.menus** to contribute to hook in into menu definitions
- create a MenuContribution with a locationURI named **menu:org.eclipse.ui.main.menu** and add a new menu
- add a new command named **org.eclipse.ui.window.preferences** which will diplay the preferences
- **accessing the preferences** from different plugins is done by Platform.getPreferencesService().getString(...
- **listening to changes in the preferences** can be done by implementing a IPropertyChangeListener()
To add a set of preferences to your extension programmatically:
- Create a new **PreferencePage**. //PreferencePages// are objects, which represent the visible preference pages. They are responsible for:
- layout of the single preference pages
- reaction to OK / Apply Button, by sending data to the responsible storage
- assigning Editors of different type to every preference from the set of preferences
- Create a new **PreferenceNode**. //PreferenceNode// represents the PreferencePage in the navigation-Tree, which is used to switch between PreferencePages.
- Create a new **PreferenceDialog**. A //PreferenceDialog// window contains a hierarchical presentation of preference pages. Each page is represented by a node in the tree shown on the left hand side of the dialog; when a node is selected, the corresponding page is shown on the right hand side.
- Add the PreferenceNode to the Root-Node or to another PreferenceNode by using a **PreferenceManager**. //PreferenceManager// organizes the //PreferenceDialog// by managing the //PreferenceNode//s and the //PreferencePage//s behind them.
== Adding preference to the plugin ==
The preference pages inside of the preferences menu can be added as following:
* use the extension-point **org.eclipse.ui.preferencePages** with a new page \\ {{http://i.imgur.com/2lgTk.png}}
* implement a new page class, by inheriting from **FieldEditorPreferencePage** and implementing **IWorkbenchPreferencePage** \\ (! the wizard makes the page class inherit from PreferencePage)
public class MyPreferencePage1 extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
public PreferencesPage() {
super(GRID);
}
}
* implement **init(IWorkbench workbench)** which should prepare the preference storage for writing:
setPreferenceStore(Activator.getDefault().getPreferenceStore());
* implement **createFieldEditors()** which should should fill the preference storage with values and assign some predefined editors to them
//registers predefined editors to the values
public void createFieldEditors() {
addField(new DirectoryFieldEditor("PATH", "&Directory preference:",
getFieldEditorParent()));
addField(new BooleanFieldEditor("BOOLEAN_VALUE", "&An example of a boolean preference", getFieldEditorParent()));
addField(new RadioGroupFieldEditor("CHOICE",
"An example of a multiple-choice preference", 1,
new String[][] { { "&Choice 1", "choice1" },
{ "C&hoice 2", "choice2" } }, getFieldEditorParent()));
addField(new StringFieldEditor("MySTRING1", "A &text preference:",
getFieldEditorParent()));
addField(new StringFieldEditor("MySTRING2", "A &text preference:",
getFieldEditorParent()));
}
== Add default values to the plugin preferences ==
* use the extension-point **org.eclipse.core.runtime.preferences** to add default values to the preferences, by introducing an initializer class
* fill the default values in code
public class MyInitializer extends AbstractPreferenceInitializer {
public MyInitializer() {
}
@Override
public void initializeDefaultPreferences() {
IPreferenceStore store = Activator.getDefault().getPreferenceStore();
store.setDefault("MySTRING1", "http://www.vogella.com");
}
}
== Create a MenuContribution and add a new menu entry, add a new command to the menu ==
* Use Extension Point **org.eclipse.ui.menus** to contribute to hook in into menu definitions.
* Create a MenuContribution with a locationURI named **menu:org.eclipse.ui.main.menu** and add a new menu.
* Add a new command named **org.eclipse.ui.window.preferences** which will diplay the preferences.
Details were explained before, in [[eclipse:eclipse_rcp#commands|Eclipse - Rich Client Platform (RCP)]]
== Accessing the preferences from different plugins ==
The preferences can be acessed as following.
== Listening for preferences-changes ==
To listen for preference changes - register a new listener by the default Activator.
**Important:**
Notice, that the method "Activator.getDefault()" only exists in RCP-Plug-Inprojects, \\
when they where created with the hook set by the setting "This plug-in will make contribution to the UI". \\
{{http://i.imgur.com/LvnVG.png}} \\
If this hook was set the generated Activator will extend **org.eclipse.ui.plugin.AbstractUIPlugin**, \\
otherwise it will extend **org.osgi.framework.BundleActivator**
Activator.getDefault() retrieves a class, which controls the plugin life-cycle.
Activator.getDefault().getPreferenceStore()
.addPropertyChangeListener(new IPropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent event) {
if (event.getProperty() == "MySTRING1") {
String value = event.getNewValue().toString()
// do something with the new value
}
}
});
=== Preferences in the toolbar Programmatically ===
The workbench toolbar can be filled with preferences programatically. This is done in the ActionBarAdvisor.
public class MainActionBarAdvisor extends ActionBarAdvisor {
private IWorkbenchAction exitAction;
private IWorkbenchAction aboutAction;
private IWorkbenchAction preferenceAction;
/**
* {@inheritDoc}
*
* @param configurer
* {@inheritDoc}
*/
public MainActionBarAdvisor(final IActionBarConfigurer configurer) {
super(configurer);
}
@Override
protected void makeActions(final IWorkbenchWindow window) {
exitAction = ActionFactory.QUIT.create(window);
register(exitAction);
aboutAction = ActionFactory.ABOUT.create(window);
register(aboutAction);
preferenceAction = ActionFactory.PREFERENCES.create(window);
register(preferenceAction);
}
@Override
protected void fillMenuBar(final IMenuManager menuBar) {
final LocaleService ls = ServiceFactory.getLocaleService();
final MenuManager fileMenu = new MenuManager(ls.translate(Messages.Menu_File), IWorkbenchActionConstants.M_FILE);
final MenuManager helpMenu = new MenuManager(ls.translate(Messages.Menu_Help), IWorkbenchActionConstants.M_HELP);
final MenuManager windowMenu = new MenuManager(ls.translate(Messages.Menu_Window),
IWorkbenchActionConstants.M_WINDOW);
menuBar.add(fileMenu);
menuBar.add(windowMenu);
menuBar.add(helpMenu);
fileMenu.add(exitAction);
windowMenu.add(preferenceAction);
helpMenu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
helpMenu.add(aboutAction);
}
}
==== Internationalization ====
The details to this Topics are explained [[http://www.vogella.com/articles/EclipseInternationalization/article.html|here]]
To set the language different from the Platfrom#s native language use the command Parameter -nl
-os ${target.os} -ws ${target.ws} -arch ${target.arch} -consoleLog -nl en
-os ${target.os} -ws ${target.ws} -arch ${target.arch} -consoleLog -nl de
-os ${target.os} -ws ${target.ws} -arch ${target.arch} -consoleLog -nl ru
-os ${target.os} -ws ${target.ws} -arch ${target.arch} -consoleLog -nl fr
The translations are maintained in ***.properties** files (**LATIN-1 encoded**)
* messages.properties: default language file, if nothing else is available
* messages_de.properties: used for German
* message_en.properties: default for English
* message_en_US.properties: US English file
* message_en_UK.properties: British English file
The main plugin should have one main language.
Additional languages should be separated from the main plugin as **Fragments** and imported, when needed.
== plugin.xml übersetzen ==
Use the Notation **%keyname** to get the language sensitive value from the *.properties file
== Tool ==
Use a Tool to extract all the Strings from a plugin by doing:
Rightclick onto plugin.xml > PDE Tools > Internationalize
There you can extenralize all the String in plugin.xml and MANIFEST.MF
{{http://i.imgur.com/g1Ym0.png}}
And you can choose languages, for which fragments should be created.
{{http://i.imgur.com/DLsix.png}}
**After the fragments are created DON'T FORGET TO :**
- ADD THE NEW FRAGMENT PROJECT TO THE RUN CONFIGURATION \\ {{http://i.imgur.com/DdOsI.png?600}}
- ADD THE "nl" FOLDER TO THE build.properties \\ {{http://i.imgur.com/aMU3u.png?600}}
\\
\\
To Test the new internationalization language add the "-nl " argument to the //run configuration//:
-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl en
-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl de
-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl fr
...
{{http://i520.photobucket.com/albums/w327/schajtan/2014-05-09_11-25-45_zps775c409b.png?600}}
In Elcipse the langauge switching may be done via Arguments. Either Java VM Arguments or Eclipse Arguments.
==Eclipse Arguments==
-nl iw
==Java VM Arguments==
-Duser.language=iw -Duser.country=IL
== Right to Left (RTL) ==
When switching t oarabic or hebrew the UI may be switched to RTL View via the Eclipse Parameter
-dir rtl
== Move *.properties files ==
To move the *.properties to a package
- move the *.properties into a package inside of the main plugin (e.g. package com.example.bang)
- create a package with the same name in the Fragment. Don't bother if your main plugin has sources in another folder structre, like /src/main/java. Put the new package into /src , from there it will be merged with the /src/main/java in the main plugin at runtime.
\\main Plugin
src
|_main
|_java
|_com.example.package
|_ localization.properties
\\Fragment
src
|_com.example.package
|_ localization_en.properties
=== Access *.property Strings programmatically ===
Choose the file you want to translate and do:
Menu > Source > Externalize Strings
This will generate a **messages.property** File and a **Messages.class**.
The Messages.class will contains all the Strings you exported, which will be loaded at runtime.
To add an English translation of the exported Strings just add **messages_en.property** to the Project. \\
Or if you want to copy the messages_en.property to a separate Fragment - don't forget to copy put the messages_en.property into the same folder structure like the messages.property, so that it is merged to the right folder at runtime.
=== Tools ===
Use the Tool http://marketplace.eclipse.org/content/eclipse-resourcebundle-editor to compare translated Strings, to see incomplete translations only!
=== Setting the language manually ===
To set the language manually edit the **config.ini** file.
Prepend the following to the file ///configurations/config.ini//:
osgi.nl=es
==== Branding ====
A Product is required for Branding an Application.
Following things can be customized:
* SplashScreen
* Icons (for the exe after the export)
* about dialog
==Icons==
The .exe Icons for each platform are set inside of the *.product file, on the Launchng-Tab.
{{http://i.imgur.com/VsOf1.png?600}}
The window icons are set inside of the Branding-Tab.
{{http://i.imgur.com/FINx8.png?600}}
==Splash-Screen==
To set a custom Splash Screen - use the Splash-Tab, to choose the plugin, which will provide the SplashScreen. \\
The Splashscreen is provided as a **splash.bmp** file, in the root directory of the plugin.
{{http://i.imgur.com/wkTbw.png?600}}
Optionaly there can be a custom SplashScreen for every provided language.
For that put the **splash.bmp** into a Fragment-Project, which will represent the Internationalization. Read more about Fragments for Internationalization above. \\
The right SplashScreen will be chose, depending on the -nl Run parameter: **-nl fr_FR** or **-nl en**
Here are some examples:
org.eclipse.ui.examples.rcp.browser/
nl/
fr/
FR/
splash.bmp
org.eclipse.ui.examples.rcp.browser/
nl/
en/
splash.bmp
**IMPORTANT:** \\
To define multiple, language specific SplashScreens they have to be added to the config.ini. (**comma separated, with the slashes escaped**)
osgi.splashPath=platform\:/base/plugins/de.ivu.fare.rcp.plugin,platform\:/base/plugins/de.ivu.fare.rcp.plugin.en
Since the config.ini is generated during the export - this parameter can to be set after each export, or defined once in the configuration-Tab.
(**comma separated, DO NOT ESCAPE SLASHES HERE**)
{{http://i.imgur.com/hUgWU.png?600}}
==about dialog==
**About Product**
{{http://i.imgur.com/YPEWF.png?200}}
* To add details-Information on the first level of the about dialog use the product-editor and don't forget to synchronize the product with it's plugin, after you change the text.
* This information can be localized by using an **%aboutText** variable and defining this variable inside of the **plugin.properties** \\
## product's branding-plugins's plugin.xml
## matching plugin.properties
aboutText=aboutText=\n\nIVU.fare\n\n\
Ticketing Backoffice System\n\
\n\
http://www.ivu.de
\n\
\u00A9 2012 Copyright IVU Traffic Technologies AG\
\n
**About Feature**
{{http://i.imgur.com/UcWjt.png?200}}
* To add details-Information on the about_dialog>feature_dialog level add an **about.ini** to the project, where the property **aboutText** should be defined aboutText=%featureAboutText
* This information can be localized by using a **%featureAboutText** variable and defining this variable inside of the **about.properties** \\
## feature's branding-plugins's about.ini
aboutText=%featureAboutText
## matching about.properties
featureAboutText=aboutText=\n\nIVU.fare\n\n\
Ticketing Backoffice System\n\
\n\
http://www.ivu.de
\n\
\u00A9 2012 Copyright IVU Traffic Technologies AG\
\n
==== Help for your app ====
The help is normally outsourcesd into an own plugin. There are two types of help:
- usual, big help dialog \\ {{http://i.imgur.com/zzgWE.png?200}}
- context help, which is activated, when the focus is on a GUI part, for that the cotext help was defined. \\ {{http://i.imgur.com/Qi898.png?200}}
==Help dialog==
To define a help dialog:
- Create a plugin-project which will manage the help, by using the "Plug-in with sample help content" template: \\ {{http://i.imgur.com/GOgof.png?200}} {{http://i.imgur.com/EovxT.png?200}}
- For **plugin-driven** product add the folliwng plugin-dependencies:
org.eclipse.help.ui
org.eclipse.help.webapp
org.eclipse.equinox.http.jetty or for **feature-driven** product add the following feature-dependencies:
org.eclipse.help
org.eclipse.ui.forms
- make your product dependant on the help-providing plugin
- embed following commands to open the help:
org.eclipse.ui.help.displayHelp - Opens the help
org.eclipse.ui.help.helpSearch - Open the Search
==Context Help==
The context-sensitive help should be contributed by the help providing plugin. For add teh following **to the plugin, which contributes the help**:
- create a new context.xml by doing new -> Context Help \\ {{http://i.imgur.com/Z7185.png?200}}
- use the Extension-Point org.eclipse.help.contexts
- to point to the context.xml with the context help
- to point to the plugin, where the help will be activated **(not to the plugin, which contains the help)** \\ {{http://i.imgur.com/pWTDw.png?200}}
**Inside the product project** (not the help contributing plugin) use the code to add context sensitive help:
public class MyView extends ViewPart {
public final static String ID = "de.vogella.rcp.intro.help.MyView" ;
@Override
public void createPartControl(Composite parent) {
Text text = new Text(parent, SWT.BORDER);
text.setText("Imagine a fantastic user interface with help here");
//ADD CONTEXT-HELP TO THE PARENT. THE CONTEXT_HELP IS CONTRIBUTED BY ANOTHER PLUGIN
PlatformUI.getWorkbench().getHelpSystem().setHelp(text, "de.vogella.rcp.intro.help.message");
...
Select the GUI Part, which you added teh help to and push **F1** to open the context sensitive help.
==== Importing Jars a RCP Plugin ====
Plugins are OSGI Bundles. \\
OSGI Bundles can only depend on OSGI bundles.\\
JARs have to be wrapped as OSGI Bundles to be used inside Plugins. \\
There is a Wizard, which allows to define a new Plugin, based on JAR libraries:
New> Other> Plug-in Development > Plug-In from Existin JAR Archivces
{{http://i.imgur.com/JTgQg.png}}
==== Download the Eclipse RCP updatesite ====
To install Eclipse plugins offline you have to download the updatesite.
Here is an example to download instasearch.
set eclipse_home="D:\Programme\_Development\Eclipse Mars - RCP\eclipse.exe"
set updatesite=http://dl.bintray.com/ajermakovics/InstaSearch/
set folder=d:\Temp\instasearch\
%eclipse_home% -application org.eclipse.equinox.p2.artifact.repository.mirrorApplication -source %updatesite% -destination %folder%
%eclipse_home% -application org.eclipse.equinox.p2.metadata.repository.mirrorApplication -source %updatesite% -destination %folder%
===== Eclipse RCP 4 =====
//create and open an MPart from class A. Which methods are triggered?
class A{
@PostCOnstruct
postConstruct(){
// is triggered! postConstruct supports inheritance
}
@Focus
onFocus(){
// NOT triggered! onFocus in only triggered on the top of the inheritance levels!
}
}
class B extends A{
@PostCOnstruct
postConstruct(){
// is triggered! postConstruct supports inheritance
}
@Focus
onFocus(){
// is triggered, because B is the top level inheritance class
}
}
* Injections will only be processed in classes, which are referenced in Application Model. \\ (see [[http://www.vogella.com/tutorials/EclipseRCP/article.html#d234227e2830|On which objects does Eclipse perform dependency injection?]])
==== Target Platform ====
ACHTUNG:
- When adding stuff from the platform \\ **Remove the Group by Category flag and add the following components.** \\ **Or some plugins will not be listed**!!!!!!!
A custom Target Platform contains all the artifacts, which teh projects depends on. (libs)
== IDE Independent Target Platform ==
Just copy the **plugins** dir form your IDE to a libs dir and point the target platform to this direction.
This will protect the project from IDE changes and uncontrolled installation of incompatible plugins.
{{http://i520.photobucket.com/albums/w327/schajtan/2014-08-19_10-37-59_zps7e744618.png}}
== Sources of packages, bundles and libs ==
All p2 update sites are listed here: https://wiki.eclipse.org/Eclipse_Project_Update_Sites
|Site|Feature|Bundles|
|
http://download.eclipse.org/eclipse/updates/4.5
The swt packages are located inside the Eclipse RCP Feature.
| Eclipse RCP |
* org.eclipse.swt
* org.eclipse.jface
|
|E4 Downloads - http://download.eclipse.org/e4/downloads/drops/S-0.17-201501051100/repository/| |
* E4 CSS Spy
* E4 Event Spy
* Eclipse E4 Tools
|
|Nattable 1.3.0 - http://download.eclipse.org/nattable/releases/1.3.0/repository/| |
* NatTable Core
|
|
http://download.eclipse.org/tools/orbit/downloads/drops/R20150519210750/repository/ \\
The 3rd party libs a located inside the ORBIT Project's update site. \\
[[http://download.eclipse.org/tools/orbit/downloads/drops/R20150519210750/|Here you can search the 3rd Party libs available through ORbit p2 site]]
| |
* org.apache.commons.logging
|
|
http://download.eclipse.org/eclipse/updates/4.5
| EMF Common **(remove Group by Category)** |
* org.eclipse.e4.emf.xpath
|
|
http://download.eclipse.org/eclipse/updates/4.5
| EMF - Eclipse Modeling Framework Core Runtime **(remove Group by Category)**|
* org.eclipse.emf.ecore
|
|
http://download.eclipse.org/eclipse/updates/4.5
| Eclipse-Platform x.y |
* org.eclipse.ui.forms
|
== Portability ==
To keep the libs locally in a project and to have it portable between different workstations
(e.g. by keeping projects in dropbox)
The **Eclipse Projects** are usually kept **on dropbox**, but the **workspace** is located on the local machine, because it uses **absolute paths**.
So the problem is, set the path to the libs workspace independent.
This can be achieved by using eclipse variables.
But there is no special variable which always points to the targetPlatform location. (**target_home** var points to the first entry in target_platform)
The solution is to import the **target_platform project** into the workspace and use the variable,
which contains an absolute path to the target_platform location.
From there you can locate the subdirectories with libs.
...
{{http://i520.photobucket.com/albums/w327/schajtan/2014-08-19_10-34-33_zpsa9e8ae06.png}}
{{http://i520.photobucket.com/albums/w327/schajtan/2014-08-19_10-34-03_zps3d9f3a6a.png}}
The Project **de.vogella.e4.rcp.target** is imported, and so it may be used to locate libs, which are located in subdirectories
== Example Setup ==
Here is a setp of a target platform, which contains all the necessary plugins / features to run a product.
{{http://i520.photobucket.com/albums/w327/schajtan/2015-08-11_09-44-40_zpsab9iyc0x.png}}
==== Tools ====
^Tool ^Where ^ Screenshot ^
| **Eclipse e4 Tools** | install the E4 Tools> Eclipse e4 Tools \\ http://download.vogella.com/kepler/e4tools \\
http://download.vogella.com/juno/e4tools \\ http://download.eclipse.org/e4/downloads/ \\ http://download.vogella.com/luna/e4tools | {{http://snag.gy/LqTaK.jpg?500}} |
|**CssSpy** - Can inspect the application structure, display the css rules. \\ You should assign a hotkey to "open CSS Spy" action, e.g. **ALT+SHIFT+F5** \\ \\
- Add the e4 tooling repository to the target. Don't check the "resolve dependent software" checkbox. (Current e4 tooling repo is listed here: https://wiki.eclipse.org/E4/Install)
- Add Plugin org.eclipse.e4.tools.css.spy to your application dependencies.
- Add command org.eclipse.e4.css.OpenSpy to the keybindings to use it in the own app. \\ E.g. **M3+Shift+F5** (M3 is Alt)
| [[http://download.eclipse.org/e4/downloads/|Tooling]] | {{http://i.imgur.com/TJXtH.jpg?500}}|
|**Plug-In Inspector** - Can inspect active screen element, to show which plugin has contributed the current view.. \\ Hotkey: **ALT+SHIFT+F1** | OnBoard in Eclipse 4 |{{http://i.imgur.com/1DEjd.png?100}}|
| **Menu-Inspector** can inspect which menu was contributed by which plugin \\ Hotkey: **ALT+SHIFT+F2** and menu click \\ \\ Useful to find plugins, which contribute functionality (e.g. about dialog). | Onboard in Eclipse e4 | {{http://i.imgur.com/fioXc.png?200}}|
|**Live-Editor** - Can CHANGE active application's model at runtime \\ Hotkey: **ALT+SHIFT+F9**. \\ \\
- Add Plugins:
- org.eclipse.e4.tools.emf.liveeditor,
- org.eclipse.e4.tools.emf.ui,
- org.eclipse.e4.tools.emf.ui.script.js +
- transitive dependencies to your application dependencies.
- Add command e4.tooling.livemodel to the keybindings, to use it in the own app.
Add Plugin //// to the application to use it in the own app. | OnBoard in Eclipse 4 | {{http://i.imgur.com/vnuWa.png?400}} {{http://i520.photobucket.com/albums/w327/schajtan/2013-01-27_16-22-19.png?400}}|
|**Context-Spy** - Is able to inspect the Eclipse Context \\ Hotkey: **ALT+SHIFT+F10**. \\ \\
- Add Plugins:
- org.eclipse.e4.tools.context.spy,
- org.eclipse.e4.tools.spy
Add Plugin //// to the application to use it in the own app. | [[http://download.vogella.com/luna/e4tools|http://download.vogella.com/luna/e4tools]] \\ or it may be downloaded under [[http://marketplace.eclipse.org/content/eclipse-4-tools-context-spy|Marketplace]] | {{http://i520.photobucket.com/albums/w327/schajtan/2014-06-22_16-18-42_zpsb6b6015e.png?400}} |
==== Glossar ====
* **Application model** - Since Version 4 of the the application layout/structure was separated from the RCP content. \\ The application model defines __only the structure__ of the application, like Layout, size, position - not hte content.(File //Application.e4xmi// ) \\ The application content is defined in the java classes.
* **Context** is the space, where the OSGI Injections data comes from. Objects can have theis own Context, which is connected to the parent-context. (hierarchically) First the own context is searched, than the parent-context. This allows to avoid collusions.
* **Context Variables** (String/Value pairs in OSGI Injection context) and common **Key/Value pairs** (Class-Object/Value pairs in OSGI Injection context) \\ are a Static settings collection with an observer in it. If those Values are injected into an Object - they can monitor the value, independantly from the value source, because Eclipse can trigger change envents, when the context values change.
* **Annotations** - there are lifecycle annotations and Behavior Annotations in Eclipse. You can annotate a class or method to tell Eclipse, what automagically to do with the class or when to call a method.
* **Command-Handlers** - class with an //@Execute// annotated method. This method is called, to handle a command. To active/decativated flag - create a boolean method with a //@CanExecute// annotation. No never use DI-Fields inside handlers! Never use @Inject inside
handlers this is doomed to fail miserably because the handler is created
in a completely different context then it is executed!
==== useful Paths and Data ====
^Path ^ Code^ Example^
|Workspace Location| Platform.getInstanceLocation().getURL().getPath()|fare\workspace\|
|Bundle path|
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Path;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTError;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.widgets.Composite;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
Bundle bundle = FrameworkUtil.getBundle(this.getClass());
String pathIndexString = "/html/index.html";
Path pathToIndex = new Path(pathIndexString);
//bundleentry://22.fwk9862796/html/index.html
URL indexUrl = bundle.getEntry(pathIndexString);
System.out.println("URL "+indexUrl);
URL url = FileLocator.find(bundle, pathToIndex, Collections.EMPTY_MAP);
URL fileUrl = null;
try {
//file:/D:/1PROJEKTE/EclipseRCP4Mp3Resizer/de.mine.application/html/index.html
fileUrl = FileLocator.toFileURL(url);
} catch (IOException e1) {
e1.printStackTrace();
}
System.out.println("fileURL "+fileUrl);
| file:/D:/1PROJEKTE/EclipseRCP4Mp3Resizer/de.mine.application/html/index.html |
|System Data|System.getProperty("user.dir") |
java.version Java Runtime Environment version
java.vendor Java Runtime Environment vendor
java.vendor.url Java vendor URL
java.home Java installation directory
java.vm.specification.version Java Virtual Machine specification version
java.vm.specification.vendor Java Virtual Machine specification vendor
java.vm.specification.name Java Virtual Machine specification name
java.vm.version Java Virtual Machine implementation version
java.vm.vendor Java Virtual Machine implementation vendor
java.vm.name Java Virtual Machine implementation name
java.specification.version Java Runtime Environment specification version
java.specification.vendor Java Runtime Environment specification vendor
java.specification.name Java Runtime Environment specification name
java.class.version Java class format version number
java.class.path Java class path
java.library.path List of paths to search when loading libraries
java.io.tmpdir Default temp file path
java.compiler Name of JIT compiler to use
java.ext.dirs Path of extension directory or directories
os.name Operating system name
os.arch Operating system architecture
os.version Operating system version
file.separator File separator ("/" on UNIX)
path.separator Path separator (":" on UNIX)
line.separator Line separator ("\n" on UNIX)
user.name User's account name
user.home User's home directory
user.dir User's current working directory |
==== Eclipse RCP Product ====
The product allows to customize your application a little:
* set an own icon for the launcher (*.exe file)
* set the name for the launcher
== Launcher Icons and tycho ==
Here is how the icon for the launcher is set.
When using **tycho** - the maven plugin, which is able to build rcp in headless mode - the **paths to the images** are set **relative to the workspace**. Otherwise tycho will not fid them. \\
You should use *.bmp files with alpha channel. The Tool [[http://www.qualibyte.com/pixelformer/download.html|Pixeformer]] is able to create such bmp files. \\
You should not use *.ico since there are bugs in tycho and not every *.ico file will work. [[http://andrius.velykis.lt/2012/10/creating-icons-for-eclipse-rcp-launcher/|Details here]]\\
{{http://i520.photobucket.com/albums/w327/schajtan/2015-06-24_09-32-48_zpsldi6jymd.png}}
== Icons for windows ==
Since E4 default Window-Icons are set via the e4Model.
{{http://i520.photobucket.com/albums/w327/schajtan/2015-06-24_09-50-07_zpsuue1ahf0.png}}
There is a possibility to set default Window-Icons for Windows without icons in code
private void setDefaults() {
Image icon16 = UtilsCommonResource.getCoreIcon(ImageSize.Size16x16);
Image icon24 = UtilsCommonResource.getCoreIcon(ImageSize.Size24x24);
Image icon32 = UtilsCommonResource.getCoreIcon(ImageSize.Size32x32);
Image icon48 = UtilsCommonResource.getCoreIcon(ImageSize.Size48x48);
Image icon256 = UtilsCommonResource.getCoreIcon(ImageSize.Size256x256);
Window.setDefaultImages(new Image[] {icon16, icon24, icon32, icon48, icon256 });
}
== Customize the product to store the data inside the AppData folder ==
The product may store the data inside the user's AppData Folder.
To do that some properties, which define the storage location for the setting must be set inside the product.
osgi.configuration.area - $APPDATA$/IVU/IVU.fare/.metadata/.plugins
osgi.instance.area - $APPDATA$/IVU/IVU.fare
As the result the above properties ae redirected into the user's directory.
You can write the log files to that directory by including the //${osgi.instance.area}/log/application.log// into the log path inside the properties.
and evaluating the path inside the log4j appender
/**
* Unverändert der RollingFileAppender,
* aber erlaubt die Angabe der Logdatei in File-URI-Notation.
* Dies wird notwendig, wenn die Logdatei über eine System-Property
* definiert wird, die von Eclipse/OSGi bereitgestellt wird.
*
* Beispiel: log4j.appender.XXX.FileUri=${osgi.instance.area}/log/application.log
*
* @author xsb
*/
public class ExtendedRollingFileAppender extends RollingFileAppender {
public void setFileUri(String fileUri) {
URI uri = URI.create(fileUri);
if (!"file".equalsIgnoreCase(uri.getScheme())) {
throw new IllegalArgumentException("given uri is not a valid file uri: " + fileUri);
}
super.setFile(uri.getRawSchemeSpecificPart());
}
}
here you can learn more about theses properties: \\
http://help.eclipse.org/luna/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fmisc%2Fruntime-options.html
{{http://i520.photobucket.com/albums/w327/schajtan/2015-08-04_12-48-29_zpspb4lnn0q.png}}
==== Customization Runtimeparameters ====
There are multiple ways to configure an RCP Product.
Here is a full list of parameters, which can be passed to Eclipse RCP Products:
http://help.eclipse.org/juno/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fmisc%2Fruntime-options.html
===.ini===
Should only contain launch arguments.
-startup
plugins/org.eclipse.equinox.launcher_1.3.0.v20120522-1813.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.1.200.v20120522-1813
-vm
C:\Programm Files\Java\JDK\1.5\bin\javaw.exe
-vmargs
-Xms40m
-Xmx512m
-Duser.timezone=Europe/Berlin
-Djna.library.path="C:/farelibs/32bit;C:/farelibs/64bit"
==vmarguments==
When adding vmarguments to the file
* you have to prepend **-vmargs** to all parameters
* you have to be prepended a **D** to each parameter. Like: **D**property=value
-Duser.language=es
-Dequinox.scr.waitTimeOnBlock=1
-Duser.timezone="Europe/Berlin"
=== /configuration/config.ini ===
Can hold any parameter, but should hold only VM arguments. For organisation' sake.
The form is **parameter=value**
#This configuration file was written by: org.eclipse.equinox.internal.frameworkadmin.equinox.EquinoxFwConfigFileParser
#Mon Oct 14 17:21:58 CEST 2013
eclipse.p2.profile=DefaultProfile
osgi.framework=file\:plugins/org.eclipse.osgi_3.8.1.v20120830-144521.jar
equinox.use.ds=true
osgi.bundles=reference\:file\:org.eclipse.equinox.simpleconfigurator_1.0.301.v20120828-033635.jar@1\:start
org.eclipse.equinox.simpleconfigurator.configUrl=file\:org.eclipse.equinox.simpleconfigurator/bundles.info
eclipse.product=de.ivu.fare.rcp.core.bundle.product
osgi.splashPath=platform\:/base/plugins/de.ivu.fare.rcp.core.bundle
osgi.framework.extensions=reference\:file\:org.eclipse.osgi.nl_de_4.2.0.v20120721043402.jar
osgi.bundles.defaultStartLevel=4
eclipse.p2.data.area=@config.dir/../p2
eclipse.application=org.eclipse.e4.ui.workbench.swt.E4Application
fare.serverhost=localhost
fare.serverport=4447
osgi.nl=es_CO
fare.user=sov
fare.passwd=sovsovsov
Equinox (which is Elcipse implementation of OSGI API) options may be added to config.ini.
All Equinox runtime optins are listed here: {{http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fmisc%2Fruntime-options.html| here}}
Here are some of them:
// how many miliseconds should equinox wait until the service is ready. Default is 10.000. This pparameter may force equinox to launch much faster!
equinox.scr.waitTimeOnBlock=1
// logs execution time in ms
equinox.ds.perf=true
// prints the trace-logs on the console
equinox.ds.print=true
// debugmode on
equinox.ds.debug=true
// which start level should the bundles have on default? This should be larger than the launch-level of your product, otherwise the fragments will wait for core, which is not started yet.
// check the product > configuration > Start level
osgi.bundles.defaultStartLevel=4
===Runtime Parameters===
Can pass runtime arguments or vmarguments. The vmarguments must come as last parameter, because all aruments after are treated as Java VM Arguments. \\
The Java VM Arguments must be separated by a **=** sign.
The vmargument proper.ty=value is passed as as runtimeparameter as "**-vmargs -D**proper.ty=value"
fare.exe -my -runtimeargumentshere -vmargs -Duser.language=es
fare.exe -fare.mandant DEF -fare.passwd sovsovsov -fare.user sov -vmargs -Duser.language=es
fare.exe -osgi.nl es_CO
ACHTUNG:
- Die Vm-Arguments **fangen mit D an** und kommen **als letztes nach -vmargs** nach allen anderen argumenten: **-vmargs** -**D**user.language**=**es_CO
- Bei OSGI Argumenten wird das **Präfix "osgi." weggelassen**. \\ Ausserdem ist wird das **Gleichheitszeichen weggelsassen**. Syntax -parameter value. \\ Bei Systemproperty osgi.nl : **-nl es_CO**
===Run Configuration===
Use run configuration during the development to set VM Args:
{{http://i520.photobucket.com/albums/w327/schajtan/2014-11-27_12-01-54_zps10f5dd43.png?800}}
==== Application Model ====
The [[eclipse:eclipse_rcp4#glossar|Applicationmodel]] looks as following : \\
{{http://i.imgur.com/qCcLF.png?400}}
It's parts are describedd here:
=== PartDescriptors ===
Can define Part-Templates.
The templates will be used to create predefined MParts:
@Inject
MPartStack mainStack;
@Inject
IEclipseContext stackEclipseContext;
...
IEclipseContext newContext = EclipseContextFactory.create();
newContext.setParent(stackEclipseContext);
MPart part = partService.createPart("partdescriptor.template.id");
part.setContext(newContext);
mainStack.getChildren().add(part);
==== API ====
The e4 Static classes, like services are listed here: [[http://wiki.eclipse.org/Eclipse4/RCP/EAS/List_of_All_Provided_Services|http://wiki.eclipse.org/Eclipse4/RCP/EAS/List_of_All_Provided_Services]]
== Basic Eclipse entrypoints ==
^Command ^What^
| [[http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fcore%2Fruntime%2FPlatform.html|org.eclipse.core.runtime.Platform]] | is a central class, which represents the platform itself. Has static methods only. Use it to: \\ manage installed plugin-registry, \\ show/hide splash screen, \\ check if in develpment mode, \\ manage authorization|
| [[http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fui%2FPlatformUI.html|org.eclipse.ui.PlatformUI]] | The central class for accessing to the Eclipse workbench.|
== UI related Classes, Interfaces, Factories and Services ==
|**MApplication**|Describes the application object. Can be used for example to add new windows to your application|
|interface **MWindow**| Represents a Window in your application. Can be used for example to add new windows to your application \\ This interface is used by **MApplication** to work with Windows inside of the EMF structure.
* getMainMenu
* getX
* getY
* getWidth
* getHeight
* getWindows
* getSharedElements
**ACHTUNG:** to hide an MWindow you can do MWindow.setIsToBeRendered(false). The same is done, when a MWindow is closed, but then ALL CHildren (Parts etc.) are set to //isToBeRendered=false//. To enable MWindows content set MWindows as to be rendered:
MWindow mWindow = findElements.get(0);
mWindow.setToBeRendered(true);
mWindow.setVisible(true);
/*
* ACHTUNG HACK: As soon as an MWindow is closed - it's children are set to
* "isToBeRendered=false".
* So Set the Children back to "isToBeRendered=true" again
*/
for (MWindowElement child : mWindow.getChildren()) {
child.setToBeRendered(true);
child.setVisible(true);
}
{{http://i520.photobucket.com/albums/w327/schajtan/2014-07-09_15-57-02_zps0a5966cb.png?600}}
To connect the windows hierarchically - add the window to a parent window. Then the child window will always be in front its parent. They will come to front together
|
|interface **MTrimmedWindow**| Represents a Window in your application. The underlying SWT shell has been created with the SWT.SHELL_TRIM attribute which means, it has a tile, a minimize, maximize and resize button.|
|interface **MPerspective**| Object for the perspective model element..|
|interface **MPart** extends **MUIElements**| Are used by the MBasicFactory to create Parts. |
|interface **MDirtyable**| Are used by the MBasicFactory to create Parts. |
|interface **MPartDescriptor**| MPartDescriptor is a template for new Parts. You define in your application model a PartDescriptor. A new Part based on this PartDescriptor can be created via the EPartService and shown its showPart() method. Are used by the MBasicFactory to create Parts.
* getMenus
* getToolbar
* isCloseable
* getDescription
|
|**MBasicFactory**|Factory, which can create Parts to insert them into the EMF Model. Available Methods:
import org.eclipse.e4.ui.model.application.ui.basic.MBasicFactory;
MBasicFactory.INSTANCE.createTrimmedWindow();
MBasicFactory.INSTANCE.createTrimBar(); //the toolbar with icons at the top
MBasicFactory.INSTANCE.createPart();
MBasicFactory.INSTANCE.createWindow();
MBasicFactory.INSTANCE.createPartSashContainer(); //a sash, which can contain parts
MBasicFactory.INSTANCE.createPartStack(); //a stack, which can contain parts
...
|
|**EModelService**| A very important class, which allows manipulating the EMF Model. \\ has a **find()** method to get Parts by
* tags
* id
* Class
Can **move()** or **clone()** Parts. \\
Can find find the nearest parent context eModelService.getContainingContext(mainStack);|
|**EPartService**|
* Can switch perspectives.
* Can activate Parts partService.showPart(newMPart, PartState.ACTIVATE);
* Can hide Parts
* Can retrieve all dirty Parts
|
|**ECommandService**| Can be injected. Finds Commands. |
|**CommandManager**| Can be injected. Finds Commands AND is able to add execution listeners to them. |
|**EHandlerService**| Can be injected. Finds Handlers.
@Inject
private IEclipseContext eclipseContext;
@Inject
private ECommandService commandService;
@Inject
private EHandlerService handlerService;
treeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
IStructuredSelection selection = (IStructuredSelection) event.getSelection();
for (Iterator> iterator = selection.iterator(); iterator.hasNext();) {
Module module = (Module) iterator.next();
ParameterizedCommand command = commandService.createCommand("de.ivu.fare.commands.activateModule",
null);
handlerService.executeHandler(command, eclipseContext);
}
}
});
}
|
|**IEventLoopAdvisor**| Displays a popup when an Exceptions occurs, which is not handled. Put that into the context to let this object handle unhandled exceptions. Default one shows exceptios in dialogs. context.set(IEventLoopAdvisor.class, new IEventLoopAdvisor() {...} |
|**MenuManagerRenderer**|
Merges MenuItems from MenuContributions with the given menu.
// somehow find a menu in Application.e4xmi e.g. by using EModelService.class
org.eclipse.e4.ui.model.application.ui.menu.MMenu mmenu;
MenuManagerRenderer mmr = new MenuManagerRenderer();
mmr.init(eclipseContext);
ContextInjectionFactory.inject(mmr, eclipseContext);
// this checks the e4 model for contributions with same id and merges them to the mmenu
mmr.processContributions(mmenu, ID_CONTEXTMENU, false, false);
|
== Eclipse e4 Context related API ==
^Command ^What^
|context.modify, \\ context.declareModifiable| context.modify(key, value) creates an unmodifyable pair. It can't be changed from another (sub)contexts. declareModifiable can declare a pair, which is changeable from other contexts. context.set/context.get can access the vars, created by modify too, changes are allowed, only if var is modifyable.|
|context.runAndTrack| registers a runnable, which is called on every context change.|
|context.getActive(MyObjectClass)| searches the given class in the whole active context chain. This is a possibility to search for objects in the hierarchy, below the own context. |
|**IContextFunction**| Context can contain Functions, which will operate on the context values.
//Creation
slideContextObjects.get(item).set("MyFunction", new IContextFunction() {
@Override
public Object compute(IEclipseContext context) {
if(context.get("Token") == "one"){
return 1;
}
return 2;
}
});
//usage
slideContextObjects.get("MyFunction"); //returns 1 or 2 depending on "Token" inside of the context
|
|**ContextInjectionFactory**| Can inject inject Data from the Context into objects. Useful to instantiate @Injection annotated Clases manually. It copies all the Data from an IEclipseContext into an Object - it doesn't set the given Context
ManipulateModelhandler man = new ManipulateModelhandler();
//IEclipseContext content was injected into man
//the man should allready have an own iEclipseContext to copy the data in
ContextInjectionFactory.inject(man,iEclipseContext);
//instantiates the TestPart and injects it into the context
ContextInjectionFactory.make(TestPart.class, context);
man.execute();|
|**EclipseContextFactory**| A factory for creating context instances
MPart newMPart = MBasicFactory.INSTANCE.createPart();
MPartStack mainStack = (MPartStack) eModelService.find(STACKID, mApplication);
mainStack.getChildren().add(newMPart);
//nearest context of the stack
IEclipseContext eclipseContext = eModelService.getContainingContext(mainStack);
// eclipseContext should be the Context of mainStack, which is the parent of newPart in model
IEclipseContext newContext = EclipseContextFactory.create();
newContext.setParent(eclipseContext);
newMPart.setContext(newContext);
|
|**EclipseContext.activate()**, **EclipseContext.getActive()**, @Active| An instance of an EclipseContext may be activated. Then the values, available in the active contexts will be accessable by getActive(). Additional you can monitor the values inside the active context instances by using the @Active Annotation.
main(){
IEclipseContext parentContext = EclipseContextFactory.create();
IEclipseContext context = EclipseContextFactory.create();
context.setParent(parentContext);
context.set("OBJECTNAME", new MyObject("xy"));
context.activate(); //activate the context. Triggers the monitorMyObject() because the active MyObject value changed
parentContext.getActive("OBJECTNAME"); //MyObject("xy")
}
@Optional
@Inject
void monitorMyObject(@Active @Named(OBJECTNAME) MyObject newMyObject){
...
}
|
|Naming the Context for Debugging|
// setting the EclipseContext name which will be displayed by debugger (toString Method)
eclipseContextForEditor.set(EclipseContext.DEBUG_STRING, "Context with editor data");
|
== Useful Classes and Methods==
^Command ^What^
|[[http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fcore%2Fruntime%2FSafeRunner.html|org.eclipse.core.runtime.SafeRunner]] |can run a runner safely, catching exceptions.|
|[[http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fcore%2Fruntime%2FIAdapterFactory.html|IAdapterFactory]] | There is a nice article about this [[http://www.eclipsezone.com/articles/what-is-iadaptable/|here]].\\ Summary: if you need the ability to dynamically cast an Object(**Adaptable**) into another - create a **IAdapterFactory** which will return an implementation of **IAdapter**. Implement the cast inside the IAdapter which is inside the IAdapterFactory. \\ (e.g. casting of Lists into an Nodes by creating a Node for every Array entry) \\ and register the IAdapterFactory to the Platform. After that you will be able to cast dynamically from Array to Nodes!!!! Endeed the returned Type will be **IAdaptable**, so you will have to do an explicite cast.\\
public class NodeListFactory implements IAdapterFactory {
/** The actual conversion to a Node */
public Object getAdapter(Object list, Class clazz) {
if (clazz == Node.class && list instanceof List) {
Element root = new Element("List");
Iterator it = list.iterator();
while(it.hasNext()) {
Element item = new Element("Entry");
item.appendChild(it.next().toString());
root.appendChild(item);
}
return root;
} else {
return null;
}
}
}
/** Teach the platform to convertLists into Nodes. The Adaptor will return IAdaptable instances which will have to be casted manually.*/
Platform.getAdapterManager().registerAdapters( new NodeListFactory(), List.class);
/** Use the mechanism to cast List to Nodes*/
Node getNodeFrom(IAdaptable list) {
Object adaptable = list.getAdapter(Node.class);
if (adaptable != null) {
Node node = (Node)adaptable;
return node;
}
return null;
}
|
|**IEventBroker**|[[http://wiki.eclipse.org/E4/Event_Processing|Alterlative to the observer pattern]].
**ACHTUNG:**
The IEventBrokerTopics may not contain any cahracters:
|. | **NOT ALLOWED**|
|_| ALLOWED|
|Big characters | ALLOWED|
There is a possibility to use hierarchies in Topics:
public static final String TOPIC_TODO_ALLTOPICS =
"TOPIC_TODO/*";
public static final String TOPIC_TODO_NEW =
"TOPIC_TODO/NEW";
public static final String TOPIC_TODO_DELETE =
"TOPIC_TODO/DELETED";
public static final String TOPIC_TODO_UPDATE =
"TOPIC_TODO/UPDATED";
}
More about the usage [[http://tomsondev.bestsolution.at/2011/02/07/enhanced-rcp-how-views-can-communicate-the-e4-way/|was written by Tom Shindl]]. \\
Eclipse 4 used the EventAdmin to communicate between Bundles. [[http://tomsondev.bestsolution.at/2011/01/03/enhanced-rcp-how-views-can-communicate/|The howto can be found here.]]
**Observer Problems**
The current event processing in Eclipse is centered on the listener mechanism (also commonly described as the "Observer" pattern). This is a good, relatively simple, and easily customizable approach. However, two drawbacks became apparent as its usage grew: forced lifecycle and multiple implementations.
I use "forced lifecycle" term to describe a situation in which lifecycle of the listener is tied to the lifecycle of the event provider. The listener can't subscribe to the event before event provider is instantiated. On the other end, the listener has to be decommissioned when the event provider is disposed. This seemingly small detail of tying the lifecycles translates into a lot of extra code and, depending on the application, might become a major bug source.
The "multiple implementations" problem is another aspect that grows with the software size. Even as parts of the pattern are provided by the Platform (ListenerList, SafeRunnable, Job), there is still code that needs to be added by every event generator to tie them together. From a memory consumption angle, every event provider has to instantiate and maintain its own listener list, even if, as often happens, nobody is listening or the particular event does not happen. A quick search shows over 200 places in the SDK code alone that create ListenerList's. Chances are, there are as many listener mechanisms that have their own implementations or use ListenerList indirectly.
**IEventBroker vs. Observer**
The main difference to the observer is that an intermediary is introduced between the sender and the receiver: events are published to the Event Broker which dispatches them to the listeners subscribed to this event type.
In this approach listeners can subscribe and unsubscribe as they please, regardless if the particular event source exists. It means that there is one implementation that everybody can use without the need to write additional code. It also means that no extra processing will be done for events that do not happen. And we'll have no need for multitude of listener interfaces specific to each event.
So, is this the best thing since sliced bread? Well, it does have some downsides. The event broker becomes a rather sensitive point of the system. It has to perform well both in CPU timing and memory allocations. And the broker itself better be robust.
//register listener
IEventBroker eventBroker = (IEventBroker) eclipseContext.get(
IEventBroker.class.getName());
eventBroker.subscribe(IUIEvents.ElementContainer.Topic, null,
new EventHandler() {
public void handleEvent(Event event) {
if (event.getProperty(IUIEvents.EventTags.AttName)
.equals(IUIEvents.ElementContainer.ActiveChild)) {
Object newPart = event.getProperty(IUIEvents.EventTags.NewValue);
if (newPart instanceof MPart) {
// do something
}
}
}
}, /* headless */ false);
//sending Events
Map data = new HashMap();
map.put(IUIEvents.EventTags.AttName, IUIEvents.ElementContainer.ActiveChild);
map.put(IUIEvents.EventTags.Element, partStack);
map.put(IUIEvents.EventTags.OldValue, oldPart);
map.put(IUIEvents.EventTags.NewValue, newPart);
map.put(IUIEvents.EventTags.Type, IUIEvents.EventTypes.Set);
IEventBroker eventBroker = (IEventBroker) eclipseContext.get(
IEventBroker.class.getName());
eventBroker.send(IUIEvents.ElementContainer.Topic, data);
//To receive EventBroker Notifications in a specific method - use the shortcut
private static final String EVENT_TOPIC_ID = "MY_EVENTTOPIC_ID";
@Inject
@Optional
public void handleEvent(@UIEventTopic(EVENT_TOPIC_ID) final EventBrokerModuleData eventBrokerModuleData,
@Optional final EditorPage page, @Optional final IEclipseContext eclipseContext) {
//LOGIC GOES HERE
}
Some Fallpits:
//1. ACHTUNG: sending Platform Objects doesn't allways work! Better Send own objects!
eventBroker.send(LocalEventDispatcher.EVENTID_CREATE_DOMAINOBJECT, eventBroker);
//here this method is not triggered
@Inject
@Optional
public void handleEvent(@EventTopic(LocalEventDispatcher.EVENTID_CREATE_DOMAINOBJECT) EventBroker b) {
System.out.println("receive now EventBroker");
}
//2. ACHTUNG: sending "this" did not work. Better create Objects to send with "new"
eventBroker.send(LocalEventDispatcher.EVENTID_CREATE_DOMAINOBJECT, this);
//3. ACHTUNG: subscribing for Interfaces does not work. Just classes.
@Inject
@Optional
//public void handleEvent(@EventTopic(LocalEventDispatcher.EVENTID_CREATE_DOMAINOBJECT) IEclipseContext c) { System.out.println("Subscribe for Interface IEclipseContext FAILS"); }
public void handleEvent(@EventTopic(LocalEventDispatcher.EVENTID_CREATE_DOMAINOBJECT) EclipseContext c) { System.out.println("Subscribe for class EclipseContext WORKS"); }
//4. receiving Object results in an unexpected behaviour! Sometimes it reacts on everything, sometims on nothing.
@Inject
@Optional
public void handleEvent(@EventTopic(LocalEventDispatcher.EVENTID_CREATE_DOMAINOBJECT) Object o) {
System.out.println("receive now Object");
}
eventBroker.send(LocalEventDispatcher.EVENTID_CREATE_DOMAINOBJECT, eventBroker);
eventBroker.send(LocalEventDispatcher.EVENTID_CREATE_DOMAINOBJECT, this);
eventBroker.send(LocalEventDispatcher.EVENTID_CREATE_DOMAINOBJECT, "String");
//5. sending and receiving String - works always. Test using Strings.
eventBroker.send(LocalEventDispatcher.EVENTID_CREATE_DOMAINOBJECT, "String");
@Inject
@Optional
public void handleEvent(@EventTopic(LocalEventDispatcher.EVENTID_CREATE_DOMAINOBJECT) String s) {
System.out.println("receive now String");
}
//6. sending and receiving Objects created by new - works
eventBroker.send(LocalEventDispatcher.EVENTID_CREATE_DOMAINOBJECT, new EventRepaintTable());
@Inject
@Optional
public void handleEvent(@EventTopic(LocalEventDispatcher.EVENTID_CREATE_DOMAINOBJECT) EventRepaintTable r) {
System.out.println("receive now EventRepaintTable");
}
The class which receives the **EventBroker** notifications is not coppled with the EventBroker.
It may be destroyed by the Garbadge Collector if it is not stored somewhere.
// Fallpit garbadge collector
class SomeClass{
SomeClass(){
/* this anonymous class is created and stored nowhere.
* It is intended to handle EVENTID_CREATE_DOMAINOBJECT events, but
* It will be destroyed by the garbadge collector and events wont be received
*/
new MyEventHandlerListener(){
public void handleEvent(@EventTopic(LocalEventDispatcher.EVENTID_CREATE_DOMAINOBJECT) EventRepaintTable r) {
System.out.println("receive now EventRepaintTable");
}
}
}
}
|
| **UISynchronize** | This Object is able to execute stuff on the UI thread.
@Inject
UISynchronize uisynchronize
..
uiSynchronizer.asyncExec(new Runnable() {
@Override
public void run() {
//do something on UI Thread
}
});
|
== OSGI Budnles Related API ==
|**IContributionFactory**| A factory , which can create an Object by ContributorURI. Can be used to create an Object to do something with it, before it will be connected to a Part.
@Inject
IEclipseContext iEclipseContext
@Inject
MApplication mApplication;
...
Object partimplementation = IContributionFactory.create("bundleclass://com.example.pluginname/com.example.pluginname.gui.parts.TestAccordionPart", iEclipseContext);
MPart part = (MPart) eModelService.find("my.part.id", mApplication);
part.setObject(partimplementation);
//its the same like doing
MPart part = (MPart) eModelService.find("my.part.id", mApplication);
part.setContributionURI("bundleclass://com.example.pluginname/com.example.pluginname.gui.parts.TestAccordionPart");
|
|**FrameworkUtil**| This can retrieve a Bundle by class.
FrameworkUtil.getBundle(MyHandler.class);
|
Class> clazz = this.getClass();
// getting the bundle
Bundle b1 = Platform.getBundle("de.ivu.fare.rcp.tariff.gui.swt");
Bundle b = FrameworkUtil.getBundle(this.getClass());
// getting the extension point by name. Now looking for the module contributed by the
// current Bundle? How? Can't get the right Bundle!
IExtensionPoint extPoint = Platform.getExtensionRegistry().getExtensionPoint("de.ivu.fare.rcp.guiprovider.swt");
IExtensionPoint extPointMod = Platform.getExtensionRegistry().getExtensionPoint(
"de.ivu.fare.rcp.moduleProvider");
//getting the extensionpoint by bundle?
==== Injection Cycle ====
|< 100% 50% >|
^Step ^Fallpits ^
| 1. run constructor code | The non static, //@Injected// annotated fields are not available at this step.
\\ You cannot use of them inside the constructor.
No parametrized constructors are allowed, where you need a **special** object as a parameter. (e.g. concrete parrent composite)\\
Workaround - is to create a special context, where you put in the concrete object and where you inject these objects into the constructor.
c2 = context.createChild();
c2.set( Composite.class, myParentComposite );
ContextInjectionFactory.make(TableToolbar.class, c2);
|
| 2. do field injection | |
| 3. do method injection | |
| 4. run @PostConstruct | |
==== Using Annotations to Inject Objects from Context ====
Add own Objects to the context, then inject it from there into own Objects
**FALLPUTS:**
- method, which is invokes should be PUBLIC
- when using own annotation - it should have @Retention(value=RetentionPolicy.RUNTIME)
//ACHTUNG: Retention is important, when using methods at runtime
@Retention(value=RetentionPolicy.RUNTIME)
@Inherited
@Target(value={java.lang.annotation.ElementType.METHOD})
public @interface MyPostGuiCreate {
}
public class InjectableObject {
void talk(){
System.out.println("xoxo im the InjectableObject");
}
}
public class InjectContextHere {
//ACHTUNG: method should be public to be reached by reflections
@MyPostGuiCreate
public void myPostGuiCreate(@Named("MyInjectableOject") InjectableObject injectableObject){
injectableObject.talk();
}
}
@PostConstruct
void postConstruct(){
// create a context
IEclipseContext context = EclipseContextFactory.create();
// put some stuff into it
InjectableObject injectableObject = new InjectableObject();
// context.set(injectableObject.getClass().getName(), injectableObject); // works: @Inject InjectableObject injectableObject
// context.set(InjectableObject.class, injectableObject); // works: @Inject InjectableObject injectableObject
// context.set(InjectableObject.class.getName(), injectableObject); // works: @Inject InjectableObject injectableObject
// context.set("MyInjectableOject", injectableObject); //works: @Inject @Named("MyInjectableOject") InjectableObject injectableObject OR myPostGuiCreate(@Named("MyInjectableOject") InjectableObject injectableObject){
// create the object, which we will inject stuff into
InjectContextHere injectContextInThisObject = new InjectContextHere();
//now use the annotation
ContextInjectionFactory.invoke(injectContextInThisObject, MyPostGuiCreate.class, context);
}
==== IPartListener and EPartService ====
The //EPartService// may be injected to listen for //MPart// lifecycle. \\
Following hooks are available and are triggered in the following order.
^ ^ ^
| partVisible | Is triggered when a Part: is created / closed, loses / gains focus |
| partHidden | When part loses focus, NOT when the part is closed |
| partDeactivated | When part loses its focus, when it is closed |
| partBroughtToTop | |
| partActivated | Is triggered when a Part: is created, |
== Concrete cycles ==
== new Part opening cycle ==
|partVisible|
|partBroughtToTop|
|UILifeCycle.BRINGTOTOP triggered after focus. Wrong MPart is injected!|
|partActivated|
|@Focus (not available in IPartListener only as annotations in Part implementations) |
|UILifeCycle.ACTIVATE triggered after focus. Wrong MPart is injected!|
== explicite selection (by click) of Part which was inactive ==
|partVisible|
|partBroughtToTop|
|@Focus (not available in IPartListener only as annotations in Part implementations) |
|UILifeCycle.BRINGTOTOP triggered after focus. Wrong MPart is injected!|
|partActivated|
|UILifeCycle.ACTIVATE triggered after focus. Wrong MPart is injected!|
== implicite unselection of a Part, through selection of another ==
|partHidden|
|partDeactivated|
== Part closing cycle ==
|partDeactivated|
Additionally an artificaial event, when the part is detached may be implemented by using the following:
* every time the part is dragged to a new Window the hook **partVisible** is triggered.
* when a //MPart//'s //MWindow//'s Parent is NULL - it is detached. \\ When it is in the main Window the Parent is = //MApplication//
// Part listener
partService.addPartListener(new IPartListener() {
@Override
public void partVisible(MPart part) {
if(isDetached(part)){
// part is detached now!
}
}
});
}
private boolean isDetached(MPart part){
boolean isDeatached = false;
MWindow mWindow = part.getContext().get(MWindow.class);
/* Every Part has an MWindow somewhere in the e4 Model hierarchy.
* In DETACHED Parts the Parent of the MWindow is NULL.
* In NON detached Parts the Parent is not null and has the type "ApplicationImpl" which implements MApplication.class */
if(mWindow.getParent()==null || !MApplication.class.isAssignableFrom(mWindow.getParent().getClass())){
isDeatached = true;
}
return isDeatached;
}
==== Annotations for Injections ====
Dependency Injections and annotations are describes [[http://wiki.eclipse.org/Eclipse4/RCP/Dependency_Injection|on wiki.eclipse.org]]. \\
^OSGI Annotations^ Meaning^
|@Inject |Can be applied to constructor, method, field. The Platform will execute those, @Inject annotated constructors/methods and fill the fields. \\
- The @Inject annotated **constructor** will be called, when the object of current type is needed by the pltform.
- Then the @Inject annotated **fields** which are are filled with data from the Context.
- Then the @Inject annotated **methods** are exectued, which suppose to do initialization. (called initializer methods)
\\ IMPORTANT: The methods, which have an //@Inject// in their parameters - are called on every change of the injected parameter. The Selection can be implemented by using injections.
@Inject
private void getActivePart(@Named(IServiceConstants.ACTIVE_PART) MPart part) {
activePart = part;
}
|
|@Optional \\ @Inject | @Optional is used together with @Inject. This Annotation tells the system, that this field is not required for the current class. However an @Option annotated Field will be filled by the system later, as soon, as the Object becomes available in the context. This feature can be used if an Object is not available on creation, but will be available in the later part of teh lifecycle.
class X{
@Optional
@Inject
EHandler eHandler; //the creation of class will not fail, if the EHandler is not yet available. However if the Object will be created in the context later it will magically appear here - and myFunction will be able to use eHandler.
...
void myFunction(){
//use eHandler;
}
|
|@Named| Can be applied to **classes** and **methods**. Makes the system retrieve a concrete object from the context, chosen by a name-key. \\ If the object was put into the context, without a name-key, then the object's class is used as key automatically. \\ Eclipse puts some Objects into the context automatically, e.g.
* @Inject @Named (IServiceConstants.ACTIVE_SHELL) Shell shell; - active shell
* @Inject @Named (IServiceConstants.ACTIVE_PART) Shell shell; - active part
* @Inject @Named (IServiceConstants.ACTIVE_SELECTION) Shell shell; - active selection
* @Inject @Named (IServiceConstants.SELECTION) Shell shell; - (inactive?) selection
|
|@Creatable| Can be applied to **classes**. Makes system initialize the Object of this type automatically, if no object of this type is available in the context.|
|@Inject @Preference(nodePath="my.plugin.id", value="dateFormat")| Preferences are retrieved by annotations, as described by [[http://www.vogella.com/articles/Eclipse4Preferences/article.html|vogella ]] \\ \\ IMPORTANT: this annotation is defined in the Plugin requires a dependency to the plugin **org.eclipse.e4.core.di.extensions** |
|@Active|Accesses the active context. Can retrieve Active Parts, active Windows etc.
@Execute
public void execute(@Active MPart activePart) {
...
}
Further, when annotating a Value by @Active this value gets reinjected, every time when a content in the active context-chain changes!.
...
@Active
MyObject myObject;
void method(EclipseContext newContextWithMyObject){
...
this.context = newContextWithMyObject; //myObject is reinjected at this point
}
void method(EclipseContext childContextWithMyObject){
...
//even listening for child context values - works
childContextWithMyObject.setParent(this.context);
} |
ACHTUNG: There only can by ONE method per lifeCycle annotation!
^LifecyleAnnotation^ Meaning^
|1. @PostConstruct |Is called after the class is constructed and the field and method injection has been performed. Create the GUI here. \\ SUPPORTS INHERITANCE. Is called on multiple inheritance levels if present!|
|2. @PostContextCreate|Can be used in a special class which is registered inside of the Extension Point \\ //org.eclipse.core.runtime.product// inside of the property //lifeCycleURI//. See [[http://www.vogella.com/articles/Eclipse4RCP/article.html#lifecycle|http://www.vogella.com/articles/Eclipse4RCP/article.html#lifecycle]]. |
|3. @ProcessAdditions|Can be used in a special class which is registered inside of the Extension Point \\ //org.eclipse.core.runtime.product// inside of the property //lifeCycleURI//. See [[http://www.vogella.com/articles/Eclipse4RCP/article.html#lifecycle|http://www.vogella.com/articles/Eclipse4RCP/article.html#lifecycle]]. **Here the e4 Model is allready loaded. Use this hook to change the Model and model dependant Contexts**|
|4. @ProcessRemovals|Can be used in a special class which is registered inside of the Extension Point \\ //org.eclipse.core.runtime.product// inside of the property //lifeCycleURI//. See [[http://www.vogella.com/articles/Eclipse4RCP/article.html#lifecycle|http://www.vogella.com/articles/Eclipse4RCP/article.html#lifecycle]]. **This
* method will be called after the @ProcessAdditions calls are done**|
|5. UIEvents.UILifeCycle.APP_STARTUP_COMPLETE |Is an IEventBroker event. Triggers when the Application is up and running Introduced in e4.3.
@Inject
@Optional
public void appIsRunning(@UIEventTopic(UIEvents.UILifeCycle.APP_STARTUP_COMPLETE )
Event event) {
// Do something
}
|
|5+. UIEvents.UILifeCycle.ACTIVATE |Is an IEventBroker event. Triggers when the E4Application-Part becomes visible.
IEventBroker broker = (IEventBroker) iEclipseContext.get(IEventBroker.class.getName());
broker.subscribe(UIEvents.UILifeCycle.ACTIVATE,new EventHandler() {
@Override
public void handleEvent(Event event) {
System.out.println("LifeCycleManager: UILifeCycle.ACTIVATE");
}
});
// alternative annotation: you can inject the UIEventTopic Event
@Inject
@Optional
public void partActivation(@UIEventTopic(UIEvents.UILifeCycle.ACTIVATE) Event event, MApplication application) {
// retrieve data from event
MPart activePart = (MPart) event.getProperty(UIEvents.EventTags.ELEMENT);
}
|
|5+. UIEvents.UILifeCycle.BRINGTOTOP|Is an IEventBroker event. Triggers when the E4Application-Part get Focus and window comes to the top.
IEventBroker broker = (IEventBroker) iEclipseContext.get(IEventBroker.class.getName());
broker.subscribe(UIEvents.UILifeCycle.BRINGTOTOP,new EventHandler() {
@Override
public void handleEvent(Event event) {
System.out.println("LifeCycleManager: UILifeCycle.BRINGTOTOP");
}
});
});
|
|5+. UIEvents.UILifeCycle.PERSPECTIVE_OPENED|Is an IEventBroker event.
broker.subscribe(UIEvents.UILifeCycle.PERSPECTIVE_OPENED,new EventHandler() {
@Override
public void handleEvent(Event event) {
System.out.println("LifeCycleManager: UILifeCycle.PERSPECTIVE_OPENED");
}
});
|
|5+. UIEvents.UILifeCycle.PERSPECTIVE_SAVED|Is an IEventBroker event.
broker.subscribe(UIEvents.UILifeCycle.PERSPECTIVE_SAVED,new EventHandler() {
@Override
public void handleEvent(Event event) {
System.out.println("LifeCycleManager: UILifeCycle.PERSPECTIVE_SAVED");
}
});
|
|5+. @Focus |Indicates that this method should be called, once the Part gets the focus. It is required to set the focus on one user interface control otherwise certain workbench functionality does not work. \\ DONT SUPPORT INHERITANCE! If present on multiple inheritance levels - only called inside the class on the top of the hierarchy! |
|5+ @PreSave |Is called before the application model is saved. You can modify the model before it is persisted. |
|5+ @Persist |Is called if a save request on the Part is triggered. Can be used to save the data of the Part. |
|6. @PersistState |Is called before the model object is disposed, so that the Part can save its state. |
|7. @PreDestroy | Is called before the class is destroyed. Can be used to clean up resources. |
==== Handler Annotations ====
Sources: http://www.vogella.com/articles/EclipseRCP/article.html#commands_behaviorannotations
|@Execute| This method will be Executed when the handelr is started|
|@CanExecute|Mehtod annotated by this must return true, in order for the Handler's menuitem to be enabled! |
==== Eclipse Context Lifecycle ====
== notes ==
- Command Handlers are created in a different context, than in which they are executed. So can't use injections in there.
==== Commands with Parameters ====
To send a Command with a parameter it should be defined in the Applicationmodel.
{{http://i520.photobucket.com/albums/w327/schajtan/2013-11-29_12-09-20_zps54912a3d.png}} {{http://i520.photobucket.com/albums/w327/schajtan/2013-11-29_12-09-04_zpsd2eb6435.png}}
The matching handler will receive the command and the //@Exectue// annotated method will do logic behind it. \\
The command parameter can be injected using //@Named// annotation with the id of the command in it. \\
**ACHTUNG:** the parameter have to be injected as **METHOD PARAMETER**, not as class variable.
@Execute
public void execute(@Optional @Named("de.ivu.fare.commands.preferences.parameter.moduleId") String moduleIdParamater) {
...
@CanExecute
public boolean canExecute(){
return true;
}
To execute the command programmatically (with parameters) do the following:
ECommandService commandService = eclipseContext.get(ECommandService.class);
EHandlerService handlerService = eclipseContext.get(EHandlerService.class);
/*
* The map is filled with [String:parameterkey - String:value]
* Can not pass any parameterkey here. Only those, which were
* defined in model, as a Command Parameter.
*/
Map parameters = new HashMap();
parameters.put("de.ivu.fare.commands.preferences.parameter.moduleId",
module.getModuleId());
Command commandNoParms = commandService.getCommand("de.ivu.fare.commands.preferences");
ParameterizedCommand commandParametrized = ParameterizedCommand.generateCommand(
commandNoParms, parameters);
handlerService.executeHandler(commandParametrized);
==== Declarative Services in e4 alias. Context Functions====
By using declarative Services you can make an Iterface availabel, for injections in functions(not as plain @Inject annotated fields.)
A Factory is registered in xml, to return implementations of an Interface.
==Fallpits==
- this funcionality requires following bundles. Otherwise the serivecs wont be found.
- org.eclipse.core.runtime
- org.eclipse.equinox.ds
- org.eclipse.equinox.util
- org.eclipse.osgi.services
- And Bundle-ActivationPolicy: lazy must be set in the **MANIFEST.MF** file
- the service must be registered in the **MANIFEST.MF** file as Service-Component: OSGi-INF/service.xml
Infos:
* http://www.toedter.com/blog/?p=222
* http://tomsondev.files.wordpress.com/2012/03/e4_enhanced.pdf
* http://www.vogella.com/articles/OSGiServices/article.html
* http://books.google.de/books?id=RnTAeoBppE4C&pg=PA178&lpg=PA178&dq=e4+OSGi+declarative+services&source=bl&ots=hLFS_VCtMf&sig=g-e-Jgsf1Jrt6NwlXQwcV0p8x2w&hl=de&sa=X&ei=Gr0BUaaZFNGzhAf57IGABQ&redir_esc=y#v=onepage&q=e4%20OSGi%20declarative%20services&f=false
|< 100% 40% 60% >|
^Step ^ Describtion^
|1. edit MANIFEST.MF| register xml in MANIFEST.MF by adding the following lines
Service-Component: OSGI-INF/component.xml
Bundle-ActivationPolicy: lazy
|
|2. Dependencies| Require Bundles
org.eclipse.equinox.util
org.eclipse.equinox.ds - Declarative service
|
|3. Create Interface, Implementation, Factory| Factory **extends ContextFunction**
public interface IContextHellower {
void sayHello();
}
// you can add @Singleton to the implementing class. Then only one instance of the service will be created.
@Singleton
public class ContextHellower implements IContextHellower {
@Override
public void sayHello() {
System.out.println("Hellou!");
}
}
public class ContextHellowerCreationFunction extends ContextFunction {
@Override
public Object compute(IEclipseContext context) {
return ContextInjectionFactory.make(ContextHellower.class, context);
}
}
|
|4. Create an XML: OSGI-INF/component.xml | {{http://i520.photobucket.com/albums/w327/schajtan/2013-01-25_00-46-37.png?400}}|
|5. Inject |
@Inject
public PlaygroundPart(IContextHellower contextHellower) {
System.out.println("Injected IContextHellower "+contextHellower);
}
|
==== Adding a non model object to the model ====
If you need to use injections or other context features inside of a class, which isn't in the model - there are several ways to do so.
Then this class will be injected into the Context AND YOU WILL BE ABLE TO USE INJECTIONS INSIDE THIS CLASS!
| **IEclipseContext.runtrack(Runnable)** | The runnable is called once on PostConstruct. IEclipseContext is passed to it. After that it is called every time when one of the context object which Runnable has used - changes.
public TableCallbackHandler(IEclipseContext context) {
context.runAndTrack(new RunAndTrack() {
@Override
public boolean changed(IEclipseContext context) {
System.out.println("TableCallbackHandler#runAndTrack: Page activated");
activeEditorPage = context.get(EditorPage.class);
return true; // makes the method to be called again, when EditorPage.class changes
// in context
}
});
}
|
| **@Creatable** | Annotate the class by @Creatable. It can then be created by atomatically, on request from context. (e.g. on Injection or on ContextInjectionFactory.make(TableCallbackHandler.class, context);)
@Creatable
public class TableCallbackHandler {
EditorPage activeEditorPage;
@Inject
public TableCallbackHandler() {
@Inject
public void onFocusChange(EditorPage page) {
System.out.println("TableCallbackHandler#onFocusChange: Page activated");
this.activeEditorPage = page;
}
}
...
TableCallbackHandler t = ContextInjectionFactory.make(TableCallbackHandler.class, context);
If the automaticall creation has to be done programatically - don't forget to put the newly created object into the context. It is not done by calling make only.
if (!eclipseContext.containsKey(TableCallbackHandler.class)) {
Object handler = ContextInjectionFactory.make(TableCallbackHandler.class, eclipseContext);
eclipseContext.set(TableCallbackHandler.class.getName(), handler);
}
|
==== Using Menu in Applicaiton.e4xmi ====
=== Menu ===
The menu in Applicaiton.e4xmi is represented by **MMenu**. \\
The menu may be rendered to SWT widgets as following:
/**
* Same as the {@link #renderMenu(Menu, MMenuElement)} but skips the first menu object.
* Usable to flattern a menu object
*
* @param parentMenu - the parent menu
* @param menuElement - the element
*/
private void renderMenuSkipFirstLevel(Menu parentMenu, MMenu menuElement){
for(MMenuElement childMenuElement : menuElement.getChildren()){
renderMenu(parentMenu, childMenuElement);
}
}
/**
* Method which iterates all {@link MenuContribution} children and renders them
* @param parentMenu - the menu which should be used as the parent for rendered {@link MenuItem} objects
* @param mMenuContribution - the element from the e4 model which contains menu items
*/
public void renderMenu(Menu parentMenu, MMenuContribution mMenuContribution){
for(MMenuElement menuElement : mMenuContribution.getChildren()){
renderMenu(parentMenu, menuElement);
}
}
/**
* Renders the given {@link MenuElement} as a {@link Menu} and {@link MenuItem} structure.
*
* @param parentMenu - the menu which should be used as the parent for rendered {@link MenuItem} objects
* @param menuElement - the element from the e4 model which represents a menuItem
*/
@SuppressWarnings({ "unused", "restriction" })
public void renderMenu(Menu parentMenu, MMenuElement menuElement){
// not null
Assert.isNotNull(parentMenu);
if(menuElement instanceof MHandledItem){
MHandledItem item = (MHandledItem) menuElement;
MCommand mcommand = item.getCommand();
String commandId = mcommand.getElementId();
final ParameterizedCommand paramCommand = commandService.createCommand(commandId, null);
// swt
MenuItem menuItem = new MenuItem(parentMenu, SWT.PUSH);
menuItem.setText(item.getLabel());
menuItem.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
handlerService.executeHandler(paramCommand, eclipseContext);
}
});
}else if(menuElement instanceof MMenuSeparator){
MMenuSeparator item = (MMenuSeparator) menuElement;
// swt
new MenuItem(parentMenu, SWT.SEPARATOR);
}else if(menuElement instanceof MDirectMenuItem){
MDirectMenuItem item = (MDirectMenuItem) menuElement;
String contributionUri = item.getContributionURI();
final Object handler = contributionFactory.create(contributionUri,eclipseContext);
// swt
MenuItem menuItem = new MenuItem(parentMenu, SWT.PUSH);
menuItem.setText(item.getLabel());
menuItem.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
ContextInjectionFactory.invoke(handler, Execute.class, eclipseContext);
}
});
}else if(menuElement instanceof MDynamicMenuContribution){
DynamicMenuContributionImpl item = (DynamicMenuContributionImpl) menuElement;
String contributionUri = item.getContributionURI();
final Object handler = contributionFactory.create(contributionUri,eclipseContext);
// swt
MenuItem menuItem = new MenuItem(parentMenu, SWT.PUSH);
menuItem.setText(item.getLabel());
menuItem.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
ContextInjectionFactory.invoke(handler, Execute.class, eclipseContext);
}
});
}else if(menuElement instanceof MMenu){
MMenu menu = (MMenu) menuElement;
// swt
MenuItem mnItemSubmenu = new MenuItem(parentMenu, SWT.CASCADE);
mnItemSubmenu.setText(menu.getLabel());
String iconUri = menu.getIconURI();
Menu swtSubMenu = new Menu(mnItemSubmenu);
mnItemSubmenu.setMenu(swtSubMenu);
for(MMenuElement subElement : ((MMenu) menuElement).getChildren()){
renderMenu(swtSubMenu, subElement);
}
}
}
=== Menu Contributions ===
A menu contribution allows adding menu points to the menu by menu-id. \\
The menu contribution may e.g. be created in another e4-model-plugin.
For that:
- Create a main-menu, here with id **de.mine.e4.styleinspector.menu.context.basic** \\ {{http://i520.photobucket.com/albums/w327/schajtan/2015-01-26_14-58-46_zpsac0ea40e.png}}
- Create a MenuContriibution and use Parent-Id to point to the main-menu **de.mine.e4.styleinspector.menu.context.basic** \\ {{http://i520.photobucket.com/albums/w327/schajtan/2015-01-26_15-01-02_zpsb3844495.png}}
Retrieving the Menu may be done as following. It is assumed that a Menu-contribution ID_CONTEXTMENU_CONTRIB and a menu ID_CONTEXTMENU exist in model.
public static final String ID_CONTEXTMENU_CONTRIB = "de.mine.e4.styleinspector.menucontribution.cont1";
public static final String ID_CONTEXTMENU = "de.mine.e4.styleinspector.menu.context.basic";
// ACHTUNG: modelService.findElements does not find the **MenuContributions**. Have to iterate.
// inspect the model and find the Menus
MMenu mmenu = null;
for(MMenuContribution mmc : app.getMenuContributions()){
if(!mmc.getElementId().equals(ID_CONTEXTMENU_CONTRIB)){
continue;
}
List listMMenu = modelService.findElements(mmc, ID_CONTEXTMENU, MMenu.class, null);
if(!listMMenu.isEmpty()){
mmenu = listMMenu.get(0);
}
break;
}
// assemble the menu, consider the Menu-Contributions with the same parent-Id
MenuManagerRenderer mmr = getMenuManagerRenderer();
mmr.processContributions(mmenu, ID_CONTEXTMENU, false, false);
==== UI Toolkits in Eclipse 4 ====
^Toolkit ^Example ^
|
* **TM alias Toolkit Model** - Das Toolkit Model (TM) an EMF-Modell to generate UI-Layouts. \\ You can write Toolkit models manually, or generate them. \\ __It generates Layout only__, the __concrete content (widgets) are bound to the layout at runtime__. \\ Runtime modelchanges are directly shown in layout. \\ Because widgets are decoupled, they can run on a remote (web)server.
* Based on **EMF** - is an Eclipse own toolkit project which __takes UML__ like model (for modeling data) and __generates java code automatically__. \\ [[http://eclipsesource.com/blogs/2011/03/22/what-every-eclipse-developer-should-know-about-emf-part-1/|eclipsesource.com]], [[http://www.vogella.com/articles/EclipseEMF/article.html|vogella.com]]
* Based on **XMI** - is an XML based format, to save Object-metadata. It is a way to define 4th meta-level: \\ 1)Applicationmodel \\ 2)UML \\ 3)UML metamodel \\ 4)Meta-Metamodel - metamodel for UML
* Based on XML.
| {{http://i.imgur.com/765Ud.png?300}} {{http://i.imgur.com/daEoC.png?300}} {{http://i.imgur.com/t2x5r.png?300}} |
|
* **XWT** - Eclipse XML Window Toolkit. It takes declarative XML like models and generates __UI layouts and widgets.__ \\ During runtime the XWT reads the XML model and converts it to Java's SWT Wdgets. \\ There is a special Editor for this.
* Based on XML.
| |
==== CSS ====
== Fallpits ==
* Use //SWT.INHERIT_DEFAULT// stylebit to inherit properties through the widget hierarchy. composite.setBackgroundMode(SWT.INHERIT_DEFAULT)
* **ACHTUNG**: the underscores **_** are not allowed in classNames and ids. \\ Use Naming conventions like: //org-eclipse-bundle-classname// to tag a class org.eclipse.bundle.classname
* The widget do **NOT** have to be a **part of the e4 model** to styled successfully
^What ^Where^
|There is a cure presentation about CSS | [[http://manumitting.com/resources/presentations/2012-EclipseCon-CSS.pdf|EclipseCon 2012 CSS Presentation]]. |
|There is a list of CSS Tags| [[http://wiki.eclipse.org/E4/CSS/SWT_Mapping|SWT- CSS Mapping]] |
|Examples about using CSS Tags| [[http://tomsondev.bestsolution.at/2010/08/05/eclipse-4-0-so-you-can-theme-me-part-1/|http://tomsondev.bestsolution.at]] |
|Style It! The Eclipse 4 Styling Tutorial| [[https://max-server.myftp.org/trac/e4/export/36/trunk/kai/doc/eclipsecon-2011/e4-styling-tutorial-eclipsecon-2011.pdf]] |
== adding a CSS file to the application ==
== Enable a new look and feel (rounded corners) ==
The howto is [[http://www.vogella.com/blog/2010/03/10/eclipse-e4-new-look-and-feel/|described here]]
{{http://www.vogella.com/blog/wp-content/uploads/2010/03/roundcorners10.gif?400}}
== Possibilities of CSS in e4 ==
Here is a short list of customizable properties.
More properties are [[http://wiki.eclipse.org/E4/CSS/SWT_Mapping|listed here]].
^Java-Property ^CSS Attribute^
|**Class** | maps to **Selector**|
|**Background** | maps to
background-color: rgb(255,255,255) rgb(0,0,0) 10%; // 10% means, that the color must have been switched to the next color. So at 10%the color is allready black.
background-color: rgb(255,255,255) rgb(0,0,0) rgb(0,0,0) rgb(255,255,255) 10% 90% 100%; // color changes becomes black at 10%, stays black till 90%, becomes white at 100%
background-image: some url |
|border|border-color: #FF0000;border-width: 3; border-style: dotted;|
|cursor|cursor:crosshair;|
|font|
font: italic 12 bold "Terminal";
font-style: italic;
font-size: 12;
font-weight: bold;
font-family: "Terminal";|
|color|color: #FF0000 |
^class ^ widget ^
|
.MTrimBar {
background-color: #b3db18;
}|{{http://i520.photobucket.com/albums/w327/schajtan/2012-12-21_00-10-40.png?500}}|
|
.MTrimmedWindow {
background-color: #b3db18;
}|{{http://i520.photobucket.com/albums/w327/schajtan/demineapplication_2012-12-21_00-13-20.png?500}}|
|Patterns can be defined as bg, e.g. [[http://bgpatterns.com/|patterns from here]].
}
.MTrimmedWindow {
background-image: url("./pattern.png");
}|{{http://i520.photobucket.com/albums/w327/schajtan/demineapplication_2012-12-21_00-39-43.png?500}} {{http://i520.photobucket.com/albums/w327/schajtan/pattern.png}}|
|It is possible to select the active(focused) tabs, by using the "active" class. To define a default look - use more general CSS rule before defining the rule for special tabs.
/* match ALL Tabs, match ALL part stacks */
CTabItem, CTabFolder{
background-color: rgb(240,240,240);
}
/* OVERRIDES TWO GENERAL RULES ABOVE */
/* match Active part stack */
CTabFolder.active{
background-color: white;
}
/* match tabs in ACTIVE(focused) part stack */
CTabFolder.active CTabItem{
background-color:white;
}
/* match SELECTED tab in ACTIVE(focused) part stack */
CTabFolder.active CTabItem:selected{
background-color:rgb(200,212,0);
}|{{http://i.imgur.com/QXo5APn.png?500}}|
== Classes and ids==
//VOGELLA
// IStylingEngine was injected
// via @Inject
Label label = new Label(parent, SWT.NONE);
Text text = new Text(parent, SWT.BORDER);
// Set the ID, must be unique in the same window
IStylingEngine.setID(label, "MyCSSTagForLabel");
//alternatively set id
label.setData("org.eclipse.e4.ui.css.id",
"MyCSSTagForLabel2asId");
//or set class
label.setData("org.eclipse.e4.ui.css.CssClassName",
"MyCSSTagForLabel2asClass");
// Set the class, can be used several times
IStylingEngine.setClassname(text, "error");
//ECLIPSE CON
//set class
WidgetElement.setCSSClass(widget, “class string”);
// set id
WidgetElement.setID(widget, “id”);
Eclipse Tags are mapped to classes in css.
dashboardPart.getTags().add("dashboardPart");
dashboardPart.getTags().add("dashboardCashier");
/* match all dashboard parts: color of content pane */
*[class='MPart dashboardPart'] {
background-color: rgb(255,174,201);
}
/* match tabs of dashboard parts: color of tab */
CTabItem[class="dashboardPart"] {
tab-color: rgb(255,174,201);
}
/* match tabs of dashboard parts in ACTIVE(focused) part stack: color of tab */
CTabFolder.active CTabItem[class="dashboardPart"] {
tab-color: rgb(255,174,201);
}
/* match cashier dashboard parts: color of content pane */
*[class='MPart dashboardPart dashboardCashier'] {
background-color: rgb(106,181,255);
}
/* match tabs of cashier dashboard parts: color of tab */
CTabItem[class="dashboardCashier"] {
tab-color: rgb(106,181,255);
}
/* match tabs of cashier dashboard parts in ACTIVE(focused) part stack: color of tab */
CTabFolder.active CTabItem[class="dashboardCashier"] {
tab-color: rgb(106,181,255);
}
== PseudoElements ==
|
Shell:parented { background: red; }
Text:focus { background: parchment; }
CTabItem:selected{ background-color:rgb(200,212,0);}
CTabFolder:selected{ white;}
|
Psedoelements can be inspected with the css spy : \\
{{http://i.imgur.com/7nHMsCw.png?500}}|
== Extend CSS by own properties ==
Add the following to the plugin.xml, as [[http://wiki.eclipse.org/Eclipse4/RCP/Modeled_UI/Rendering_the_Model#Adding_CSS_Support_for_a_New_Widget_Type|stated here]]
//define a Handler
public class XXXPropertyHandler implements ICSSPropertyHandler {
public boolean applyCSSProperty(Object element, String property, CSSValue value, String pseudo, CSSEngine engine) throws Exception {
...
}
public String retrieveCSSProperty(Object widget, String pseudo, CSSEngine engine) throws Exception {
return ...;
}
}
==== Scripting ====
The Model can be edited live by using the Live Editor, see [[eclipse:eclipse_rcp4#tools|LiveEditor]].
Import the necessary plugins and use **ALT+Shift+F9** in your application.
{{http://i520.photobucket.com/albums/w327/schajtan/2013-01-27_16-22-19.png}}
^Objects ^Methods ^Describtion ^
|mainObject| All members of the element, chosen in Live Editor| The most importan Object|
|log| debug(Objects) \\ error(Object)| Logger Object |
|swt| newColor(Color) \\ newText(Composite, int) \\ new Label(Composite, int)| Can change SWT attributes here |
|eclipseContext| get(String name) | here you can enter the current EclipseObject |
|service| getStyleEngine() \\ getPartService() \\ getModelService()| Can get Services |
|di| newInstance(String, String, String) \\ execute(Object) | Object can get all Objects, available per Dependency injection |
**Example:**
mainObject.getWidget().setBackground(swt.newColor("#00ff00"));
var meinpart = service.getModelService().find("de.vogella.e4.rcp.part.playground", mainObject);
var meinuri = meinpart.getContributionURI();
log.debug(meinuri);
==== Model Processor ====
package de.mine.experiments.modelprocessor.processors;
import javax.inject.Inject;
import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.model.application.ui.basic.MBasicFactory;
import org.eclipse.e4.ui.model.application.ui.basic.MTrimmedWindow;
import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
/**
* A processor, registerd in extension Point: org.eclipse.e4.workbench.model
* Changes the existing model, as soon as the bundle , in which this processor is registered is loaded.
*
* @author skip
*
*/
public class Processor {
@Inject
MApplication application;
@Execute
public void execute(){
MWindow existingWindow = application.getChildren().get(0);
MTrimmedWindow newWindow = MBasicFactory.INSTANCE.createTrimmedWindow();
existingWindow.setX(300);
existingWindow.setY(300);
newWindow.setWidth(200);
newWindow.setHeight(existingWindow.getHeight());
newWindow.setY(existingWindow.getY());
newWindow.setX(existingWindow.getX()+existingWindow.getWidth());
application.getChildren().add(newWindow);
}
}
==== Persistence ====
==Model==
The Model changes are persisted into the file\\
...runtime-EclipseApplication\.metadata\.plugins\org.eclipse.e4.workbench\workbench.xmi
==Arguments==
Run configurations can have different, persistence relevant arguments:
^Argument ^ Meaning ^
|**-clearPersistedState**|Clears persisted model data (window size, position, open parts..) on every application -clearPersistedState|
|**-persistState**| If the app was started with this parameter - changes wont be persisted: -persistState true|
In code you can check, whether the -clearPersistedState was set, by injecting named data:
@Inject
@Named(E4Workbench.CLEAR_PERSISTED_STATE)
private boolean clearPersistedState;
==@PersistState==
To trigger persistence you should use the annotation **@PersistState**, see [[eclipse:eclipse_rcp4#annotations_for_injections|annotations]]
==== TAGS ====
The Tags are defined and explained inside of the Interface **org.eclipse.e4.ui.workbench.IPresentationEngine**
The following Tags can be added to the Parts:
NoTitle - hide part title
NoClose - prevents parts from being closed (no lcose button)
NoAutoCollapse - prevents MPartStack from autocollapse, when empty.(grey area) The Tag should be applied to Area, containing the MPartStack.
NoMove - prevents parts from being dragged out from stack
Minimized
Maximized
MinimizedByZoom
Horizontal
Vertical
e4_disabled_icon_image_key
e4_override_icon_image_key
e4_override_title_tool_tip_key
Animations Enabled
==== OSGI ====
=== ClassLoaders ====
Every Eclipse Bundle has an own class loader.
The mechanism is described here: http://www.martinlippert.org/publications/JS-Classloading-in-Eclipse-final-web.pdf
=== Logging in OSGI ====
**Achtung**
On default there already are OSGI Listeners, which redirect the Exceptions to STDout. \\
So e.g. OSGI Messaging (EventBroker) Exceptions should be visible in the Eclipse Console and Log. \\
But sometimes the Exception-messages just do not appear there, until Eclipse is restarted.
|Source: | https://code.google.com/p/osgi-logging/wiki/UnderstandingTheOSGiLogging |
OSGI implements a Fascade, behind which any framework like log4j may be used.
This is done, because logging is done per Bundle, which is not possible with other logging frameworks.
There are **LogService** and **LogReaderService** which may be retrieved inside the **Activator**.
Listeners may be installed to the LogReaderService.
Here is the summary of what is done below:
- you retrieve the **LogReaderService** from the Platform
- you add an own **LogService**
- inside the LogService you can log int oyour own file (e.g. using SLF4j)
The OSGI Platform will do the following:
- Some event will occur, e.g. because of an Exception
- The Eception will be bundled into an **LogEntry**
- The class **LogTracker** will be triggered
- LogTracker will pass the events on to platform services **org.osgi.service.log.LogService** and **org.eclipse.equinox.log.ExtendedLogService** (extends LogReaderService)
- the platform service org.eclipse.equinox.log.ExtendedLogService will pass the event to your **LogService**
import org.osgi.service.log.LogEntry;
import org.osgi.service.log.LogListener;
import org.osgi.service.log.LogService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OSGILogListenerImpl implements LogListener {
private static final Logger LOG = LoggerFactory.getLogger(OSGILogListenerImpl.class);
@Override
public void logged(LogEntry entry) {
if (entry.getMessage() != null) {
switch (entry.getLevel()) {
case LogService.LOG_ERROR:
LOG.error("Bundle: {}, Message: {}", entry.getBundle(), entry.getMessage(), entry.getException());
break;
case LogService.LOG_WARNING:
LOG.warn("Bundle: {}, Message: {}", entry.getBundle(), entry.getMessage(), entry.getException());
break;
case LogService.LOG_DEBUG:
LOG.debug("Bundle: {}, Message: {}", entry.getBundle(), entry.getMessage(), entry.getException());
break;
case LogService.LOG_INFO:
LOG.info("Bundle: {}, Message: {}", entry.getBundle(), entry.getMessage(), entry.getException());
break;
default:
break;
}
}
}
}
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.log.LogReaderService;
/**
* This class should be registerd as the Bundle Activator for a bundle, which is loaded early (low **osgi start level**)
*/
public class OSGILogActivator implements BundleActivator {
private OSGILogListenerImpl osgiLogListener = new OSGILogListenerImpl();
@SuppressWarnings({"rawtypes", "unchecked" })
private LogReaderService getReaderService(BundleContext context) {
LogReaderService readerService = null;
ServiceReference readerRef = context.getServiceReference(LogReaderService.class.getName());
if (readerRef != null) {
readerService = (LogReaderService) context.getService(readerRef);
}
return readerService;
}
@Override
public void start(BundleContext context) throws Exception {
LogReaderService readerService = getReaderService(context);
if (readerService != null) {
readerService.addLogListener(osgiLogListener);
}
}
@Override
public void stop(BundleContext context) throws Exception {
LogReaderService readerService = getReaderService(context);
if (readerService != null) {
readerService.removeLogListener(osgiLogListener);
}
}
}
In Eclipse you should use **ExtendedLogReaderService** to register to platform events, like errors on initialization of bundles.
{{http://i520.photobucket.com/albums/w327/schajtan/2015-06-10_17-01-57_zps9ibe1z8g.png}}
The listener-Bundle should be loaded as early as possible, in an own bundle which has a low **osgi start level**
This setting can be set within the runtim configuration or the product configuration.
{{http://i520.photobucket.com/albums/w327/schajtan/2015-06-10_17-11-28_zpsshyd0vkm.png}}
==== Fragments ====
A plugin may contribute any element to the **Application.e4xml**
- Create a Model Fragment (every one may contribute to one part of Model-Element)
- Featurename is the name of the element, how it is called inside ApplicationModel.e4xml: addons, children
{{http://i.imgur.com/opMRMHL.png}}
{{http://i.imgur.com/d5M6i78.png}}
==== Startup faster ====
Add following to the VM arguments
* in product as VM Argument -Dequinox.scr.waitTimeOnBlock=1
* as runtime parameter: -vmargs -Dequinox.scr.waitTimeOnBlock=1
* in Runtime configuration as VM Argument: -Dequinox.scr.waitTimeOnBlock=1
equinox.scr.waitTimeOnBlock=1
==== ToolControl in Window Trim ====
Icons in the Toolbar are difficult to center.
They are not created as children of Toolbar but as children of Composites, which are children of the ToolBar.
To set a fixed size to the composite and to center wom widget, like progressbar within do:
@PostComposite
public void createWidget(Composite parent){
// centering nested composite
Composite centering = new Composite(parent, SWT.NONE);
centering.setBounds(0, 0, 30, 20);
centering.setLayout(new GridLayout());
// centering.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
centering.setLayout(new GridLayout(1, false));
// progressbar
progressBar = new ProgressBar(centering, SWT.INDETERMINATE);
progressBar.setMaximum(progressBar.getMaximum());
GridData gd_progressBar = new GridData(SWT.CENTER, SWT.CENTER, true, true, 1, 1);
gd_progressBar.widthHint = 60;
progressBar.setLayoutData(gd_progressBar);
// listener
ToolItemSelectedListener listener = new ToolItemSelectedListener();
// cursor
centering.setCursor(cursor);
// do the logic
centering.addMouseListener(listener);
progressBar.addMouseListener(listener);
// tooltip here
String toolTip = MessagesUtils.getNlsMessage(Messages.class, KeyExportsInProgress);
progressBar.setToolTipText(toolTip);
==== Platform Files ====
|**platform.xml**|
In your Eclipse configuration directory in the org.eclipse.update folder, there should be a file named platform.xml. This is the file that the Update Configurator uses to determine the rest of the bundles that are known to your system.
The file is organized into sites. You should see a site with the location of platform:/base/ which basically means "everything from the plugins/ folder in my Eclipse install directory". If you have created application extension locations via the update manager UI or if you have a links/ folder then you will have a site entry for each one you have created.
If your bundle exists in an enabled site that is in the platform.xml file, then everything should be ok. Note that the sites can list either features or plug-ins so you may need to know which feature your plug-in belongs to, in order to figure out if it should be known. See: https://wiki.eclipse.org/Where_Is_My_Bundle#Update_-_platform.xml |
==== Eclipse RCP Project with Maven dependencies====
Maven dependencies can not be added to Eclipse RCP projects driectly.
It is possible to create a special RCP projects, which would resolve Maven dependencies automatically and share them with other plugins, which depend on them.
Several things have to be done by using **maven-felix-plugin**
* add jars to **classpath**
* **export** all packages
* set **Eclipse-BundlePolicy** to **global** (means that missing Classes will be looked up in all available packages)
* set **Bundle-ActivationPolicy** to **lazy**
bundleru.mine.dependencies.mavenorg.apache.logging.log4jlog4j-api2.3org.apache.logging.log4jlog4j-core2.3org.graylog2.log4j2log4j2-gelf1.1.0org.apache.felixmaven-bundle-plugintrueMETA-INF${rcp.bundle.name};singleton:=true**;type=jarjarslog4j/log4j.properties,log4j/Log4j2.xmltrue
<_failok>true
<_nouses>true
globallazy.,{maven-dependencies},log4j
==== Versioning ====
Eclipse bundles and features have version numbers of the form major.minor.micro.qualifier
1.0.0.SNAPSHOT
15.1.0.FINAL
Source: http://help.eclipse.org/kepler/index.jsp?topic=%2Forg.eclipse.pde.doc.user%2Ftasks%2Fpde_version_qualifiers.htm
You can modify the qualifier by different plugins.
E.g. tycho-packaging-plugin modifies it for tycho builds:
org.eclipse.tychotycho-packaging-plugin${tycho.version}org.eclipse.tycho.extrastycho-buildtimestamp-jgit0.23.1false'revvodoo1-'yyyyMMdd-HHmm-
makes the qualifier to be the following **after deploy** (**not inside the target folder**)
1.0.0.revvodoo1-20150906-2225
====== UnitTesting ======
Read here about Jubula, Q7: [[:unit_tests|Unit Testing the GUI]]
====== Examples by code ======
===== Creating a new Part =====
Add the following POJO into the Class URI field inside of Application.e4xml to create a new part.
{{http://i.imgur.com/raWE7dF.png}}
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import org.eclipse.e4.ui.di.Focus;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
public class PartSwt {
// @Inject annotated constructor will be used to create the Part
@Inject
public PartSwt(){
System.out.println("Constructor");
}
// will be called with, to fill the new part with content
@Inject
@PostConstruct
void onCreate(Composite partCanvas){
partCanvas.setLayout(new FillLayout());
Button b = new Button(partCanvas, SWT.NONE);
b.setText("SWT Button");
partCanvas.pack();
}
// will be called every time, when the new part retrieves focus
@Focus
void onFocus(){
System.out.println("On part Focus");
}
}
===== Manipulate the GUI programmatically =====
package de.vogella.e4.rcp.wizard.handlers;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.model.application.commands.MHandler;
import org.eclipse.e4.ui.model.application.ui.MUIElement;
import org.eclipse.e4.ui.model.application.ui.basic.MBasicFactory;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
import org.eclipse.e4.ui.model.application.ui.basic.MTrimmedWindow;
import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem;
import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement;
import org.eclipse.e4.ui.model.application.ui.menu.MMenuFactory;
import org.eclipse.e4.ui.workbench.modeling.EModelService;
import org.eclipse.e4.ui.workbench.modeling.EPartService;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.MenuItem;
public class ManipulateModelhandler {
/*
* Application representation.
* Represents the top level EMF Container, entrypoint for getting all the EMF-Model Data:
* - Addons
* - Binding Context
* - Binding Tables
* - Handlers
* ...
*
* Can retrieve active parts and everything, what is related to the model.
*/
@Inject
private MApplication mapplication;
/*
* Service, responsible for
* - finding the parts of the EMF Model by Tag, Id, Class
* - manipulating the EMF Model, bringing them to the top etc.
*/
@Inject
private EModelService eModelService;
//service, responsible for manipulating the model
@Inject
private EPartService ePartService;
@Execute
private void execute() {
//1. mapplication : FINDING APPLICATION DATA CONTRIBUTED IN Application.e4xml
mapplication.getHandlers();
mapplication.getRootContext();
mapplication.getSelectedElement();
mapplication.getToolBarContributions();
mapplication.getMenuContributions();
System.out.println("\n Total Handlers: "+mapplication.getHandlers().size());
for(MHandler handler : mapplication.getHandlers()){
handler.getCommand().getCommandName();
System.out.println("Found Handler which handles: "+handler.getCommand().getCommandName());
}
//2. eModelService : FINDING MODEL PARTS - use with MUIElement, MWindow
// Find objects by ID
List findElements = eModelService.findElements(mapplication, "de.vogella.e4.rcp.wizard.part.0", MPart.class, null);
System.out.println("InjectionHandler: Found part(s) : " + findElements.size());
// Find objects by type
List parts = eModelService.findElements(mapplication, null, MPart.class, null);
System.out.println("Found parts(s) : " + parts.size());
// Find objects by tags
List tags = new ArrayList();
tags.add("justatag");
List elementsWithTags = eModelService.findElements(mapplication, null, null, tags);
System.out.println("Found parts(s) : " + elementsWithTags.size());
// Get the MWindow and change its size
List windows = eModelService.findElements(mapplication, null, MWindow.class, null);
MWindow mWindow = windows.get(0);
mWindow.setWidth(mWindow.getWidth()-10);
/* ATTENTION: RootContext contains is the context, in which the commands can be activated,
* like "dialogAndWindow". It is not the Bundle Context! */
// mapplication.getRootContext();
IEclipseContext iEclipseContext1 = mapplication.getContext();
IEclipseContext iEclipseContext2 = eModelService.getActivePerspective(mWindow).getContext();
//get MTrimmedWindow from the context or by eModelService. Injecting MTrimmedWindow will fail
MTrimmedWindow mTrimmedWindow1 = iEclipseContext1.get(MTrimmedWindow.class); //null
MTrimmedWindow mTrimmedWindow2 = iEclipseContext2.get(MTrimmedWindow.class); //found
MTrimmedWindow mTrimmedWindow3 = eModelService.findElements(mapplication, null, MTrimmedWindow.class, null).get(0); //found
//3. eModelService : MANIPULATING MODEL PARTS - use with MUIElement, MWindow
//find "Demo" menu
MMenu mMenuDemo = null;
for( MMenuElement menu : mTrimmedWindow2.getMainMenu().getChildren()){
System.out.println("\nTop Menue :"+menu.getLabel() + " Element Id: "+menu.getElementId() ); //File Help Extras
if(menu.getElementId()!= null && menu.getElementId().equals("de.vogella.e4.rcp.prefs.menu.demo")){
mMenuDemo = (MMenu) menu;
}else{
((MUIElement)menu).setToBeRendered(false);
}
}
//EDIT: adding menu entries doesn't work yet. The do not appear.
//add an Exit menu-Entry
if(mMenuDemo != null){
MDirectMenuItem newExitItem = MMenuFactory.INSTANCE.createDirectMenuItem();
newExitItem.setLabel("New Exit");
//ACHTUNG: not setContributORURI!!!!
newExitItem.setContributionURI("bundleclass://de.vogella.e4.rcp.wizard/de.vogella.e4.rcp.wizard.handlers.QuitHandler");
mMenuDemo.getChildren().add(newExitItem);
newExitItem.setVisible(true);
newExitItem.setToBeRendered(true);
}
//moving parts around
MUIElement partPlayground = eModelService.find("de.vogella.e4.rcp.wizard.part.playground", mapplication);
MUIElement partDetails = eModelService.find("de.vogella.e4.rcp.wizard.part.details", mapplication);
//move the part to a new parent
if (partPlayground.getParent() != partDetails.getParent()){
// eModelService.move(partPlayground, partDetails.getParent()); //ATTENTION: ArrayIndexOutOfBoundsException
eModelService.move(partPlayground, partDetails.getParent(), 0);
}
//3. MBasicFactory : CREATING MODEL PARTS
MBasicFactory.INSTANCE.createTrimmedWindow();
MBasicFactory.INSTANCE.createTrimBar(); //the toolbar with icons at the top
MBasicFactory.INSTANCE.createPart();
MBasicFactory.INSTANCE.createWindow();
MBasicFactory.INSTANCE.createPartStack(); //a container, which makes parts appear as tabs
MBasicFactory.INSTANCE.createPartSashContainer(); //a container, which can arrange stacks horizontally or vertically
//create a new Part, attach it near playground
MPart newMPart = MBasicFactory.INSTANCE.createPart();
newMPart.setLabel("NewPart");
newMPart.setParent(partPlayground.getParent());
//create a new Window
MWindow mWindow = MBasicFactory.INSTANCE.createWindow();
mapplication.getChildren().add(mWindow);
}
private void wait(int sec){
int start = Calendar.getInstance().get(Calendar.SECOND);
while(Calendar.getInstance().get(Calendar.SECOND) - start
===== Create a new MWindow, with a custom Shell =====
The Shell for the MWindow is created by the **WBWRenderer.class** in context of the window.
Here we inject a custom, extended WBWRenderer into the context.
MWindow mWindow = MBasicFactory.INSTANCE.createWindow();
app.getChildren().add(mWindow);
mWindow.getTags().add(WBWRendererCustomTags.WINDOWTAG_CLOSERESIZE);
mWindow.setRenderer(new WBWRendererCustomTags());
Shell s = (Shell) mWindow.getWidget();
stylingEngine.setClassname(s, CSS_CLASS_WINDOW);
stylingEngine.setId(s, CSS_CLASS_WINDOW);
if (cssClassName != null) {
stylingEngine.setClassname(s, cssClassName);
}
for (Control c : s.getChildren()) {
c.setVisible(false);
}
s.pack();
return s;
===== Loading Image from Bundle =====
Label labelMessages = new Label(parent, SWT.NONE);
Bundle bundle = FrameworkUtil.getBundle(ControlTrimbarMessages.class);
URL fileURLImage = bundle.getEntry("/icons/showcat_co.gif");
URL fileUrl = null;
try {
fileUrl = FileLocator.toFileURL(fileURLImage);
} catch (IOException e) {
e.printStackTrace();
}
Image image = ImageDescriptor.createFromURL(fileUrl).createImage();
labelMessages.setImage(image);
====== FAQ ======
- Welche klassen haben einen Kontext?
-> die meissten model Klasen haben einen context
- wie ist die Kontext hierarchie? Ist es die Gleiche, wie im EMF Model? Context vom Parent Window ist das Parent-kontext von unterwindows?
-> in einem der Tutorials gibts eine uebersicht.
- wie kann man ein MWindow entfernen? (dispose)
-> man kann auf das zugrundeliegende Widget zugreifen. Dieses muss man casten und disposen.
- muss man einen Kontext initialisieren?
-> ja , neu erstellte Model-Objekte haben einen null-Context