Mittwoch, 5. Dezember 2012

Eclipse RCP / SWT - TreeViewer Sortierreihenfolge Teil 2

Eclipse 3.7

Problem: Knoten im TreeViewer sollen sortiert werden.

Lösung: Der ViewSorter erledigt die Sortierung. In unserem Beispiel werden die Knoten alphabetisch sortiert. Im ersten Teil dieses Artikels wurde ein Beispiel vorbereitet. Im diesem Teil soll die Sortierung hinzugefügt werden.

Schritt 1: Erzeuge die Klasse StructureViewerComparator.

import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;

public class StructureViewerComparator extends ViewerComparator {

  @Override
  public int compare(Viewer viewer, Object e1, Object e2) {
    if ((e1 instanceof MyTreeNode) && (e2 instanceof MyTreeNode)){
      return e2.toString().compareTo(e1.toString());
    }
    return 0;
  }
}

Schritt 2: In der View Klasse, wird in der createPartControl Methode dem Viewer ein neuer Comparator vom Typ StructureViewerComparator hinzugefügt.

 
public void createPartControl(Composite parent) {
  viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL
    | SWT.V_SCROLL);
  viewer.setContentProvider(new TreeContentProvider());
  viewer.setInput(new MyTreeNode(0,""));
  viewer.setComparator(new StructureViewerComparator()); //Comparator hinzugefügt
}

Schritt 3: Code ausführen!

Eclipse RCP / SWT - TreeViewer Sortierreihenfolge Teil 1

Eclipse 3.7

Problem: Knoten im TreeViewer sollen sortiert werden.

Lösung: Der ViewSorter erledigt die Sortierung. In unserem Beispiel werden die Knoten alphabetisch sortiert. Im ersten Teil dieses Artikels wird ein Beispiel vorbereitet. Im zweiten die Sortierung hinzugefügt.

Schritt 1: Erstelle die einfache TreeViewer Anwendung aus diesem Blog.

Schritt 2: Im zweiten Schritt wird das Modell der Knoten etwas abgeändert, damit eine Sortierung später nötig wird. Dazu wird der Klasse MyTreeNode ein Attribut prefix hinzugefügt, welches im Konstruktor initialisiert wird.


public class MyTreeNode {
 private int depth;
 private MyTreeNode parent = null;
 private ArrayList children;
 private String prefix; // neues Attribut

        //Übergabeparameter an den Konstruktor werden geändert 
 public MyTreeNode(int depth, String prefix) { 
  children = new ArrayList();
  this.prefix = prefix; // Initialisierung
  this.depth = depth;
 }

 ...

 public String toString() {
  StringBuffer sb = new StringBuffer();
  sb.append(prefix + " Knoten mit Tiefe ");
  sb.append(String.valueOf(depth));
  return sb.toString();
 }
        ...
}
Schritt 3: Im letzten Schritt wird an allen Stellen, an denen der Konstruktor aufgerufen wird der zweite Übergabeparameter mit einem willkürlichem String gefüllt. Dazu wird in der Klasse TreeContentProvider die Methode createChildNodes(Object parent) wie folgt geändert.

public class TreeContentProvider implements ITreeContentProvider {

...         

  public void createChildNodes(Object parent) {
    if (parent instanceof MyTreeNode) {
      MyTreeNode node = (MyTreeNode)parent;
      node.addChild(new MyTreeNode(node.getDepth() + 1, "1")); // zweiter 
      node.addChild(new MyTreeNode(node.getDepth() + 1, "5")); // Parameter 
      node.addChild(new MyTreeNode(node.getDepth() + 1, "3")); // mit beliebigen 
      node.addChild(new MyTreeNode(node.getDepth() + 1, "z")); // Werten
    }
  }
}
und zuletzt in der View Klasse die Methode createPartControl wie folgt geändert:

public void createPartControl(Composite parent) {
  viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL
    | SWT.V_SCROLL);
  viewer.setContentProvider(new TreeContentProvider());
  viewer.setInput(new MyTreeNode(0,"")); // hier ebenfalls aktualisiert
}

Sonntag, 25. November 2012

