Index: /trunk/sources/HeuristicLab.CEDMA.Core/Console.cs
===================================================================
--- /trunk/sources/HeuristicLab.CEDMA.Core/Console.cs	(revision 416)
+++ /trunk/sources/HeuristicLab.CEDMA.Core/Console.cs	(revision 417)
@@ -33,4 +33,5 @@
   public class Console : ItemBase, IEditable {
     private AgentList agentList;
+    private DatabaseOperatorLibrary operatorLibary;
     private ChannelFactory<IDatabase> factory;
     private IDatabase database;
@@ -44,7 +45,12 @@
     }
 
+    public IOperatorLibrary OperatorLibrary {
+      get { return operatorLibary; }
+    }
+
     public Console()
       : base() {
       agentList = new AgentList();
+      operatorLibary = new DatabaseOperatorLibrary();
     }
 
@@ -82,4 +88,5 @@
       database = factory.CreateChannel(new EndpointAddress(serverUri));
       agentList.Database = database;
+      operatorLibary.Database = database;
     }
     #endregion
Index: /trunk/sources/HeuristicLab.CEDMA.Core/ConsoleEditor.cs
===================================================================
--- /trunk/sources/HeuristicLab.CEDMA.Core/ConsoleEditor.cs	(revision 416)
+++ /trunk/sources/HeuristicLab.CEDMA.Core/ConsoleEditor.cs	(revision 417)
@@ -27,4 +27,5 @@
 using System.Windows.Forms;
 using System.ServiceModel;
+using HeuristicLab.PluginInfrastructure;
 
 namespace HeuristicLab.CEDMA.Core {
@@ -40,4 +41,6 @@
     private Timer refreshTimer;
     private System.ComponentModel.IContainer components;
+    private Button opLibButton;
+    private Label label1;
     private Console console;
 
@@ -58,4 +61,6 @@
       this.newButton = new System.Windows.Forms.Button();
       this.refreshTimer = new System.Windows.Forms.Timer(this.components);
+      this.opLibButton = new System.Windows.Forms.Button();
+      this.label1 = new System.Windows.Forms.Label();
       this.tabControl.SuspendLayout();
       this.SuspendLayout();
@@ -63,5 +68,5 @@
       // uriTextBox
       // 
-      this.uriTextBox.Location = new System.Drawing.Point(91, 3);
+      this.uriTextBox.Location = new System.Drawing.Point(94, 3);
       this.uriTextBox.Name = "uriTextBox";
       this.uriTextBox.Size = new System.Drawing.Size(205, 20);
@@ -84,8 +89,8 @@
       this.tabControl.Controls.Add(this.agentsPage);
       this.tabControl.Enabled = false;
-      this.tabControl.Location = new System.Drawing.Point(6, 56);
+      this.tabControl.Location = new System.Drawing.Point(6, 85);
       this.tabControl.Name = "tabControl";
       this.tabControl.SelectedIndex = 0;
-      this.tabControl.Size = new System.Drawing.Size(506, 407);
+      this.tabControl.Size = new System.Drawing.Size(506, 378);
       this.tabControl.TabIndex = 2;
       // 
@@ -95,5 +100,5 @@
       this.agentsPage.Name = "agentsPage";
       this.agentsPage.Padding = new System.Windows.Forms.Padding(3);
-      this.agentsPage.Size = new System.Drawing.Size(498, 381);
+      this.agentsPage.Size = new System.Drawing.Size(498, 352);
       this.agentsPage.TabIndex = 1;
       this.agentsPage.Text = "Agents";
@@ -102,5 +107,5 @@
       // connectButton
       // 
-      this.connectButton.Location = new System.Drawing.Point(302, 1);
+      this.connectButton.Location = new System.Drawing.Point(305, 1);
       this.connectButton.Name = "connectButton";
       this.connectButton.Size = new System.Drawing.Size(75, 23);
@@ -114,5 +119,5 @@
       this.comboBox1.Enabled = false;
       this.comboBox1.FormattingEnabled = true;
-      this.comboBox1.Location = new System.Drawing.Point(91, 29);
+      this.comboBox1.Location = new System.Drawing.Point(94, 29);
       this.comboBox1.Name = "comboBox1";
       this.comboBox1.Size = new System.Drawing.Size(121, 21);
@@ -132,5 +137,5 @@
       // 
       this.newButton.Enabled = false;
-      this.newButton.Location = new System.Drawing.Point(218, 27);
+      this.newButton.Location = new System.Drawing.Point(221, 27);
       this.newButton.Name = "newButton";
       this.newButton.Size = new System.Drawing.Size(75, 23);
@@ -144,7 +149,29 @@
       this.refreshTimer.Tick += new System.EventHandler(this.refreshTimer_Tick);
       // 
+      // opLibButton
+      // 
+      this.opLibButton.Enabled = false;
+      this.opLibButton.Location = new System.Drawing.Point(94, 56);
+      this.opLibButton.Name = "opLibButton";
+      this.opLibButton.Size = new System.Drawing.Size(75, 23);
+      this.opLibButton.TabIndex = 7;
+      this.opLibButton.Text = "&Open";
+      this.opLibButton.UseVisualStyleBackColor = true;
+      this.opLibButton.Click += new System.EventHandler(this.opLibButton_Click);
+      // 
+      // label1
+      // 
+      this.label1.AutoSize = true;
+      this.label1.Location = new System.Drawing.Point(3, 61);
+      this.label1.Name = "label1";
+      this.label1.Size = new System.Drawing.Size(85, 13);
+      this.label1.TabIndex = 8;
+      this.label1.Text = "Operator Library:";
+      // 
       // ConsoleEditor
       // 
       this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.Controls.Add(this.label1);
+      this.Controls.Add(this.opLibButton);
       this.Controls.Add(this.newButton);
       this.Controls.Add(this.projectLabel);
@@ -171,4 +198,6 @@
         agentsPage.Controls[0].Dock = DockStyle.Fill;
         refreshTimer.Enabled = true;
+        opLibButton.Enabled = true;
+        opLibButton.Enabled = true;
       } catch(CommunicationException ex) {
         // TASK create helper class for error reporting
@@ -182,4 +211,13 @@
       refreshTimer.Enabled = true;
     }