Eclipse RCP - 4.2 Juno Bug bei Applikation mit Template

Problem: Nach der Installation von Eclipse Juno 4.2 RCP Developer Version treten beim Erstellen von Eclipse RCP Applikationen aus einem Template heraus mehrere Fehler auf.

Diese sehen wie folgt aus:


!ENTRY org.eclipse.e4.ui.workbench 4 0 2012-11-25 00:42:28.600
!MESSAGE Unable to retrieve the bundle from the URI: 
bundleclass://org.eclipse.e4.ui.workbench.addons.swt
/org.eclipse.e4.ui.workbench.addons.cleanupaddon.CleanupAddon


!ENTRY org.eclipse.e4.ui.workbench 4 0 2012-11-25 00:42:28.600
!MESSAGE Unable to retrieve the bundle from the URI: 
bundleclass://org.eclipse.e4.ui.workbench.addons.swt
/org.eclipse.e4.ui.workbench.addons.dndaddon.DnDAddon

!ENTRY org.eclipse.e4.ui.workbench 4 0 2012-11-25 00:42:28.600
!MESSAGE Unable to retrieve the bundle from the URI: 
bundleclass://org.eclipse.e4.ui.workbench.addons.swt
/org.eclipse.e4.ui.workbench.addons.minmax.MinMaxAddon



Schritte um das Problem nachzustellen:

Schritt 1: Download von Eclipse Juno (hier: Build id: 20120614-1722)

Schirtt 2: Komprimierte Datei entpacken und Eclipse starten

Schritt 3: Ein Plugin Projekt erstllen der auf dem Template "RCP application with a view" basiert.

Schritt 4: Pluginprojekt ausführen. In der Standardausgabe erscheinen dann die Fehlermeldungen.

Schritte für eine Lösung

Lösungsschritt 1: das plugin org.eclipse.e4.ui.workbench.addons.swt unter Dependencies im MANIFEST.MF hinzufügen siehe Abbildung 1.
Abbildung 1


Lösungsschritt 2:Speichern und Eclipse RCP Applikation ausführen. Fertig!


Dieser Artikel basiert auf der folgenden Quelle (Stand: 25.11.2012) : https://bugs.eclipse.org./bugs/show_bug.cgi?id=369073

Donnerstag, 8. November 2012

Eclipse RCP - Datei im Bundle öffnen

Eclipse Version 3.7

Problem: Wie öffne ich eine Datei, die sich im Bundle/meiner RCP Applikation befindet. In der Beispielanwendung wird eine BMP Datei geöffnet.

Schritt 1: Verzeichnis mit BMP Datei anlegen

Die Datei befindet sich im Rootverzeichnis des Projekts. Bild 1 zeigt eine Projektstruktur mit dem Verzeichnis myfiles und einer Bilddatei picture.bmp
Bild 1

Schritt 2: Build Configuration anpassen

In der Build Configuration des plugin.xml im Binary Build muss das Verzeichnis mit eingebunden sein. (Bild 2)
Bild 2
Schritt 3: Ausführenden Code einfügen

Der Quellcode kann z.B. in einen Command Handler eingefügt werden. Es wird die Standardapplikation für den jeweiligen Dateityp gestartet. Diese muss vorher im Betriebssystem definiert sein. In Windows ist dies z.B. Paint.

  URL fileURL = null;
  try {
    fileURL = FileLocator
               .toFileURL(Activator.getDefault()
               .getBundle()
               .getEntry("myfiles/picture.bmp"));
    String filePath = fileURL.getPath();

    File file = new File(filePath);
    Desktop.getDesktop().open(file);
  } catch (IOException e) {
     e.printStackTrace();
  }

Ein alternativer Code der die gleiche Wirkung hat wird im Codeache Blog von Hugo Corbucci beschrieben.

  Bundle bundle = Activator.getDefault().getBundle();
  Path path = new Path("myfiles/picture.bmp"); //$NON-NLS-1$
  URL url = FileLocator.find(bundle, path, Collections.EMPTY_MAP);
  URL fileUrl = null;
  try {
    fileUrl = FileLocator.toFileURL(url);
    File file = new File(fileUrl.getPath());
    Desktop.getDesktop().open(file);
  } catch (IOException e) {
    e.printStackTrace();
  }

Schritt 4: Ausführen. Fertig!

Montag, 5. November 2012

Eclipse RCP - Command und bedingtes Anzeigen von Menüeinträgen

Problem: Die Applikation zeigt Menüs oder Contextmenüs (MenuContribution) an, die in Abhängigkeitei von der Selektion oder anderen Kriteren einen Menüeintrag (Command) Anzeigen soll. Die Commands sind deklarativ definiert.

Ein konkreteres Szenario könnte wie folgt aussehen:

Beim Rechtsklick auf ein Objekt in einem TreeViewer oder einen Tabelleneintrag im TableViewer soll ein Attribut aus dem jeweiligen Objekt abgefragt werden (test).

Lösung:

Diese Lösung ist nicht zu 100% deklarativ. Jedoch stellt diese einen kurzen und übersichtlichen Weg dar.

Schritt 1:
In der Handler Klasse muss die Methode isEnabled() überschrieben werden und immer dann true zurückliefern, wenn der Menüeintrag angezeigt werden soll. In allen Anderen Fällen muss diese Methode ein false zurückliefern.

Schritt 2:
In der Datei plugin.xml muss im Tag MenuContribution das Command wie folgt definiert sein:


 <command 
       commandid="com.blogger.javadingsda.beispielCommand" 
       label="Menüeintrag">
    <visiblewhen checkenabled="true"></visiblewhen>
 </command>



(... Fortsetzung mit einem ausführlichen Beispiel folgt)

Labels:

visibleWhen, property, test, expressions framework, command core expressions

Samstag, 3. November 2012

Eclipse RCP - There is no handler to execute for command

Eclipse Version 3.7

Problem: Ihr habt ein Command angelegt. Zusätzlich habt ihr ein Handler zum Command angelegt und eine Klasse zum Handler erstellt die org.eclipse.core.commands.IHandler oder org.eclipse.core.commands.IHandler2 implementiert bzw. vom org.eclipse.core.commands.AbstractHandler erbt. Diese Klasse ist beim Handler eingetragen. Eigentlich sollte dann alles laufen, ihr erhält aber dennoch eine Exception mit dem Text "There is no handler to execute for command...".
Lösung:

In der Klasse die zum Händler gehört muss die Methode istHandled() ein true zurückgeben, da sonst das Fremework eine NotHandledException wirft. Wenn es nicht unbedingt nötig sollte man auf das Überschreiben der isHandled Methode verzichten bzw. vom Abstract Handler erben.


@Override
public boolean isHandled() {

    return true;

}




Dieser Artikel basiert auf dem Forumbeitrag http://slopjong.de/2010/04/01/there-is-no-handler-to-execute-for-command/

Freitag, 7. September 2012

Eclipse RCP - SWT ScrolledComposite schneller scrollen

Die Codezeile Zeigt wie ein ScrolledComposite dazu gebracht werden kann schneller über die Buttons zu Scrollen. Das Beispiel scrollt die ScrolledComposite sc vertikal fünf mal schneller.

sc.getVerticalBar().setIncrement(sc.getVerticalBar().getIncrement()*3);

Quelle: http://www.richclient2.de/2006_10_03/scrolledcomposite-and-the-mouse-wheel/

Montag, 20. August 2012

Reguläre Ausdrücke

Habe neulich ein Tutorial für Reguläre Ausdrücke gesucht und bin fündig geworden. Da ich der Meinung bin, dass ein gutes Tuorial es verdient verlinkt zu werden hier der Link zum Tutorial.

Dienstag, 31. Juli 2012

Eclipse RCP - Fenster Applikationsname ändern programmatisch

Dieses kurze Tutorial zeigt wie in einer Eclipse RCP Anwendung der Titel im Fenster beim Start via Code (programmatisch) geändert werden kann.

Eclipse Version 3.7

Schritt 1: RCP Applikation mit dem Namen com.blogspot.javadingsda.windowtitle aus der Vorlage 'RCP application with a view' erstellen.