+
+    private void opLibButton_Click(object sender, EventArgs e) {
+      IOperatorLibrary opLib = console.OperatorLibrary;
+      if(opLib != null) {
+        IView view = opLib.CreateView();
+        if(view != null)
+          PluginManager.ControlManager.ShowControl(view);
+      }
+    }
   }
 }
Index: /trunk/sources/HeuristicLab.CEDMA.Core/DatabaseOperatorLibrary.cs
===================================================================
--- /trunk/sources/HeuristicLab.CEDMA.Core/DatabaseOperatorLibrary.cs	(revision 416)
+++ /trunk/sources/HeuristicLab.CEDMA.Core/DatabaseOperatorLibrary.cs	(revision 417)
@@ -4,4 +4,5 @@
 using System.Text;
 using HeuristicLab.Core;
+using HeuristicLab.CEDMA.DB.Interfaces;
 
 namespace HeuristicLab.CEDMA.Core {
@@ -13,12 +14,53 @@
     }
 
-    private string dbUri;
-
-    public DatabaseOperatorLibrary(string dbUri)
-      : base() {
-      this.dbUri = dbUri;
-      group = new OperatorGroup();
+    private IDatabase database;
+    public IDatabase Database {
+      get { return database; }
+      set { this.database = value; }
     }
 
+    private Dictionary<IOperator, long> knownOperators;
+
+    public DatabaseOperatorLibrary()
+      : base() {
+      group = new OperatorGroup();
+      knownOperators = new Dictionary<IOperator, long>();
+    }
+
+    public void Save() {
+      Dictionary<IOperator, long> newKnownOperators = new Dictionary<IOperator,long>();
+      foreach(IOperator op in group.Operators) {
+        if(knownOperators.ContainsKey(op)) {
+          // update
+          long id =knownOperators[op]; 
+          Database.UpdateOperator(id, op.Name, PersistenceManager.SaveToGZip(op));
+          knownOperators.Remove(op);
+          newKnownOperators.Add(op, id);
+        } else {
+          // create new
+          long id = Database.InsertOperator(op.Name, PersistenceManager.SaveToGZip(op));
+          newKnownOperators.Add(op, id);
+        }
+      }
+      // delete operators from the table that are not present in the group anymore (remaining entries)
+      foreach(long id in knownOperators.Values) {
+        Database.DeleteOperator(id);
+      }
+      
+      knownOperators = newKnownOperators;
+    }
+
+    public void Restore() {
+      foreach(IOperator op in knownOperators.Keys) {
+        group.RemoveOperator(op);
+      }
+      knownOperators.Clear();
+      if(database == null) return;
+      foreach(OperatorEntry e in Database.GetOperators()) {
+        IOperator op = (IOperator)PersistenceManager.RestoreFromGZip(e.RawData);
+        knownOperators.Add(op, e.Id);
+        group.AddOperator(op);
+      }
+    }
 
     public override System.Xml.XmlNode GetXmlNode(string name, System.Xml.XmlDocument document, IDictionary<Guid, IStorable> persistedObjects) {
@@ -35,6 +77,6 @@
 
     public override IView CreateView() {
-      // return new DatabaseOperatorLibraryView(this);
-      return null;
+      Restore();
+      return new DatabaseOperatorLibraryView(this);
     }
   }
Index: /trunk/sources/HeuristicLab.CEDMA.Core/DatabaseOperatorLibraryView.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.CEDMA.Core/DatabaseOperatorLibraryView.Designer.cs	(revision 417)
+++ /trunk/sources/HeuristicLab.CEDMA.Core/DatabaseOperatorLibraryView.Designer.cs	(revision 417)
@@ -0,0 +1,161 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.CEDMA.Core {
+  partial class DatabaseOperatorLibraryView {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (chooseOperatorDialog != null) chooseOperatorDialog.Dispose();
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Component Designer generated code
+
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      this.operatorsGroupBox = new System.Windows.Forms.GroupBox();
+      this.operatorsTreeView = new System.Windows.Forms.TreeView();
+      this.removeButton = new System.Windows.Forms.Button();
+      this.addOperatorButton = new System.Windows.Forms.Button();
+      this.saveButton = new System.Windows.Forms.Button();
+      this.refreshButton = new System.Windows.Forms.Button();
+      this.operatorsGroupBox.SuspendLayout();
+      this.SuspendLayout();
+      // 
+      // operatorsGroupBox
+      // 
+      this.operatorsGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+                  | System.Windows.Forms.AnchorStyles.Left)
+                  | System.Windows.Forms.AnchorStyles.Right)));
+      this.operatorsGroupBox.Controls.Add(this.operatorsTreeView);
+      this.operatorsGroupBox.Enabled = false;
+      this.operatorsGroupBox.Location = new System.Drawing.Point(0, 32);
+      this.operatorsGroupBox.Name = "operatorsGroupBox";
+      this.operatorsGroupBox.Size = new System.Drawing.Size(522, 334);
+      this.operatorsGroupBox.TabIndex = 2;
+      this.operatorsGroupBox.TabStop = false;
+      this.operatorsGroupBox.Text = "&Operators";
+      // 
+      // operatorsTreeView
+      // 
+      this.operatorsTreeView.AllowDrop = true;
+      this.operatorsTreeView.Dock = System.Windows.Forms.DockStyle.Fill;
+      this.operatorsTreeView.HideSelection = false;
+      this.operatorsTreeView.LabelEdit = true;
+      this.operatorsTreeView.Location = new System.Drawing.Point(3, 16);
+      this.operatorsTreeView.Name = "operatorsTreeView";
+      this.operatorsTreeView.ShowNodeToolTips = true;
+      this.operatorsTreeView.Size = new System.Drawing.Size(516, 315);
+      this.operatorsTreeView.TabIndex = 0;
+      this.operatorsTreeView.AfterLabelEdit += new System.Windows.Forms.NodeLabelEditEventHandler(this.operatorsTreeView_AfterLabelEdit);
+      this.operatorsTreeView.DoubleClick += new System.EventHandler(this.operatorsTreeView_DoubleClick);
+      this.operatorsTreeView.DragDrop += new System.Windows.Forms.DragEventHandler(this.operatorsTreeView_DragDrop);
+      this.operatorsTreeView.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.operatorsTreeView_AfterSelect);
+      this.operatorsTreeView.MouseDown += new System.Windows.Forms.MouseEventHandler(this.operatorsTreeView_MouseDown);
+      this.operatorsTreeView.DragEnter += new System.Windows.Forms.DragEventHandler(this.operatorsTreeView_DragEnter);
+      this.operatorsTreeView.KeyDown += new System.Windows.Forms.KeyEventHandler(this.operatorsTreeView_KeyDown);
+      this.operatorsTreeView.ItemDrag += new System.Windows.Forms.ItemDragEventHandler(this.operatorsTreeView_ItemDrag);
+      this.operatorsTreeView.DragOver += new System.Windows.Forms.DragEventHandler(this.operatorsTreeView_DragOver);
+      // 
+      // removeButton
+      // 
+      this.removeButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+      this.removeButton.Enabled = false;
+      this.removeButton.Location = new System.Drawing.Point(113, 372);
+      this.removeButton.Name = "removeButton";
+      this.removeButton.Size = new System.Drawing.Size(104, 23);
+      this.removeButton.TabIndex = 4;
+      this.removeButton.Text = "&Remove";
+      this.removeButton.UseVisualStyleBackColor = true;
+      this.removeButton.Click += new System.EventHandler(this.removeButton_Click);
+      // 
+      // addOperatorButton
+      // 
+      this.addOperatorButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+      this.addOperatorButton.Enabled = false;
+      this.addOperatorButton.Location = new System.Drawing.Point(3, 372);
+      this.addOperatorButton.Name = "addOperatorButton";
+      this.addOperatorButton.Size = new System.Drawing.Size(104, 23);
+      this.addOperatorButton.TabIndex = 3;
+      this.addOperatorButton.Text = "Add &Operator...";
+      this.addOperatorButton.UseVisualStyleBackColor = true;
+      this.addOperatorButton.Click += new System.EventHandler(this.addOperatorButton_Click);
+      // 
+      // saveButton
+      // 
+      this.saveButton.Location = new System.Drawing.Point(6, 3);
+      this.saveButton.Name = "saveButton";
+      this.saveButton.Size = new System.Drawing.Size(104, 23);
+      this.saveButton.TabIndex = 0;
+      this.saveButton.Text = "&Upload";
+      this.saveButton.UseVisualStyleBackColor = true;
+      this.saveButton.Click += new System.EventHandler(this.saveButton_Click);
+      // 
+      // refreshButton
+      // 
+      this.refreshButton.Location = new System.Drawing.Point(113, 3);
+      this.refreshButton.Name = "refreshButton";
+      this.refreshButton.Size = new System.Drawing.Size(104, 23);
+      this.refreshButton.TabIndex = 1;
+      this.refreshButton.Text = "R&efresh";
+      this.refreshButton.UseVisualStyleBackColor = true;
+      this.refreshButton.Click += new System.EventHandler(this.refreshButton_Click);
+      // 
+      // DatabaseOperatorLibraryView
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Controls.Add(this.refreshButton);
+      this.Controls.Add(this.saveButton);
+      this.Controls.Add(this.operatorsGroupBox);
+      this.Controls.Add(this.addOperatorButton);
+      this.Controls.Add(this.removeButton);
+      this.Name = "DatabaseOperatorLibraryView";
+      this.Size = new System.Drawing.Size(522, 395);
+      this.operatorsGroupBox.ResumeLayout(false);
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.GroupBox operatorsGroupBox;
+    private System.Windows.Forms.TreeView operatorsTreeView;
+    private System.Windows.Forms.Button removeButton;
+    private System.Windows.Forms.Button addOperatorButton;
+    private System.Windows.Forms.Button saveButton;
+    private System.Windows.Forms.Button refreshButton;
+  }
+}
Index: /trunk/sources/HeuristicLab.CEDMA.Core/DatabaseOperatorLibraryView.cs
===================================================================
--- /trunk/sources/HeuristicLab.CEDMA.Core/DatabaseOperatorLibraryView.cs	(revision 417)
+++ /trunk/sources/HeuristicLab.CEDMA.Core/DatabaseOperatorLibraryView.cs	(revision 417)
@@ -0,0 +1,255 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Data;
+using System.Text;
+using System.Windows.Forms;
+using HeuristicLab.PluginInfrastructure;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.CEDMA.Core {
+  public partial class DatabaseOperatorLibraryView : ViewBase {
+    private ChooseOperatorDialog chooseOperatorDialog;
+
+    public IOperatorLibrary OperatorLibrary {
+      get { return (IOperatorLibrary)Item; }
+      set { base.Item = value; }
+    }
+
+    public DatabaseOperatorLibraryView() {
+      InitializeComponent();
+      operatorsTreeView.TreeViewNodeSorter = new NodeSorter();
+      Caption = "Operator Library";
+    }
+    public DatabaseOperatorLibraryView(DatabaseOperatorLibrary operatorLibrary)
+      : this() {
+      OperatorLibrary = operatorLibrary;
+    }
+
+    private class NodeSorter : IComparer {
+      public int Compare(object x, object y) {
+        TreeNode tx = x as TreeNode;
+        TreeNode ty = y as TreeNode;
+
+        int result = string.Compare(tx.Text, ty.Text);
+        if (result == 0)
+          result = tx.Index.CompareTo(ty.Index);
+        return result;
+      }
+    }
+
+    protected override void UpdateControls() {
+      base.UpdateControls();
+      operatorsTreeView.Nodes.Clear();
+      addOperatorButton.Enabled = false;
+      removeButton.Enabled = false;
+      if (OperatorLibrary == null) {
+        Caption = "Operator Library";
+        operatorsGroupBox.Enabled = false;
+      } else {
+        Caption = OperatorLibrary.Group.Name + " (" + OperatorLibrary.GetType().Name + ")";
+        operatorsGroupBox.Enabled = true;
+        operatorsTreeView.Nodes.Add(CreateTreeNode(OperatorLibrary.Group));
+        operatorsTreeView.Sort();
+      }
+    }
+
+    private TreeNode CreateTreeNode(IOperatorGroup group) {
+      TreeNode node = new TreeNode();
+      node.Text = group.Name;
+      node.ForeColor = Color.LightGray;
+      node.Tag = group;
+
+      foreach(IOperator op in group.Operators)
+        node.Nodes.Add(CreateTreeNode(op));
+      foreach(IOperatorGroup subGroup in group.SubGroups)
+        node.Nodes.Add(CreateTreeNode(subGroup));
+      return node;
+    }
+    private TreeNode CreateTreeNode(IOperator op) {
+      TreeNode node = new TreeNode();
+      node.Text = op.Name;
+      node.ToolTipText = op.GetType().Name;
+      node.Tag = op;
+      return node;
+    }
+    private void RemoveTreeNode(TreeNode node) {
+      if (node.Tag is IOperatorGroup) {
+        IOperatorGroup group = node.Tag as IOperatorGroup;
+        IOperatorGroup parent = node.Parent.Tag as IOperatorGroup;
+        parent.RemoveSubGroup(group);
+      } else if (node.Tag is IOperator) {
+        IOperator op = node.Tag as IOperator;
+        IOperatorGroup group = node.Parent.Tag as IOperatorGroup;
+        group.RemoveOperator(op);
+      }
+      node.Remove();
+      EnableDisableButtons();
+    }
+
+    private void EnableDisableButtons() {
+      addOperatorButton.Enabled = false;
+      removeButton.Enabled = false;
+      operatorsTreeView.Focus();
+
+      if (operatorsTreeView.SelectedNode != null) {
+        if (operatorsTreeView.SelectedNode.Parent != null)
+          removeButton.Enabled = true;
+        if (operatorsTreeView.SelectedNode.Tag is IOperatorGroup) {
+          addOperatorButton.Enabled = true;
+        }
+      }
+    }
+
+    #region TreeView Events
+    private void operatorsTreeView_AfterSelect(object sender, TreeViewEventArgs e) {
+      EnableDisableButtons();
+    }
+    private void operatorsTreeView_AfterLabelEdit(object sender, NodeLabelEditEventArgs e) {
+      e.CancelEdit = false;
+
+      string name = e.Label;
+      if (name != null) {
+        if (e.Node.Tag is IOperatorGroup)
+          ((IOperatorGroup)e.Node.Tag).Name = name;
+        else if (e.Node.Tag is IOperator)
+          ((IOperator)e.Node.Tag).Name = name;
+      }
+    }
+    private void operatorsTreeView_DoubleClick(object sender, EventArgs e) {
+      if (operatorsTreeView.SelectedNode != null) {
+        IOperator op = operatorsTreeView.SelectedNode.Tag as IOperator;
+        if (op != null) {
+          IView view = op.CreateView();
+          if (view != null)
+            PluginManager.ControlManager.ShowControl(view);
+        }
+      }
+    }
+    #endregion
+
+    #region Button Events
+    private void addOperatorButton_Click(object sender, EventArgs e) {
+      if (chooseOperatorDialog == null) chooseOperatorDialog = new ChooseOperatorDialog();
+      if (chooseOperatorDialog.ShowDialog(this) == DialogResult.OK) {
+        TreeNode node = operatorsTreeView.SelectedNode;
+        IOperatorGroup group = node.Tag as IOperatorGroup;
+        group.AddOperator(chooseOperatorDialog.Operator);
+        node.Nodes.Add(CreateTreeNode(chooseOperatorDialog.Operator));
+        operatorsTreeView.Sort();
+        EnableDisableButtons();
+      }
+    }
+    private void removeButton_Click(object sender, EventArgs e) {
+      TreeNode node = operatorsTreeView.SelectedNode;
+      RemoveTreeNode(node);
+    }
+    #endregion
+
+    #region Key Events
+    private void operatorsTreeView_KeyDown(object sender, KeyEventArgs e) {
+      TreeNode node = operatorsTreeView.SelectedNode;
+      if ((e.KeyCode == Keys.Delete) && (node != null) && (node.Parent != null))
+        RemoveTreeNode(operatorsTreeView.SelectedNode);
+      if ((e.KeyCode == Keys.F2) && (node != null))
+        node.BeginEdit();
+    }
+    #endregion
+
+
+    #region Mouse Events
+    private void operatorsTreeView_MouseDown(object sender, MouseEventArgs e) {
+      if (e.Button != MouseButtons.Right) return;
+      TreeNode clickedNode = operatorsTreeView.GetNodeAt(e.X, e.Y);
+      if (clickedNode != null) {
+        operatorsTreeView.SelectedNode = clickedNode;
+        operatorsTreeView.Refresh();
+      }
+    }
+    #endregion
+
+    #region Drag and Drop Events
+    private void operatorsTreeView_ItemDrag(object sender, ItemDragEventArgs e) {
+      TreeNode node = (TreeNode)e.Item;
+      IOperator op = node.Tag as IOperator;
+      if (op != null) {
+        DataObject data = new DataObject();
+        data.SetData("IOperator", op);
+        data.SetData("DragSource", operatorsTreeView);
+        DoDragDrop(data, DragDropEffects.Copy);
+      }
+    }
+    private void operatorsTreeView_DragEnter(object sender, DragEventArgs e) {
+      e.Effect = DragDropEffects.None;
+      if (e.Data.GetDataPresent("IOperator")) {
+        Point p = operatorsTreeView.PointToClient(new Point(e.X, e.Y));
+        TreeNode node = operatorsTreeView.GetNodeAt(p);
+        if ((node != null) && (node.Tag is IOperatorGroup))
+          e.Effect = DragDropEffects.Copy;
+      }
+    }
+    private void operatorsTreeView_DragOver(object sender, DragEventArgs e) {
+      e.Effect = DragDropEffects.None;
+      if (e.Data.GetDataPresent("IOperator")) {
+        Point p = operatorsTreeView.PointToClient(new Point(e.X, e.Y));
+        TreeNode node = operatorsTreeView.GetNodeAt(p);
+        if ((node != null) && (node.Tag is IOperatorGroup))
+          e.Effect = DragDropEffects.Copy;
+      }
+    }
+    private void operatorsTreeView_DragDrop(object sender, DragEventArgs e) {
+      if (e.Effect != DragDropEffects.None) {
+        if (e.Data.GetDataPresent("IOperator")) {
+          IOperator op = (IOperator)e.Data.GetData("IOperator");
+          Point p = operatorsTreeView.PointToClient(new Point(e.X, e.Y));
+          TreeNode node = operatorsTreeView.GetNodeAt(p);
+          if (node != null) {
+            op = (IOperator)op.Clone();
+
+            while (op.SubOperators.Count > 0)
+              op.RemoveSubOperator(0);
+
+            IOperatorGroup group = (IOperatorGroup)node.Tag;
+            group.AddOperator(op);
+            node.Nodes.Add(CreateTreeNode(op));
+            operatorsTreeView.Sort();
+            EnableDisableButtons();
+          }
+        }
+      }
+    }
+    #endregion
+
+    private void saveButton_Click(object sender, EventArgs e) {
+      ((DatabaseOperatorLibrary)OperatorLibrary).Save();
+    }
+
+    private void refreshButton_Click(object sender, EventArgs e) {
+      ((DatabaseOperatorLibrary)OperatorLibrary).Restore();
+      UpdateControls();
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.CEDMA.Core/DatabaseOperatorLibraryView.resx
===================================================================
--- /trunk/sources/HeuristicLab.CEDMA.Core/DatabaseOperatorLibraryView.resx	(revision 417)
+++ /trunk/sources/HeuristicLab.CEDMA.Core/DatabaseOperatorLibraryView.resx	(revision 417)
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
Index: /trunk/sources/HeuristicLab.CEDMA.Core/HeuristicLab.CEDMA.Core.csproj
===================================================================
--- /trunk/sources/HeuristicLab.CEDMA.Core/HeuristicLab.CEDMA.Core.csproj	(revision 416)
+++ /trunk/sources/HeuristicLab.CEDMA.Core/HeuristicLab.CEDMA.Core.csproj	(revision 417)
@@ -63,4 +63,10 @@
     </Compile>
     <Compile Include="DatabaseOperatorLibrary.cs" />
+    <Compile Include="DatabaseOperatorLibraryView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="DatabaseOperatorLibraryView.Designer.cs">
+      <DependentUpon>DatabaseOperatorLibraryView.cs</DependentUpon>
+    </Compile>
     <Compile Include="Result.cs" />
     <Compile Include="IResult.cs" />
@@ -113,4 +119,8 @@
       <SubType>Designer</SubType>
     </EmbeddedResource>
+    <EmbeddedResource Include="DatabaseOperatorLibraryView.resx">
+      <DependentUpon>DatabaseOperatorLibraryView.cs</DependentUpon>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
Index: /trunk/sources/HeuristicLab.CEDMA.DB.Interfaces/IDatabase.cs
===================================================================
--- /trunk/sources/HeuristicLab.CEDMA.DB.Interfaces/IDatabase.cs	(revision 416)
+++ /trunk/sources/HeuristicLab.CEDMA.DB.Interfaces/IDatabase.cs	(revision 417)
@@ -49,5 +49,11 @@
 
     [OperationContract]
-    long InsertOperator(string name, string rawData);
+    long InsertOperator(string name, byte[] rawData);
+
+    [OperationContract]
+    void UpdateOperator(long id, string name, byte[] rawData);
+
+    [OperationContract]
+    void DeleteOperator(long id);
 
     // should be replaced by more powerful querying interface (LINQ provider?)
Index: /trunk/sources/HeuristicLab.CEDMA.DB.Interfaces/OperatorEntry.cs
===================================================================
--- /trunk/sources/HeuristicLab.CEDMA.DB.Interfaces/OperatorEntry.cs	(revision 416)
+++ /trunk/sources/HeuristicLab.CEDMA.DB.Interfaces/OperatorEntry.cs	(revision 417)
@@ -35,5 +35,5 @@
     public string Name { get; set; }
     [DataMember]
-    public string RawData { get; set; }
+    public byte[] RawData { get; set; }
   }
 }
Index: /trunk/sources/HeuristicLab.CEDMA.DB/Database.cs
===================================================================
--- /trunk/sources/HeuristicLab.CEDMA.DB/Database.cs	(revision 416)
+++ /trunk/sources/HeuristicLab.CEDMA.DB/Database.cs	(revision 417)
@@ -65,5 +65,5 @@
             }
             using(DbCommand cmd = cnn.CreateCommand()) {
-              cmd.CommandText = "CREATE TABLE Operator (ID integer primary key autoincrement, Name text, RawData text)";
+              cmd.CommandText = "CREATE TABLE Operator (ID integer primary key autoincrement, Name text, RawData Blob)";
               cmd.Transaction = t;
               cmd.ExecuteNonQuery();
@@ -200,5 +200,5 @@
     }
 