Schritt 2: Füge in der Klasse ApplicationWorkbenchAdvisor in der Methode createWorkbenchWindowAdvisor die Zeile configurer.setTitle("My Title!"); hinzu.

public class ApplicationWorkbenchAdvisor extends WorkbenchAdvisor {
 
 @Override
 public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(
                                 IWorkbenchWindowConfigurer configurer) {
   configurer.setTitle("My Title!"); 
   return new ApplicationWorkbenchWindowAdvisor(configurer);
 }

 @Override
 public String getInitialWindowPerspectiveId() {
  return Perspective.ID;
 } 
}


Schritt 3: Kompilieren und testen!

Donnerstag, 29. März 2012

Eclipse RCP - Widgets in der Statusleiste (StatusLine/Statusbar)

Eclipse Version 3.7

Dieser Artikel zeigt wie eine Statusleiste(im folgenden Text auch Statusline genannt) aktiviert werden kann und wie einige Widgets zu dieser hinzugefügt werden können.


Problemstellung:

In der Statusleiste einer Eclipse RCP Anwendung soll eine Textbox mit einer Schaltfläche (Button) erscheinen. Beim Klick auf die Schalfläche soll der Text aus der Textbox in der view erscheinen.









Lösung
Es gibt zwei wichtige Schritte die beachtet werden müssen, um eine Statusleiste zu erzeugen. Erstens muss in der Klasse, die vom WorkbenchWindowAdvisor erbt (in unserem Beispiel ist es die Klasse ApplicationWorkbenchWindowAdvisor) in der Methode preWindowOpen die Anzeige der Statusline aktiviert werden. Zweitens muss die Methode fillStatusLine in er Klasse ApplicationActionBarAdvisor überschrieben werden um dort eine ControlContribution einzufügen, die den Ihnalt der Statusleiste repräsentiert. Alle nötigen Schritte werden unten genauer beschrieben.

Schritt 1
Erzeuge eine RCP Application aus dem Template RCP Eclipse Application with a view mit dem Namen com.blogspot.javadingsda.statusline.

Schritt 2
Erzeuge die Klasse StatusLineTextBox. Diese repräsentiert die Statuszeile.

package com.blogspot.javadingsda.statusline;

import org.eclipse.jface.action.ControlContribution;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Text;

public class StatusLineTextBox extends ControlContribution {

 Text textBox;
 private View view;

 public StatusLineTextBox(String str) {
  super(str);
 }

 @Override
 protected Control createControl(Composite parent) {

  textBox = new Text(parent, SWT.BORDER );
  textBox.setText("hier was eingeben!");
  
  Button button = new Button(parent, SWT.NONE);
  button.setText("Text oben ausgeben");
  button.addSelectionListener(new SelectionAdapter() {
   public void widgetSelected(SelectionEvent e) {
    view.setText(textBox.getText());
    view.update();
   }
  });

  return textBox;
 }

 public void addView(View view) {
  this.view = view;
 }
}


Schritt 3
Füge zur Klasse ApplicationActionBarAdvisor die Methode fillStatusLine hinzu. Die Klasse sollte wie folgt aussehen:

package com.blogspot.javadingsda.statusline;

import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.ui.application.ActionBarAdvisor;
import org.eclipse.ui.application.IActionBarConfigurer;

public class ApplicationActionBarAdvisor extends ActionBarAdvisor {

 public static StatusLineTextBox textBox = new StatusLineTextBox("MyBox");
 public ApplicationActionBarAdvisor(IActionBarConfigurer configurer) {
  super(configurer);
 }
 
 @Override
 protected void fillStatusLine(IStatusLineManager statusLine) {
  super.fillStatusLine(statusLine);
  statusLine.add(textBox);
 }
}


Schritt 4

package com.blogspot.javadingsda.statusline;

import org.eclipse.swt.graphics.Point;
import org.eclipse.ui.application.ActionBarAdvisor;
import org.eclipse.ui.application.IActionBarConfigurer;
import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
import org.eclipse.ui.application.WorkbenchWindowAdvisor;

public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {

 public ApplicationWorkbenchWindowAdvisor(
   IWorkbenchWindowConfigurer configurer) {
  super(configurer);
 }

 public ActionBarAdvisor createActionBarAdvisor(
   IActionBarConfigurer configurer) {
  return new ApplicationActionBarAdvisor(configurer);
 }

 @Override
 public void preWindowOpen() {
  IWorkbenchWindowConfigurer configurer = getWindowConfigurer();
  configurer.setInitialSize(new Point(400, 300));
  configurer.setShowCoolBar(false);
  configurer.setShowStatusLine(true); // auf true setzen
  configurer.setTitle("RCP Application");
 }
}


Schritt 5
Anschließend muss nur noch die View modifiziert werden.

package com.blogspot.javadingsda.statusline;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.part.ViewPart;

public class View extends ViewPart {
 public static final String ID = "com.blogspot.javadingsda.statusline.view";

 private String text = "Testmich!";

 private Label l1;

 public void createPartControl(Composite parent) {
  ApplicationActionBarAdvisor.textBox.addView(this);
  l1 = new Label(parent, SWT.NONE);
  l1.setText(text);
 }

 public void setFocus() {}

 public void setText(String text) {
  this.text = text;
 }

 public void update() {
  l1.setText(text);
 }
}


Anwendung ausführen. Fertig!

Dieser Artikel basiert auf den folgenden Quellen: www.java-tips.org und www.saxonysoft.de

Dienstag, 6. März 2012

Eclipse RCP - TreeViewer drag and drop (DnD)

Eclipse Version 3.7 (Indigo)


In diesem Artikel (Tutorial) wird ein einfaches 'Drag and Drop' Beispiel mit einem TreeViewer gezeigt.

Problem:
In einem TreeViewer sollen die Knoten per 'Drag and Drop' umgeordnet werden. Es soll möglich sein, einen Knoten des TreeViewer gezielt vor oder hinter einen anderen Knoten einzufügen. Es ist nicht möglich die Knoten eines TreeViewer zwischen zwei Fenstern zu schieben. Sollte ein Interesse an solch einem Tutorial bestehen, dann schickt mir bitte eine kurze Info per Mail.

Schritt 1:
RCP Applikation mit dem Namen com.blogspot.javadingsda.dndfirst aus der Vorlage 'RCP application with a view' erstellen.

Schritt 2:
Entferne alle inneren Klassen, Methoden und Attribute aus der View Klasse und ersetze sie durch den unten aufgeführten Code. Die View Klasse sollte wie folgt aussehen.

package com.blogspot.javadingsda.dndfirst;

import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;

public class View extends ViewPart {
 public static final String ID = "com.blogspot.javadingsda.dndfirst.view";

 private TreeViewer viewer;
 Model model = new Model();

 public void createPartControl(Composite parent) {
  viewer = new TreeViewer(parent, SWT.H_SCROLL | SWT.V_SCROLL);
  viewer.setContentProvider(new ViewContentProvider());
  Transfer[] transferTypes = new Transfer[] { 
                                                    TextTransfer.getInstance() };
  viewer.addDragSupport(DND.DROP_MOVE | DND.DROP_COPY, 
                                      transferTypes,
          new NodeDragListener(viewer));
  viewer.addDropSupport(DND.DROP_MOVE | DND.DROP_COPY, 
                                      transferTypes,
          new NodeDropListener(this, viewer));
  viewer.setInput(model.getRoot());
 }

 public void setFocus() {
  viewer.getControl().setFocus();
 }
}

Schritt 3:
Erzeuge die Klasse ViewContentProvider. Die Funktionalität dieser Klasse (bzw. der Klasse ITreeContentProvider) wird im Artikel Eclipse RCP / SWT - Einfaches TreeViewer Beispiel erläutert.

package com.blogspot.javadingsda.dndfirst;

import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;

public class ViewContentProvider implements ITreeContentProvider {

 public void inputChanged(Viewer v, Object oldInput, Object newInput) {
 }

 public void dispose() {
 }

 public Object[] getElements(Object parent) {
  TreeNode ret = (TreeNode) parent;
  return ret.getChildren();
 }

 @Override
 public Object[] getChildren(Object parentElement) {
  TreeNode node = (TreeNode) parentElement;
  return node.getChildren();
 }