-    public long InsertOperator(string name, string rawData) {
+    public long InsertOperator(string name, byte[] rawData) {
       rwLock.EnterWriteLock();
       try {
@@ -230,5 +230,5 @@
     #endregion
 
-    #region update agent/run
+    #region update agent, run, operator
     public void UpdateAgent(long id, string name) {
       rwLock.EnterWriteLock();
@@ -312,7 +312,38 @@
     }
 
+    public void UpdateOperator(long id, string name, byte[] rawData) {
+      rwLock.EnterWriteLock();
+      try {
+        using(SQLiteConnection cnn = new SQLiteConnection(connectionString)) {
+          cnn.Open();
+          using(SQLiteTransaction t = cnn.BeginTransaction()) {
+            using(SQLiteCommand c = cnn.CreateCommand()) {
+              c.Transaction = t;
+              c.CommandText = "Update Operator set Name=@Name, RawData=@RawData where id=@Id";
+              DbParameter rawDataParam = c.CreateParameter();
+              DbParameter nameParam = c.CreateParameter();
+              DbParameter idParam = c.CreateParameter();
+              rawDataParam.ParameterName = "@RawData";
+              rawDataParam.Value = rawData;
+              idParam.ParameterName = "@Id";
+              idParam.Value = id;
+              nameParam.ParameterName = "@Name";
+              nameParam.Value = name;
+              c.Parameters.Add(rawDataParam);
+              c.Parameters.Add(nameParam);
+              c.Parameters.Add(idParam);
+              c.ExecuteNonQuery();
+            }
+            t.Commit();
+          }
+        }
+      } finally {
+        rwLock.ExitWriteLock();
+      }
+    }
+
     #endregion
 
-    #region get agent/result/sub-result
+    #region get agent/result/sub-result/operator
 
     public ICollection<AgentEntry> GetAgents(ProcessStatus status) {
@@ -481,5 +512,5 @@
                 op.Id = r.GetInt32(0);
                 op.Name = r.IsDBNull(1) ? "-" : r.GetString(1);
-                op.RawData = r.GetString(2);
+                op.RawData = (byte[])r.GetValue(2);
                 operators.Add(op);
               }
@@ -491,4 +522,29 @@
       }
       return operators;
+    }
+    #endregion
+
+    #region delete operator
+    public void DeleteOperator(long id) {
+      rwLock.EnterWriteLock();
+      try {
+        using(DbConnection cnn = new SQLiteConnection(connectionString)) {
+          cnn.Open();
+          using(DbTransaction t = cnn.BeginTransaction()) {
+            using(DbCommand c = cnn.CreateCommand()) {
+              c.Transaction = t;
+              c.CommandText = "Delete from Operator where id=@Id";
+              DbParameter idParam = c.CreateParameter();
+              idParam.ParameterName = "@Id";
+              idParam.Value = id;
+              c.Parameters.Add(idParam);
+              c.ExecuteNonQuery();
+            }
+            t.Commit();
+          }
+        }
+      } finally {
+        rwLock.ExitWriteLock();
+      }
     }
     #endregion