 @Override
 public Object getParent(Object element) {
  TreeNode node = (TreeNode) element;
  return node.getParent();
 }

 @Override
 public boolean hasChildren(Object element) {
  TreeNode node = (TreeNode) element;
  return node.getChildren().length > 0;
 }
}


Schritt 4:
Erzeuge die Klasse TreeNode. Diese repräsentiert die Knotenpunkte im Baum. Abgesehen von den standard Methoden wie getParent und addChild besitzt diese Klasse die Methoden insertAfter und insertBefore. Die Methode insertAfter fügt einen Knoten hinter einen anderen Knoten hinzu. Die Methode insertBefore fügt einen Knoten vor einen anderen Knoten.









package com.blogspot.javadingsda.dndfirst;

import java.util.LinkedList;
import java.util.List;

public class TreeNode {

 private List<TreeNode> children = new LinkedList<TreeNode>();
 private String name; // visible name
 private TreeNode parent;

 public TreeNode(String name) {
  this.name = name;
 }

 public void addChild(TreeNode child) {
  if (child.getParent() != null) {
   ((TreeNode) child.getParent()).children.remove(child);
  }
  child.setParent(this);
  children.add(child);
 }

 public void removeChild(TreeNode node) {
  children.remove(node);
  node.setParent(null);
 }

 public void insertAfter(Object targetObj) {
  TreeNode target = convertToTreeNode(targetObj);
  List<TreeNode> childrenList = target.parent.children;
  int targetIndex = childrenList.indexOf(target);
  int thisIndex;
  int index;
  if (target.parent == this.parent) {
   thisIndex = childrenList.indexOf(this);
   if (thisIndex < targetIndex)
    index = targetIndex;
   else
    index = targetIndex + 1;
  } else {
   index = targetIndex + 1;
  }
  insertChild(target, index);
 }

 public void insertBefore(Object targetObj) {
  TreeNode target = convertToTreeNode(targetObj);
  int index;
  int thisIndex;
  int targetIndex = target.parent.children.indexOf(target);
  if (target.parent == this.parent){
   thisIndex = target.parent.children.indexOf(this);
   if (thisIndex < targetIndex) {
    index = targetIndex - 1;
   } else {
    index = targetIndex;
   }
  } else {
   index = targetIndex;
  }
  insertChild(target, index);
 }

 private void insertChild(TreeNode target, int index) {
  if (parent != null)
   parent.removeChild(this);
  target.parent.children.add(index, this);
  this.setParent(target.parent);
 }

 private TreeNode convertToTreeNode(Object obj) {
  if (obj instanceof TreeNode) {
   return (TreeNode) obj;
  }
  return null;
 }

 private void setParent(TreeNode parent) {
  this.parent = parent;
 }

 public String toString() {
  return name;
 }

 public Object[] getChildren() {
  return children.toArray();
 }

 public Object getParent() {
  return parent;
 }
}
Schritt 5:
Erzeuge die Model Klasse. Die Model Klasse erzeugt einen Baum in dem die Knoten durchnummeriert sind. Die Reihenfolge ist willkürlich.

package com.blogspot.javadingsda.dndfirst;

import java.util.HashMap;

public class Model {

 private TreeNode root = new TreeNode("root");
 private HashMap<String, TreeNode> map = new HashMap<String, TreeNode>();

 public Model() {

  TreeNode node1 = new TreeNode("Node1");
  TreeNode node2 = new TreeNode("Node2");
  TreeNode node3 = new TreeNode("Node3");
  TreeNode node4 = new TreeNode("Node4");
  TreeNode node5 = new TreeNode("Node5");
  TreeNode node6 = new TreeNode("Node6");
  TreeNode node7 = new TreeNode("Node7");
  TreeNode node8 = new TreeNode("Node8");
  TreeNode node9 = new TreeNode("Node9");
  TreeNode node10 = new TreeNode("Node10");
  TreeNode node11 = new TreeNode("Node11");
  TreeNode node12 = new TreeNode("Node12");
  TreeNode node13 = new TreeNode("Node13");

  map.put("root", root);
  map.put("Node1", node1);
  map.put("Node2", node2);
  map.put("Node3", node3);
  map.put("Node4", node4);
  map.put("Node5", node5);
  map.put("Node6", node6);
  map.put("Node7", node7);
  map.put("Node8", node8);
  map.put("Node9", node9);
  map.put("Node10", node10);
  map.put("Node11", node11);
  map.put("Node12", node12);
  map.put("Node13", node13);

  root.addChild(node1);
  root.addChild(node2);
  node1.addChild(node3);
  node1.addChild(node4);
  node1.addChild(node5);
  node2.addChild(node6);
  node2.addChild(node7);
  node2.addChild(node8);
  node2.addChild(node9);
  node2.addChild(node10);
  root.addChild(node11);
  root.addChild(node12);
  root.addChild(node13);
 }

 public TreeNode getRoot() {
  return root;
 }

 public TreeNode get(String nodeName) {
  return map.get(nodeName);
 }
}

Schritt 6:
Erzeuge die Klasse NodeDragListener. Die vom DragScourceAdapter geerbte Methode dragSetData(DragSourceEvent event) hat die Aufgabe den Text des beim 'draggen' selektierten Knotens im data Attribut abzulegen. Sollte die Selektion nicht auf einem TreeViewer statt finden, dann wird die 'Drag and Drop' Aktion abgebrochen.

package com.blogspot.javadingsda.dndfirst;

import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.dnd.DragSourceAdapter;
import org.eclipse.swt.dnd.DragSourceEvent;

public class NodeDragListener extends DragSourceAdapter {

  private TreeViewer treeViewer;

  public NodeDragListener(TreeViewer treeViewer) {
    this.treeViewer = treeViewer;
  }

  @Override
  public void dragSetData(DragSourceEvent event) {
    ISelection selection = treeViewer.getSelection();

    if (selection instanceof TreeSelection) {
      TreeSelection treeSelection = (TreeSelection) selection;
      event.data = ((TreeNode) treeSelection.getFirstElement())
                                  .toString();
    } else {
      event.doit = false;
    }
  }
}


Schritt 7:
Erzeuge die Klasse NodeDropListener. Diese Klasse steuert den 'Drop', d.h. die Ereignisse wenn der Benutzer einen Knoten wieder im Baum losläßt. Die Methode validateDrop prüft ob ein Element auf der definierten stelle losgelassen ('gedropt') werden kann. Diese wird vom ViewDropAdapter benutzt. Die drop Methode kümmert sich um das Verschieben der TreeNode im Baum, indem sie die Aufgabe an die richtige Methode der Ziel TreeNode delegiert. Das Attribut operation zeigt an, in welcher Relation die TreeNode zur Ziel TreeNode hinzugefügt werden soll.

package com.blogspot.javadingsda.dndfirst;

import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.ViewerDropAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.TransferData;

class NodeDropListener extends ViewerDropAdapter {

  private View view;
  private TreeViewer treeViewer;
  private TreeNode target;
  private int operation;

  public NodeDropListener(View view, TreeViewer treeViewer) {
    super(treeViewer);
    this.view = view;
    this.treeViewer = treeViewer;
  }

  @Override
  public void drop(DropTargetEvent event)  {

    if (event.data instanceof String) {
      operation = this.determineLocation(event);
      TreeNode dropedNode = this.view.model.get((String) event.data);
      TreeNode parentDropedNode = (TreeNode) dropedNode.getParent();
      if (dropedNode == target)
        return;
      switch (this.operation) {
        case ViewerDropAdapter.LOCATION_AFTER:
          dropedNode.insertAfter(target);
          System.out.println(dropedNode + " wurde hinter " + target + " eingefügt.");
          break;
        case ViewerDropAdapter.LOCATION_BEFORE:
          dropedNode.insertBefore(target);
          System.out.println(dropedNode + " wurde vor " + target + " eingefügt.");
          break;
        case ViewerDropAdapter.LOCATION_ON:
          if (dropedNode != target.getParent())
               target.addChild(dropedNode);
          System.out.println(dropedNode + " wurde zur " + target + " eingefügt.");
          break;
        case ViewerDropAdapter.LOCATION_NONE:
          break;
        default:
          break;
      }
      super.drop(event);
      treeViewer.refresh(this.target.getParent(), true);
      treeViewer.refresh(parentDropedNode, true);
    }
  }

  @Override
  public boolean performDrop(Object data) {
    return true;
  }

  @Override
  public boolean validateDrop(Object target, int operation,
                              TransferData transferType) {
    if (target instanceof TreeNode) {
      this.target = (TreeNode) target;
      this.operation = operation;
      return true;
    } else {
      this.target = null;
      this.operation = 0;
      return false;
    }
  }
}

Wird die Anwendung ausgeführt, dann wird in der Standardkonsole die Position des einzufügenden Knotens angezeigt.
Dieser Artikel baut auf dem Artikel Eclipse Drag and Drop. von Lars Vogel

Donnerstag, 1. März 2012

Eclipse RCP - Plug-in Problem

Problem:
Beim Ausführen eines Plugin Projekts erhält man die Fehlermeldung:

!SESSION 2012-03-01 16:09:21.828 -----------------------------------------------
eclipse.buildId=unknown
java.version=1.6.0_22
java.vendor=Sun Microsystems Inc.
BootLoader constants: OS=win32, ARCH=x86, WS=win32, NL=de_DE
Framework arguments:  -application com.blogspot.javadingsda.databindingeasy.application
Command-line arguments:  -application com.blogspot.javadingsda.databindingeasy.application -data C:\dev\workspaces\databinding/../runtime-com.blogspot.javadingsda.databindingeasy.application -dev file:C:/dev/workspaces/databinding/.metadata/.plugins/org.eclipse.pde.core/com.blogspot.javadingsda.databindingeasy.application/dev.properties -os win32 -ws win32 -arch x86 -consoleLog

!ENTRY org.eclipse.osgi 2 0 2012-03-01 16:09:23.296
!MESSAGE One or more bundles are not resolved because the following root constraints are not resolved:
!SUBENTRY 1 org.eclipse.osgi 2 0 2012-03-01 16:09:23.296
!MESSAGE Bundle initial@reference:file:../../../workspaces/databinding/com.blogspot.javadingsda.databindingeasy/ was not resolved.
!SUBENTRY 2 com.blogspot.javadingsda.databindingeasy 2 0 2012-03-01 16:09:23.296
!MESSAGE Missing required bundle org.eclipse.core.databinding.beans_1.2.100.

!ENTRY org.eclipse.osgi 2 0 2012-03-01 16:09:23.312
!MESSAGE The following is a complete list of bundles which are not resolved, see the prior log entry for the root cause if it exists:
!SUBENTRY 1 org.eclipse.osgi 2 0 2012-03-01 16:09:23.312
!MESSAGE Bundle com.blogspot.javadingsda.databindingeasy_1.0.0.qualifier [32] was not resolved.
!SUBENTRY 2 com.blogspot.javadingsda.databindingeasy 2 0 2012-03-01 16:09:23.312
!MESSAGE Missing required bundle org.eclipse.core.databinding.beans_1.2.100.

!ENTRY org.eclipse.osgi 4 0 2012-03-01 16:09:23.312
!MESSAGE Application error
!STACK 1
java.lang.RuntimeException: Application "com.blogspot.javadingsda.databindingeasy.application" could not be found in the registry. The applications available are: org.eclipse.equinox.app.error.
    at org.eclipse.equinox.internal.app.EclipseAppContainer.startDefaultApp(EclipseAppContainer.java:248)


so oder ähnlich .
In der plugin.xml wurden die benötigten Plugins aber hinzugefügt.





Mögliche Lösung:

Rechter Mausklick auf das Projekt. Im Kontext Menü 'Properties' auswählen. Dann 'Run/Debug Settings'. Das zum Projekt passende Produkt auswählen und mit dem Edit Button bearbeiten. Reiter Plug-ins auswählen und nachsehen ob beim bemängelten Bundle ein Häckchen steht. In diesem Beispiel ist es 'org.eclipse.core.databinding.beans_1.2.100'. Falls dies nicht der Fall ist, Häckchen setzen.