Configurable list of external URLs for each object (issue #NX-1213)
authorVictor Kirhenshtein <victor@netxms.org>
Fri, 10 Mar 2017 18:11:55 +0000 (20:11 +0200)
committerVictor Kirhenshtein <victor@netxms.org>
Fri, 10 Mar 2017 18:11:55 +0000 (20:11 +0200)
33 files changed:
ChangeLog
include/netxmsdb.h
include/nms_cscp.h
sql/schema.in
src/java/client/netxms-base/src/main/java/org/netxms/base/NXCPCodes.java
src/java/client/netxms-client/src/main/java/org/netxms/client/NXCObjectModificationData.java
src/java/client/netxms-client/src/main/java/org/netxms/client/NXCSession.java
src/java/client/netxms-client/src/main/java/org/netxms/client/ObjectUrl.java [new file with mode: 0644]
src/java/client/netxms-client/src/main/java/org/netxms/client/objects/AbstractObject.java
src/java/netxms-eclipse/ObjectManager/META-INF/MANIFEST.MF
src/java/netxms-eclipse/ObjectManager/plugin.xml
src/java/netxms-eclipse/ObjectManager/src/org/netxms/ui/eclipse/objectmanager/dialogs/AttributeEditDialog.java
src/java/netxms-eclipse/ObjectManager/src/org/netxms/ui/eclipse/objectmanager/dialogs/ObjectUrlEditDialog.java [copied from src/java/netxms-eclipse/ObjectManager/src/org/netxms/ui/eclipse/objectmanager/dialogs/AttributeEditDialog.java with 50% similarity]
src/java/netxms-eclipse/ObjectManager/src/org/netxms/ui/eclipse/objectmanager/propertypages/CustomAttributes.java
src/java/netxms-eclipse/ObjectManager/src/org/netxms/ui/eclipse/objectmanager/propertypages/ExternalResources.java [copied from src/java/netxms-eclipse/ObjectManager/src/org/netxms/ui/eclipse/objectmanager/propertypages/CustomAttributes.java with 57% similarity]
src/java/netxms-eclipse/ObjectManager/src/org/netxms/ui/eclipse/objectmanager/propertypages/helpers/UrlListLabelProvider.java [new file with mode: 0644]
src/java/netxms-eclipse/ObjectView/META-INF/MANIFEST.MF
src/java/netxms-eclipse/ObjectView/src/org/netxms/ui/eclipse/objectview/objecttabs/ObjectOverview.java
src/java/netxms-eclipse/ObjectView/src/org/netxms/ui/eclipse/objectview/objecttabs/elements/ExternalResources.java [new file with mode: 0644]
src/server/core/netobj.cpp
src/server/core/tools.cpp
src/server/include/nms_objects.h
src/server/tools/nxdbmgr/upgrade.cpp
webui/webapp/ObjectManager/META-INF/MANIFEST.MF
webui/webapp/ObjectManager/plugin.xml
webui/webapp/ObjectManager/src/org/netxms/ui/eclipse/objectmanager/dialogs/AttributeEditDialog.java
webui/webapp/ObjectManager/src/org/netxms/ui/eclipse/objectmanager/dialogs/ObjectUrlEditDialog.java [copied from src/java/netxms-eclipse/ObjectManager/src/org/netxms/ui/eclipse/objectmanager/dialogs/AttributeEditDialog.java with 50% similarity]
webui/webapp/ObjectManager/src/org/netxms/ui/eclipse/objectmanager/propertypages/CustomAttributes.java
webui/webapp/ObjectManager/src/org/netxms/ui/eclipse/objectmanager/propertypages/ExternalResources.java [copied from src/java/netxms-eclipse/ObjectManager/src/org/netxms/ui/eclipse/objectmanager/propertypages/CustomAttributes.java with 57% similarity]
webui/webapp/ObjectManager/src/org/netxms/ui/eclipse/objectmanager/propertypages/helpers/UrlListLabelProvider.java [new file with mode: 0644]
webui/webapp/ObjectView/META-INF/MANIFEST.MF
webui/webapp/ObjectView/src/org/netxms/ui/eclipse/objectview/objecttabs/ObjectOverview.java
webui/webapp/ObjectView/src/org/netxms/ui/eclipse/objectview/objecttabs/elements/ExternalResources.java [new file with mode: 0644]

index b84acf0..101d850 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -25,7 +25,8 @@
        - DCIs created from templates made visually distinguishable in data collection editor
        - "Inverted" flag ignored in event processing policy if event or object list is empty
        - Object tools can be filtered by custom attribute presence
-- Fixed issues: NX-60, NX-630, NX-916, NX-1123, NX-1129, NX-1151, NX-1161, NX-1165, NX-1171, NX-1174, NX-1178, NX-1188, NX-1190, NX-1191, NX-1192, NX-1193, NX-1197, NX-1198, NX-1216
+       - Configurable list of external URLs for each object
+- Fixed issues: NX-60, NX-630, NX-916, NX-1123, NX-1129, NX-1151, NX-1161, NX-1165, NX-1171, NX-1174, NX-1178, NX-1188, NX-1190, NX-1191, NX-1192, NX-1193, NX-1197, NX-1198, NX-1213, NX-1216
 
 
 *
index 6827bd3..3439dde 100644 (file)
@@ -23,6 +23,6 @@
 #ifndef _netxmsdb_h
 #define _netxmsdb_h
 
-#define DB_FORMAT_VERSION   441
+#define DB_FORMAT_VERSION   442
 
 #endif
index 670b858..ea81edf 100644 (file)
@@ -1173,6 +1173,7 @@ typedef struct
 #define VID_TRAP_TYPE               ((UINT32)572)
 #define VID_IS_ACTIVE               ((UINT32)573)
 #define VID_CHANNEL_ID              ((UINT32)574)
+#define VID_NUM_URLS                ((UINT32)575)
 
 // Base variabe for single threshold in message
 #define VID_THRESHOLD_BASE          ((UINT32)0x00800000)
@@ -1205,15 +1206,6 @@ typedef struct
 
 // Variable range for trap parameter list
 #define VID_TRAP_PBASE              ((UINT32)0x00009000)
-/* Unused
-#define VID_TRAP_PLEN_LAST          ((UINT32)0x000093FF)
-#define VID_TRAP_PNAME_BASE         ((UINT32)0x00009400)
-#define VID_TRAP_PNAME_LAST         ((UINT32)0x000097FF)
-#define VID_TRAP_PDESCR_BASE        ((UINT32)0x00009800)
-#define VID_TRAP_PDESCR_LAST        ((UINT32)0x00009BFF)
-#define VID_TRAP_PFLAGS_BASE        ((UINT32)0x00009C00)
-#define VID_TRAP_PFLAGS_LAST        ((UINT32)0x00009FFF)
-*/
 
 // Object information can contain variable number of parent and child objects' ids.
 // Because each variable in message have to have unique identifier,
@@ -1235,6 +1227,9 @@ typedef struct
 // Base value for tooltip DCI list
 #define VID_TOOLTIP_DCI_LIST_BASE   ((UINT32)0x73000000)
 
+// Base value for URL list
+#define VID_URL_LIST_BASE           ((UINT32)0x74000000)
+
 // IP address list base
 #define VID_IP_ADDRESS_LIST_BASE    ((UINT32)0x7F000000)
 
index b24abc7..80373ec 100644 (file)
@@ -177,6 +177,18 @@ CREATE TABLE object_properties
   PRIMARY KEY(object_id)
 ) TABLE_TYPE;
 
+/**
+ * Object URLs
+ */
+CREATE TABLE object_urls
+(
+  object_id integer not null,
+  url_id integer not null,
+  url varchar(2000) null,
+  description varchar(2000) null,
+  PRIMARY KEY(object_id,url_id)
+) TABLE_TYPE;
+
 /*
 ** Object custom attributes
 */
index a1b6111..bd74982 100644 (file)
@@ -955,6 +955,10 @@ public class NXCPCodes
    public static final long VID_HOSTNAME = 569;
    public static final long VID_ENABLE_COMPRESSION = 570;
    public static final long VID_AGENT_COMPRESSION_MODE = 571;
+   public static final long VID_TRAP_TYPE = 572;
+   public static final long VID_IS_ACTIVE = 573;
+   public static final long VID_CHANNEL_ID = 574;
+   public static final long VID_NUM_URLS = 575;
 
        public static final long VID_ACL_USER_BASE = 0x00001000L;
        public static final long VID_ACL_USER_LAST = 0x00001FFFL;
@@ -969,15 +973,6 @@ public class NXCPCodes
        public static final long VID_EVENT_ARG_BASE = 0x00008000L;
        public static final long VID_EVENT_ARG_LAST = 0x00008FFFL;
        public static final long VID_TRAP_PBASE = 0x00009000L;
-       /* Unused
-       public static final long VID_TRAP_PLEN_LAST = 0x000093FFL;
-       public static final long VID_TRAP_PNAME_BASE = 0x00009400L;
-       public static final long VID_TRAP_PNAME_LAST = 0x000097FFL;
-       public static final long VID_TRAP_PDESCR_BASE = 0x00009800L;
-       public static final long VID_TRAP_PDESCR_LAST = 0x00009BFFL;
-       public static final long VID_TRAP_PFLAGS_BASE = 0x00009C00L;
-       public static final long VID_TRAP_PFLAGS_LAST = 0x00009FFFL;
-       */
        public static final long VID_PARENT_ID_BASE = 0x00003000L;
        public static final long VID_PARENT_ID_LAST = 0x00003FFFL;
        public static final long VID_CHILD_ID_BASE = 0x80000000L;
@@ -986,6 +981,7 @@ public class NXCPCodes
    public static final long VID_MODULE_DATA_BASE = 0x71000000L;
    public static final long VID_OVERVIEW_DCI_LIST_BASE = 0x72000000L;
    public static final long VID_TOOLTIP_DCI_LIST_BASE = 0x73000000L;
+   public static final long VID_URL_LIST_BASE = 0x74000000L;
        public static final long VID_RESOURCE_LIST_BASE = 0x20000000L;
        public static final long VID_IP_ADDRESS_LIST_BASE = 0x7F000000L;
    public static final long VID_SYNC_SUBNETS_BASE = 0x28000000L;
index ea7f7f5..b30e8c8 100644 (file)
@@ -117,6 +117,7 @@ public class NXCObjectModificationData
    public static final int SSH_PASSWORD           = 66;
    public static final int ZONE_PROXY             = 67;
    public static final int AGENT_COMPRESSION_MODE = 68;
+   public static final int URL_LIST               = 69;
        
        private Set<Integer> fieldSet;
        private long objectId;
@@ -209,6 +210,7 @@ public class NXCObjectModificationData
        private String sshLogin;
        private String sshPassword;
        private long zoneProxy;
+       private List<ObjectUrl> urls;
        
        /**
         * Constructor for creating modification data for given object
@@ -1736,4 +1738,23 @@ public class NXCObjectModificationData
       this.zoneProxy = zoneProxy;
       fieldSet.add(ZONE_PROXY);
    }
+
+   /**
+    * @return urls
+    */
+   public List<ObjectUrl> getUrls()
+   {
+      return urls;
+   }
+
+   /**
+    * Set URL list
+    * 
+    * @param urls new URL list
+    */
+   public void setUrls(List<ObjectUrl> urls)
+   {
+      this.urls = urls;
+      fieldSet.add(URL_LIST);
+   }
 }
index a37f09a..af1d782 100644 (file)
@@ -4631,6 +4631,17 @@ public class NXCSession
          }
       }
 
+      if (data.isFieldSet(NXCObjectModificationData.URL_LIST))
+      {
+         msg.setFieldInt32(NXCPCodes.VID_NUM_URLS, data.getUrls().size());
+         long fieldId = NXCPCodes.VID_URL_LIST_BASE;
+         for(ObjectUrl u : data.getUrls())
+         {
+            u.fillMessage(msg, fieldId);
+            fieldId += 10;
+         }
+      }
+
       if (data.isFieldSet(NXCObjectModificationData.SCRIPT))
       {
          msg.setField(NXCPCodes.VID_SCRIPT, data.getScript());
diff --git a/src/java/client/netxms-client/src/main/java/org/netxms/client/ObjectUrl.java b/src/java/client/netxms-client/src/main/java/org/netxms/client/ObjectUrl.java
new file mode 100644 (file)
index 0000000..4ce48a7
--- /dev/null
@@ -0,0 +1,86 @@
+/**
+ * 
+ */
+package org.netxms.client;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import org.netxms.base.NXCPMessage;
+
+/**
+ * URL associated with object
+ */
+public class ObjectUrl
+{
+   private int id;
+   private URL url;
+   private String description;
+   
+   /**
+    * Create from NXCP message
+    */
+   public ObjectUrl(NXCPMessage msg, long baseId)
+   {
+      id = msg.getFieldAsInt32(baseId);
+      try
+      {
+         url = new URL(msg.getFieldAsString(baseId + 1));
+      }
+      catch(MalformedURLException e)
+      {
+         url = null;
+      }
+      description = msg.getFieldAsString(baseId + 2);
+   }
+
+   /**
+    * Create new object URL
+    * 
+    * @param id
+    * @param url
+    * @param description
+    */
+   public ObjectUrl(int id, URL url, String description)
+   {
+      this.id = id;
+      this.url = url;
+      this.description = description;
+   }
+
+   /**
+    * Fill NXCP message
+    * 
+    * @param msg NXCP message
+    * @param baseId base field ID
+    */
+   public void fillMessage(NXCPMessage msg, long baseId)
+   {
+      msg.setFieldInt32(baseId, id);
+      msg.setField(baseId + 1, (url != null) ? url.toExternalForm() : "");
+      msg.setField(baseId + 2, description);
+   }
+   
+   /**
+    * @return the id
+    */
+   public int getId()
+   {
+      return id;
+   }
+
+   /**
+    * @return the url
+    */
+   public URL getUrl()
+   {
+      return url;
+   }
+
+   /**
+    * @return the description
+    */
+   public String getDescription()
+   {
+      return description;
+   }
+}
index 9a70887..f847169 100644 (file)
@@ -37,6 +37,7 @@ import org.netxms.base.annotations.Internal;
 import org.netxms.client.AccessListElement;
 import org.netxms.client.ModuleDataProvider;
 import org.netxms.client.NXCSession;
+import org.netxms.client.ObjectUrl;
 import org.netxms.client.constants.ObjectStatus;
 import org.netxms.client.services.ServiceManager;
 
@@ -140,6 +141,7 @@ public abstract class AbstractObject
        protected final HashSet<Long> children = new HashSet<Long>(0);
        protected final List<Long> dashboards = new ArrayList<Long>(0);
        protected final Map<String, String> customAttributes = new HashMap<String, String>(0);
+       protected final List<ObjectUrl> urls = new ArrayList<ObjectUrl>(0);
        protected Map<String, Object> moduleData = null;
        
        @Internal private int effectiveRights = 0;
@@ -262,6 +264,13 @@ public abstract class AbstractObject
                        customAttributes.put(msg.getFieldAsString(id), msg.getFieldAsString(id + 1));
                }
                
+               // URLs
+      count = msg.getFieldAsInt32(NXCPCodes.VID_NUM_URLS);
+      for(i = 0, id = NXCPCodes.VID_URL_LIST_BASE; i < count; i++, id += 10)
+      {
+         urls.add(new ObjectUrl(msg, id));
+      }
+      
                // Access list
                inheritAccessRights = msg.getFieldAsBoolean(NXCPCodes.VID_INHERIT_RIGHTS);
                count = msg.getFieldAsInt32(NXCPCodes.VID_ACL_SIZE);
@@ -334,6 +343,26 @@ public abstract class AbstractObject
        {
                return accessList.toArray(new AccessListElement[accessList.size()]);
        }
+       
+       /**
+        * Get associated URLs
+        * 
+        * @return associated URLs
+        */
+       public List<ObjectUrl> getUrls()
+       {
+          return new ArrayList<ObjectUrl>(urls);
+       }
+       
+       /**
+        * Check if object has associated URLs 
+        * 
+        * @return true if object has associated URLs
+        */
+       public boolean hasUrls()
+       {
+          return !urls.isEmpty();
+       }
 
        /**
         * @return the comments
index 3867943..10c39eb 100644 (file)
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: NXMC Basic Object Management Plug-in
 Bundle-SymbolicName: org.netxms.ui.eclipse.objectmanager;singleton:=true
-Bundle-Version: 2.1.2
+Bundle-Version: 2.1.3
 Bundle-Activator: org.netxms.ui.eclipse.objectmanager.Activator
 Bundle-Vendor: netxms.org
 Require-Bundle: org.eclipse.ui;bundle-version="3.8.2",
index bcfd591..a913715 100644 (file)
               </instanceof>
            </enabledWhen>
         </page>
+        <page
+              class="org.netxms.ui.eclipse.objectmanager.propertypages.ExternalResources"
+              id="org.netxms.ui.eclipse.objectmanager.propertypages.ExternalResources"
+              name="External Resources">
+           <enabledWhen>
+              <instanceof
+                    value="org.netxms.client.objects.AbstractObject">
+              </instanceof>
+           </enabledWhen>
+        </page>
   </extension>
 
    <extension
index 1975b9c..a30ba21 100644 (file)
@@ -20,35 +20,33 @@ package org.netxms.ui.eclipse.objectmanager.dialogs;
 
 import org.eclipse.jface.dialogs.Dialog;
 import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
 import org.netxms.ui.eclipse.objectmanager.Messages;
 import org.netxms.ui.eclipse.tools.WidgetHelper;
-
+import org.netxms.ui.eclipse.widgets.LabeledText;
 
 /**
  * Object's custom attribute edit dialog
- *
  */
 public class AttributeEditDialog extends Dialog
 {
-       private Text textName;
-       private Text textValue;
-       private String attrName;
-       private String attrValue;
+       private LabeledText textName;
+       private LabeledText textValue;
+       private String name;
+       private String value;
        
        /**
         * @param parentShell
         */
-       public AttributeEditDialog(Shell parentShell, String attrName, String attrValue)
+       public AttributeEditDialog(Shell parentShell, String name, String value)
        {
                super(parentShell);
-               this.attrName = attrName;
-               this.attrValue = attrValue;
+               this.name = name;
+               this.value = value;
        }
 
        /* (non-Javadoc)
@@ -59,36 +57,35 @@ public class AttributeEditDialog extends Dialog
        {
                Composite dialogArea = (Composite)super.createDialogArea(parent);
                
-               FillLayout layout = new FillLayout();
-      layout.type = SWT.VERTICAL;
-      layout.marginWidth = WidgetHelper.DIALOG_WIDTH_MARGIN;
+               GridLayout layout = new GridLayout();
       layout.marginHeight = WidgetHelper.DIALOG_HEIGHT_MARGIN;
       dialogArea.setLayout(layout);
                
-      Label label = new Label(dialogArea, SWT.NONE);
-      label.setText(Messages.get().AttributeEditDialog_Name);
-      
-      textName = new Text(dialogArea, SWT.SINGLE | SWT.BORDER);
-      textName.setTextLimit(63);
-      if (attrName != null)
+      textName = new LabeledText(dialogArea, SWT.NONE);
+      textName.setLabel(Messages.get().AttributeEditDialog_Name);
+      textName.getTextControl().setTextLimit(63);
+      if (name != null)
       {
-       textName.setText(attrName);
+       textName.setText(name);
        textName.setEditable(false);
       }
+      GridData gd = new GridData();
+      gd.horizontalAlignment = SWT.FILL;
+      gd.grabExcessHorizontalSpace = true;
+      textName.setLayoutData(gd);
       
-      label = new Label(dialogArea, SWT.NONE);
-      label.setText(""); //$NON-NLS-1$
-
-      label = new Label(dialogArea, SWT.NONE);
-      label.setText(Messages.get().AttributeEditDialog_Value);
-
-      textValue = new Text(dialogArea, SWT.SINGLE | SWT.BORDER);
-      textValue.setTextLimit(255);
-      textValue.getShell().setMinimumSize(300, 0);
-      if (attrValue != null)
-       textValue.setText(attrValue);
+      textValue = new LabeledText(dialogArea, SWT.NONE);
+      textValue.setLabel(Messages.get().AttributeEditDialog_Value);
+      textValue.getTextControl().setTextLimit(255);
+      if (value != null)
+       textValue.setText(value);
+      gd = new GridData();
+      gd.horizontalAlignment = SWT.FILL;
+      gd.grabExcessHorizontalSpace = true;
+      gd.widthHint = 300;
+      textValue.setLayoutData(gd);
       
-      if (attrName != null)
+      if (name != null)
        textValue.setFocus();
       
                return dialogArea;
@@ -101,29 +98,24 @@ public class AttributeEditDialog extends Dialog
        protected void configureShell(Shell newShell)
        {
                super.configureShell(newShell);
-               newShell.setText((attrName == null) ? Messages.get().AttributeEditDialog_AddAttr : Messages.get().AttributeEditDialog_ModifyAttr);
+               newShell.setText((name == null) ? Messages.get().AttributeEditDialog_AddAttr : Messages.get().AttributeEditDialog_ModifyAttr);
        }
        
-       
        /**
         * Get variable name
-        * 
         */
-       public String getAttrName()
+       public String getName()
        {
-               return attrName;
+               return name;
        }
        
-       
        /**
         * Get variable value
-        * 
         */
-       public String getAttrValue()
+       public String getValue()
        {
-               return attrValue;
+               return value;
        }
-
        
        /* (non-Javadoc)
         * @see org.eclipse.jface.dialogs.Dialog#okPressed()
@@ -131,8 +123,8 @@ public class AttributeEditDialog extends Dialog
        @Override
        protected void okPressed()
        {
-               attrName = textName.getText();
-               attrValue = textValue.getText();
+               name = textName.getText().trim();
+               value = textValue.getText();
                super.okPressed();
        }
 }
@@ -1,6 +1,6 @@
 /**
  * NetXMS - open source network management system
- * Copyright (C) 2003-2013 Victor Kirhenshtein
+ * Copyright (C) 2003-2017 Victor Kirhenshtein
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  */
 package org.netxms.ui.eclipse.objectmanager.dialogs;
 
+import java.net.MalformedURLException;
+import java.net.URL;
 import org.eclipse.jface.dialogs.Dialog;
 import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
-import org.netxms.ui.eclipse.objectmanager.Messages;
+import org.netxms.ui.eclipse.tools.MessageDialogHelper;
 import org.netxms.ui.eclipse.tools.WidgetHelper;
-
+import org.netxms.ui.eclipse.widgets.LabeledText;
 
 /**
- * Object's custom attribute edit dialog
- *
+ * Object's associated URL edit dialog
  */
-public class AttributeEditDialog extends Dialog
+public class ObjectUrlEditDialog extends Dialog
 {
-       private Text textName;
-       private Text textValue;
-       private String attrName;
-       private String attrValue;
+       private LabeledText textUrl;
+       private LabeledText textDescription;
+       private URL url;
+       private String description;
        
        /**
         * @param parentShell
         */
-       public AttributeEditDialog(Shell parentShell, String attrName, String attrValue)
+       public ObjectUrlEditDialog(Shell parentShell, URL url, String description)
        {
                super(parentShell);
-               this.attrName = attrName;
-               this.attrValue = attrValue;
+               this.url = url;
+               this.description = description;
        }
 
        /* (non-Javadoc)
@@ -59,37 +59,30 @@ public class AttributeEditDialog extends Dialog
        {
                Composite dialogArea = (Composite)super.createDialogArea(parent);
                
-               FillLayout layout = new FillLayout();
-      layout.type = SWT.VERTICAL;
-      layout.marginWidth = WidgetHelper.DIALOG_WIDTH_MARGIN;
+               GridLayout layout = new GridLayout();
       layout.marginHeight = WidgetHelper.DIALOG_HEIGHT_MARGIN;
       dialogArea.setLayout(layout);
                
-      Label label = new Label(dialogArea, SWT.NONE);
-      label.setText(Messages.get().AttributeEditDialog_Name);
-      
-      textName = new Text(dialogArea, SWT.SINGLE | SWT.BORDER);
-      textName.setTextLimit(63);
-      if (attrName != null)
-      {
-       textName.setText(attrName);
-       textName.setEditable(false);
-      }
-      
-      label = new Label(dialogArea, SWT.NONE);
-      label.setText(""); //$NON-NLS-1$
-
-      label = new Label(dialogArea, SWT.NONE);
-      label.setText(Messages.get().AttributeEditDialog_Value);
-
-      textValue = new Text(dialogArea, SWT.SINGLE | SWT.BORDER);
-      textValue.setTextLimit(255);
-      textValue.getShell().setMinimumSize(300, 0);
-      if (attrValue != null)
-       textValue.setText(attrValue);
+      textUrl = new LabeledText(dialogArea, SWT.NONE);
+      textUrl.setLabel("URL");
+      textUrl.getTextControl().setTextLimit(2000);
+      if (url != null)
+       textUrl.setText(url.toExternalForm());
+      GridData gd = new GridData();
+      gd.horizontalAlignment = SWT.FILL;
+      gd.grabExcessHorizontalSpace = true;
+      textUrl.setLayoutData(gd);
       
-      if (attrName != null)
-       textValue.setFocus();
+      textDescription = new LabeledText(dialogArea, SWT.NONE);
+      textDescription.setLabel("Description");
+      textDescription.getTextControl().setTextLimit(2000);
+      if (description != null)
+       textDescription.setText(description);
+      gd = new GridData();
+      gd.horizontalAlignment = SWT.FILL;
+      gd.grabExcessHorizontalSpace = true;
+      gd.widthHint = 500;
+      textDescription.setLayoutData(gd);
       
                return dialogArea;
        }
@@ -101,29 +94,24 @@ public class AttributeEditDialog extends Dialog
        protected void configureShell(Shell newShell)
        {
                super.configureShell(newShell);
-               newShell.setText((attrName == null) ? Messages.get().AttributeEditDialog_AddAttr : Messages.get().AttributeEditDialog_ModifyAttr);
+               newShell.setText((url == null) ? "Create URL" : "Edit URL");
        }
        
-       
        /**
-        * Get variable name
-        * 
+        * Get URL
         */
-       public String getAttrName()
+       public URL getUrl()
        {
-               return attrName;
+               return url;
        }
        
-       
        /**
-        * Get variable value
-        * 
+        * Get description
         */
-       public String getAttrValue()
+       public String getDescription()
        {
-               return attrValue;
+               return description;
        }
-
        
        /* (non-Javadoc)
         * @see org.eclipse.jface.dialogs.Dialog#okPressed()
@@ -131,8 +119,16 @@ public class AttributeEditDialog extends Dialog
        @Override
        protected void okPressed()
        {
-               attrName = textName.getText();
-               attrValue = textValue.getText();
+               try
+      {
+         url = new URL(textUrl.getText().trim());
+      }
+      catch(MalformedURLException e)
+      {
+         MessageDialogHelper.openWarning(getShell(), "Warning", "Entered URL is invalid. Please enter valid URL.");
+         return;
+      }
+               description = textDescription.getText();
                super.okPressed();
        }
 }
index 2f5d69b..68dab47 100644 (file)
@@ -153,14 +153,14 @@ public class CustomAttributes extends PropertyPage
                                final AttributeEditDialog dlg = new AttributeEditDialog(CustomAttributes.this.getShell(), null, null);
                                if (dlg.open() == Window.OK)
                                {
-                                       if (attributes.containsKey(dlg.getAttrName()))
+                                       if (attributes.containsKey(dlg.getName()))
                                        {
                                                MessageDialogHelper.openWarning(CustomAttributes.this.getShell(), Messages.get().CustomAttributes_Warning, 
-                                                     String.format(Messages.get().CustomAttributes_WarningAlreadyExist, dlg.getAttrName()));
+                                                     String.format(Messages.get().CustomAttributes_WarningAlreadyExist, dlg.getName()));
                                        }
                                        else
                                        {
-                                               attributes.put(dlg.getAttrName(), dlg.getAttrValue());
+                                               attributes.put(dlg.getName(), dlg.getValue());
                                      viewer.setInput(attributes.entrySet());
                                      CustomAttributes.this.isModified = true;
                                        }
@@ -191,7 +191,7 @@ public class CustomAttributes extends PropertyPage
                                        final AttributeEditDialog dlg = new AttributeEditDialog(CustomAttributes.this.getShell(), element.getKey(), element.getValue());
                                        if (dlg.open() == Window.OK)
                                        {
-                                               attributes.put(dlg.getAttrName(), dlg.getAttrValue());
+                                               attributes.put(dlg.getName(), dlg.getValue());
                                      viewer.setInput(attributes.entrySet());
                                      CustomAttributes.this.isModified = true;
                                        }
  */
 package org.netxms.ui.eclipse.objectmanager.propertypages;
 
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Map.Entry;
+import java.util.ArrayList;
+import java.util.List;
 import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.Platform;
 import org.eclipse.jface.viewers.ArrayContentProvider;
 import org.eclipse.jface.viewers.DoubleClickEvent;
 import org.eclipse.jface.viewers.IDoubleClickListener;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
 import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.jface.viewers.SelectionChangedEvent;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.jface.window.Window;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.SelectionEvent;
@@ -47,33 +43,34 @@ import org.eclipse.swt.widgets.Event;
 import org.eclipse.ui.dialogs.PropertyPage;
 import org.netxms.client.NXCObjectModificationData;
 import org.netxms.client.NXCSession;
+import org.netxms.client.ObjectUrl;
 import org.netxms.client.objects.AbstractObject;
 import org.netxms.ui.eclipse.jobs.ConsoleJob;
 import org.netxms.ui.eclipse.objectmanager.Activator;
 import org.netxms.ui.eclipse.objectmanager.Messages;
-import org.netxms.ui.eclipse.objectmanager.dialogs.AttributeEditDialog;
-import org.netxms.ui.eclipse.objectmanager.propertypages.helpers.AttrListLabelProvider;
-import org.netxms.ui.eclipse.objectmanager.propertypages.helpers.AttrViewerComparator;
+import org.netxms.ui.eclipse.objectmanager.dialogs.ObjectUrlEditDialog;
+import org.netxms.ui.eclipse.objectmanager.propertypages.helpers.UrlListLabelProvider;
 import org.netxms.ui.eclipse.shared.ConsoleSharedData;
-import org.netxms.ui.eclipse.tools.MessageDialogHelper;
 import org.netxms.ui.eclipse.tools.WidgetHelper;
 import org.netxms.ui.eclipse.widgets.SortableTableViewer;
 
 /**
- * "Custom Attributes" property page
+ * "External Resources" property page
  */
-public class CustomAttributes extends PropertyPage
+public class ExternalResources extends PropertyPage
 {
        public static final int COLUMN_NAME = 0;
        public static final int COLUMN_VALUE = 1;
        
        private AbstractObject object = null;
        private SortableTableViewer viewer;
+   private Button moveUpButton;
+   private Button moveDownButton;
        private Button addButton;
        private Button editButton;
        private Button deleteButton;
-       private Map<String, String> attributes = null;
-       private boolean isModified = false;
+       private List<ObjectUrl> urls = null;
+       private boolean modified = false;
 
        /* (non-Javadoc)
         * @see org.eclipse.jface.preference.PreferencePage#createContents(org.eclipse.swt.widgets.Composite)
@@ -91,53 +88,91 @@ public class CustomAttributes extends PropertyPage
                layout.verticalSpacing = WidgetHelper.OUTER_SPACING;
                layout.marginWidth = 0;
                layout.marginHeight = 0;
+               layout.numColumns = 2;
       dialogArea.setLayout(layout);
       
-      final String[] columnNames = { Messages.get().CustomAttributes_Name, Messages.get().CustomAttributes_Value };
-      final int[] columnWidths = { 150, 250 };
+      final String[] columnNames = { "URL", "Description" };
+      final int[] columnWidths = { 300, 300 };
       viewer = new SortableTableViewer(dialogArea, columnNames, columnWidths, 0, SWT.UP,
                                        SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION);
       viewer.setContentProvider(new ArrayContentProvider());
-      viewer.setLabelProvider(new AttrListLabelProvider());
-      viewer.setComparator(new AttrViewerComparator());
+      viewer.setLabelProvider(new UrlListLabelProvider());
       
-      attributes = new HashMap<String, String>(object.getCustomAttributes());
-      viewer.setInput(attributes.entrySet());
-      
-      if (!Platform.getPreferencesService().getBoolean("org.netxms.ui.eclipse.console", "SHOW_HIDDEN_ATTRIBUTES", false, null)) //$NON-NLS-1$ //$NON-NLS-2$
-      {
-             viewer.addFilter(new ViewerFilter() {
-                               @SuppressWarnings("unchecked")
-                               @Override
-                               public boolean select(Viewer viewer, Object parentElement, Object element)
-                               {
-                                       return !((Entry<String, String>)element).getKey().startsWith("."); //$NON-NLS-1$
-                               }
-                       });
-      }
+      urls = new ArrayList<ObjectUrl>(object.getUrls());
+      viewer.setInput(urls);
       
       GridData gridData = new GridData();
       gridData.verticalAlignment = GridData.FILL;
       gridData.grabExcessVerticalSpace = true;
       gridData.horizontalAlignment = GridData.FILL;
       gridData.grabExcessHorizontalSpace = true;
+      gridData.horizontalSpan = 2;
       gridData.heightHint = 0;
       viewer.getControl().setLayoutData(gridData);
-      
-      Composite buttons = new Composite(dialogArea, SWT.NONE);
+
+      Composite buttonsLeft = new Composite(dialogArea, SWT.NONE);
       RowLayout buttonLayout = new RowLayout();
       buttonLayout.type = SWT.HORIZONTAL;
       buttonLayout.pack = false;
       buttonLayout.marginWidth = 0;
       buttonLayout.marginRight = 0;
-      buttons.setLayout(buttonLayout);
+      buttonsLeft.setLayout(buttonLayout);
+      gridData = new GridData();
+      gridData.horizontalAlignment = SWT.LEFT;
+      buttonsLeft.setLayoutData(gridData);
+      
+      moveUpButton = new Button(buttonsLeft, SWT.PUSH);
+      moveUpButton.setText("&Up");
+      RowData rd = new RowData();
+      rd.width = WidgetHelper.BUTTON_WIDTH_HINT;
+      moveUpButton.setLayoutData(rd);
+      moveUpButton.addSelectionListener(new SelectionListener() {
+         @Override
+         public void widgetDefaultSelected(SelectionEvent e)
+         {
+            widgetSelected(e);
+         }
+
+         @Override
+         public void widgetSelected(SelectionEvent e)
+         {
+            moveSelection(true);
+         }
+      });
+      
+      moveDownButton = new Button(buttonsLeft, SWT.PUSH);
+      moveDownButton.setText("&Down");
+      rd = new RowData();
+      rd.width = WidgetHelper.BUTTON_WIDTH_HINT;
+      moveDownButton.setLayoutData(rd);
+      moveDownButton.addSelectionListener(new SelectionListener() {
+         @Override
+         public void widgetDefaultSelected(SelectionEvent e)
+         {
+            widgetSelected(e);
+         }
+
+         @Override
+         public void widgetSelected(SelectionEvent e)
+         {
+            moveSelection(false);
+         }
+      });
+      
+      Composite buttonsRight = new Composite(dialogArea, SWT.NONE);
+      buttonLayout = new RowLayout();
+      buttonLayout.type = SWT.HORIZONTAL;
+      buttonLayout.pack = false;
+      buttonLayout.marginWidth = 0;
+      buttonLayout.marginRight = 0;
+      buttonsRight.setLayout(buttonLayout);
       gridData = new GridData();
       gridData.horizontalAlignment = SWT.RIGHT;
-      buttons.setLayoutData(gridData);
+      buttonsRight.setLayoutData(gridData);
 
-      addButton = new Button(buttons, SWT.PUSH);
+      addButton = new Button(buttonsRight, SWT.PUSH);
       addButton.setText(Messages.get().CustomAttributes_Add);
-      RowData rd = new RowData();
+      rd = new RowData();
       rd.width = WidgetHelper.BUTTON_WIDTH_HINT;
       addButton.setLayoutData(rd);
       addButton.addSelectionListener(new SelectionListener() {
@@ -150,25 +185,11 @@ public class CustomAttributes extends PropertyPage
                        @Override
                        public void widgetSelected(SelectionEvent e)
                        {
-                               final AttributeEditDialog dlg = new AttributeEditDialog(CustomAttributes.this.getShell(), null, null);
-                               if (dlg.open() == Window.OK)
-                               {
-                                       if (attributes.containsKey(dlg.getAttrName()))
-                                       {
-                                               MessageDialogHelper.openWarning(CustomAttributes.this.getShell(), Messages.get().CustomAttributes_Warning, 
-                                                     String.format(Messages.get().CustomAttributes_WarningAlreadyExist, dlg.getAttrName()));
-                                       }
-                                       else
-                                       {
-                                               attributes.put(dlg.getAttrName(), dlg.getAttrValue());
-                                     viewer.setInput(attributes.entrySet());
-                                     CustomAttributes.this.isModified = true;
-                                       }
-                               }
+                          addUrl();
                        }
       });
                
-      editButton = new Button(buttons, SWT.PUSH);
+      editButton = new Button(buttonsRight, SWT.PUSH);
       editButton.setText(Messages.get().CustomAttributes_Modify);
       rd = new RowData();
       rd.width = WidgetHelper.BUTTON_WIDTH_HINT;
@@ -180,26 +201,14 @@ public class CustomAttributes extends PropertyPage
                                widgetSelected(e);
                        }
 
-                       @SuppressWarnings("unchecked")
                        @Override
                        public void widgetSelected(SelectionEvent e)
                        {
-                               IStructuredSelection selection = (IStructuredSelection)viewer.getSelection();
-                               if (selection.size() == 1)
-                               {
-                                       Entry<String, String> element = (Entry<String, String>)selection.getFirstElement();
-                                       final AttributeEditDialog dlg = new AttributeEditDialog(CustomAttributes.this.getShell(), element.getKey(), element.getValue());
-                                       if (dlg.open() == Window.OK)
-                                       {
-                                               attributes.put(dlg.getAttrName(), dlg.getAttrValue());
-                                     viewer.setInput(attributes.entrySet());
-                                     CustomAttributes.this.isModified = true;
-                                       }
-                               }
+                          editUrl();
                        }
       });
                
-      deleteButton = new Button(buttons, SWT.PUSH);
+      deleteButton = new Button(buttonsRight, SWT.PUSH);
       deleteButton.setText(Messages.get().CustomAttributes_Delete);
       rd = new RowData();
       rd.width = WidgetHelper.BUTTON_WIDTH_HINT;
@@ -211,22 +220,10 @@ public class CustomAttributes extends PropertyPage
                                widgetSelected(e);
                        }
 
-                       @SuppressWarnings("unchecked")
                        @Override
                        public void widgetSelected(SelectionEvent e)
                        {
-                               IStructuredSelection selection = (IStructuredSelection)viewer.getSelection();
-                               Iterator<Entry<String, String>> it = selection.iterator();
-                               if (it.hasNext())
-                               {
-                                       while(it.hasNext())
-                                       {
-                                               Entry<String, String> element = it.next();
-                                               attributes.remove(element.getKey());
-                                       }
-                             viewer.setInput(attributes.entrySet());
-                             CustomAttributes.this.isModified = true;
-                               }
+                          deleteUrl();
                        }
       });
                
@@ -243,13 +240,97 @@ public class CustomAttributes extends PropertyPage
                        public void selectionChanged(SelectionChangedEvent event)
                        {
                                IStructuredSelection selection = (IStructuredSelection)viewer.getSelection();
-                               editButton.setEnabled(selection.size() == 1);
+                               moveUpButton.setEnabled(selection.size() == 1);
+            moveDownButton.setEnabled(selection.size() == 1);
+            editButton.setEnabled(selection.size() == 1);
                                deleteButton.setEnabled(selection.size() > 0);
                        }
                });
       
                return dialogArea;
        }
+       
+       /**
+        * Add new URL
+        */
+       private void addUrl()
+       {
+          ObjectUrlEditDialog dlg = new ObjectUrlEditDialog(getShell(), null, null);
+          if (dlg.open() != Window.OK)
+             return;
+          
+          urls.add(new ObjectUrl(urls.size(), dlg.getUrl(), dlg.getDescription()));
+          viewer.refresh();
+          modified = true;
+       }
+       
+       /**
+        * Edit selected URL 
+        */
+       private void editUrl()
+       {
+      IStructuredSelection selection = (IStructuredSelection)viewer.getSelection();
+          if (selection.size() != 1)
+             return;
+
+          ObjectUrl url = (ObjectUrl)selection.getFirstElement();
+      ObjectUrlEditDialog dlg = new ObjectUrlEditDialog(getShell(), url.getUrl(), url.getDescription());
+      if (dlg.open() != Window.OK)
+         return;
+
+      int index = urls.indexOf(url);
+      urls.set(index, new ObjectUrl(url.getId(), dlg.getUrl(), dlg.getDescription()));
+      viewer.refresh();
+      viewer.setSelection(new StructuredSelection(urls.get(index)));
+      modified = true;
+       }
+       
+       /**
+        * Delete selected URLs
+        */
+       private void deleteUrl()
+       {
+      IStructuredSelection selection = (IStructuredSelection)viewer.getSelection();
+      if (selection.isEmpty())
+         return;
+      
+          for(Object o : selection.toList())
+             urls.remove(o);
+          for(int i = 0; i < urls.size(); i++)
+          {
+             ObjectUrl u = urls.get(i);
+             urls.set(i, new ObjectUrl(i, u.getUrl(), u.getDescription()));
+          }
+      viewer.refresh();
+      modified = true;
+       }
+       
+       /**
+        * Move selection
+        * 
+        * @param up
+        */
+       private void moveSelection(boolean up)
+       {
+      IStructuredSelection selection = (IStructuredSelection)viewer.getSelection();
+      if (selection.size() != 1)
+         return;
+
+      ObjectUrl url = (ObjectUrl)selection.getFirstElement();
+      int index = urls.indexOf(url);
+      if (((index == 0) && up) || ((index == urls.size() - 1) && !up))
+         return;
+      
+      int swapIndex = up ? index - 1 : index + 1;
+      ObjectUrl swapUrl = urls.get(swapIndex);
+      
+      urls.set(index, new ObjectUrl(index, swapUrl.getUrl(), swapUrl.getDescription()));
+      urls.set(swapIndex, new ObjectUrl(index, url.getUrl(), url.getDescription()));
+      
+      viewer.refresh();
+      viewer.setSelection(new StructuredSelection(urls.get(swapIndex)));
+      modified = true;
+       }
 
        /**
         * Apply changes
@@ -258,27 +339,27 @@ public class CustomAttributes extends PropertyPage
         */
        protected void applyChanges(final boolean isApply)
        {
-               if (!isModified)
+               if (!modified)
                        return;         // Nothing to apply
                
                if (isApply)
                        setValid(false);
                
                final NXCObjectModificationData md = new NXCObjectModificationData(object.getObjectId());
-               md.setCustomAttributes(attributes);
+               md.setUrls(new ArrayList<ObjectUrl>(urls));
                final NXCSession session = (NXCSession)ConsoleSharedData.getSession();
                new ConsoleJob(Messages.get().CustomAttributes_JobName, null, Activator.PLUGIN_ID, null) {
                        @Override
                        protected void runInternal(IProgressMonitor monitor) throws Exception
                        {
                                session.modifyObject(md);
-                               isModified = false;
+                               modified = false;
                        }
 
                        @Override
                        protected String getErrorMessage()
                        {
-                               return Messages.get().CustomAttributes_JobError;
+                               return "Cannot update object's URL list";
                        }
 
                        @Override
@@ -290,7 +371,7 @@ public class CustomAttributes extends PropertyPage
                                                @Override
                                                public void run()
                                                {
-                                                       CustomAttributes.this.setValid(true);
+                                                       ExternalResources.this.setValid(true);
                                                }
                                        });
                                }
diff --git a/src/java/netxms-eclipse/ObjectManager/src/org/netxms/ui/eclipse/objectmanager/propertypages/helpers/UrlListLabelProvider.java b/src/java/netxms-eclipse/ObjectManager/src/org/netxms/ui/eclipse/objectmanager/propertypages/helpers/UrlListLabelProvider.java
new file mode 100644 (file)
index 0000000..c19303d
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ * NetXMS - open source network management system
+ * Copyright (C) 2003-2017 Victor Kirhenshtein
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+package org.netxms.ui.eclipse.objectmanager.propertypages.helpers;
+
+import java.net.URL;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.swt.graphics.Image;
+import org.netxms.client.ObjectUrl;
+
+/**
+ * Label provider for URL list
+ */
+public class UrlListLabelProvider extends LabelProvider implements ITableLabelProvider
+{
+   /* (non-Javadoc)
+    * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int)
+    */
+   @Override
+   public Image getColumnImage(Object element, int columnIndex)
+   {
+      return null;
+   }
+
+   /* (non-Javadoc)
+    * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int)
+    */
+   @Override
+   public String getColumnText(Object element, int columnIndex)
+   {
+      switch(columnIndex)
+      {
+         case 0:
+            URL url = ((ObjectUrl)element).getUrl(); 
+            return (url != null) ? url.toExternalForm() : "";
+         case 1:
+            return ((ObjectUrl)element).getDescription();
+      }
+      return null;
+   }
+}
index d8f9f54..68a58be 100644 (file)
@@ -12,7 +12,8 @@ Require-Bundle: org.eclipse.ui;bundle-version="3.8.2",
  org.netxms.ui.eclipse.charts;bundle-version="2.0.0",
  org.netxms.ui.eclipse.objecttools;bundle-version="2.0.6",
  org.netxms.ui.eclipse.imagelibrary;bundle-version="2.0.0",
- org.netxms.ui.eclipse.objectbrowser;bundle-version="2.0.7"
+ org.netxms.ui.eclipse.objectbrowser;bundle-version="2.0.7",
+ org.eclipse.ui.forms;bundle-version="3.5.200"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.6
 Bundle-ActivationPolicy: lazy
 Export-Package: org.netxms.ui.eclipse.objectview.api,
index ee2ec1b..4ad458a 100644 (file)
@@ -37,6 +37,7 @@ import org.netxms.ui.eclipse.objectview.objecttabs.elements.Capabilities;
 import org.netxms.ui.eclipse.objectview.objecttabs.elements.Commands;
 import org.netxms.ui.eclipse.objectview.objecttabs.elements.Comments;
 import org.netxms.ui.eclipse.objectview.objecttabs.elements.Connection;
+import org.netxms.ui.eclipse.objectview.objecttabs.elements.ExternalResources;
 import org.netxms.ui.eclipse.objectview.objecttabs.elements.GeneralInfo;
 import org.netxms.ui.eclipse.objectview.objecttabs.elements.LastValues;
 import org.netxms.ui.eclipse.objectview.objecttabs.elements.OverviewPageElement;
@@ -105,6 +106,8 @@ public class ObjectOverview extends ObjectTab
                elements.add(e);
                e = new AvailabilityChart(leftColumn, e, this);
                elements.add(e);
+      e = new ExternalResources(leftColumn, e, this);
+      elements.add(e);
                e = new Comments(leftColumn, e, this);
                elements.add(e);
                e = new Capabilities(rightColumn, null, this);
diff --git a/src/java/netxms-eclipse/ObjectView/src/org/netxms/ui/eclipse/objectview/objecttabs/elements/ExternalResources.java b/src/java/netxms-eclipse/ObjectView/src/org/netxms/ui/eclipse/objectview/objecttabs/elements/ExternalResources.java
new file mode 100644 (file)
index 0000000..a93ad92
--- /dev/null
@@ -0,0 +1,146 @@
+/**
+ * 
+ */
+package org.netxms.ui.eclipse.objectview.objecttabs.elements;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.forms.events.HyperlinkAdapter;
+import org.eclipse.ui.forms.events.HyperlinkEvent;
+import org.eclipse.ui.forms.widgets.Hyperlink;
+import org.netxms.client.ObjectUrl;
+import org.netxms.client.objects.AbstractObject;
+import org.netxms.ui.eclipse.console.resources.SharedColors;
+import org.netxms.ui.eclipse.objectview.Activator;
+import org.netxms.ui.eclipse.objectview.objecttabs.ObjectTab;
+import org.netxms.ui.eclipse.tools.MessageDialogHelper;
+
+/**
+ * @author victor
+ *
+ */
+public class ExternalResources extends OverviewPageElement
+{
+   private Composite content;
+   private List<Element> elements = new ArrayList<Element>();
+   
+   /**
+    * @param parent
+    * @param anchor
+    * @param objectTab
+    */
+   public ExternalResources(Composite parent, OverviewPageElement anchor, ObjectTab objectTab)
+   {
+      super(parent, anchor, objectTab);
+   }
+
+   /* (non-Javadoc)
+    * @see org.netxms.ui.eclipse.objectview.objecttabs.elements.OverviewPageElement#getTitle()
+    */
+   @Override
+   protected String getTitle()
+   {
+      return "External Resources";
+   }
+
+   /* (non-Javadoc)
+    * @see org.netxms.ui.eclipse.objectview.objecttabs.elements.OverviewPageElement#isApplicableForObject(org.netxms.client.objects.AbstractObject)
+    */
+   @Override
+   public boolean isApplicableForObject(AbstractObject object)
+   {
+      return object.hasUrls();
+   }
+
+   /* (non-Javadoc)
+    * @see org.netxms.ui.eclipse.objectview.objecttabs.elements.OverviewPageElement#createClientArea(org.eclipse.swt.widgets.Composite)
+    */
+   @Override
+   protected Control createClientArea(Composite parent)
+   {
+      content = new Composite(parent, SWT.NONE);
+      GridLayout layout = new GridLayout();
+      layout.numColumns = 2;
+      content.setLayout(layout);
+      content.setBackground(SharedColors.getColor(SharedColors.OBJECT_TAB_BACKGROUND, parent.getDisplay()));
+      return content;
+   }
+
+   /* (non-Javadoc)
+    * @see org.netxms.ui.eclipse.objectview.objecttabs.elements.OverviewPageElement#onObjectChange()
+    */
+   @Override
+   protected void onObjectChange()
+   {
+      for(Element e : elements)
+         e.dispose();
+      elements.clear();
+      for(ObjectUrl u : getObject().getUrls())
+         elements.add(new Element(content, u));
+      content.layout();
+   }
+   
+   /**
+    * Open URL
+    * 
+    * @param url URL to open
+    */
+   private void openUrl(URL url)
+   {
+      try
+      {
+         PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser().openURL(url);
+      }
+      catch(PartInitException e)
+      {
+         Activator.log("Exception when trying to open URL " + url.toExternalForm(), e);
+         MessageDialogHelper.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), "Error", "Cannot start external web browser");
+      }
+   }
+   
+   /**
+    * Display element
+    */
+   private class Element
+   {
+      ObjectUrl url;
+      Hyperlink link;
+      Label description;
+      
+      Element(Composite parent, ObjectUrl url)
+      {
+         this.url = url;
+         
+         link = new Hyperlink(parent, SWT.NONE);
+         link.setBackground(content.getBackground());
+         link.setForeground(SharedColors.getColor(SharedColors.COMMAND_BOX_TEXT, link.getDisplay()));
+         link.setText(url.getUrl().toExternalForm());
+         link.addHyperlinkListener(new HyperlinkAdapter() {
+            @Override
+            public void linkActivated(HyperlinkEvent e)
+            {
+               openUrl(Element.this.url.getUrl());
+            }
+            
+         });
+         
+         description = new Label(parent, SWT.NONE);
+         description.setBackground(content.getBackground());
+         description.setText(url.getDescription());
+      }
+      
+      void dispose()
+      {
+         link.dispose();
+         description.dispose();
+      }
+   }
+}
index 225d6ec..07063bf 100644 (file)
@@ -85,6 +85,7 @@ NetObj::NetObj()
    m_moduleData = NULL;
    m_postalAddress = new PostalAddress();
    m_dashboards = new IntegerArray<UINT32>();
+   m_urls = new ObjectArray<ObjectUrl>(4, 4, true);
 }
 
 /**
@@ -105,6 +106,7 @@ NetObj::~NetObj()
    delete m_moduleData;
    delete m_postalAddress;
    delete m_dashboards;
+   delete m_urls;
 }
 
 /**
@@ -175,6 +177,8 @@ bool NetObj::deleteFromDatabase(DB_HANDLE hdb)
       success = executeQueryOnObject(hdb, _T("DELETE FROM object_properties WHERE object_id=?"));
    if (success)
       success = executeQueryOnObject(hdb, _T("DELETE FROM object_custom_attributes WHERE object_id=?"));
+   if (success)
+      success = executeQueryOnObject(hdb, _T("DELETE FROM object_urls WHERE object_id=?"));
 
    // Delete events
    if (success && ConfigReadInt(_T("DeleteEventsOfDeletedObject"), 1))
@@ -354,6 +358,35 @@ bool NetObj::loadCommonProperties(DB_HANDLE hdb)
       }
    }
 
+   // Load associated URLs
+   if (success)
+   {
+      hStmt = DBPrepare(hdb, _T("SELECT url_id,url,description FROM object_urls WHERE object_id=?"));
+      if (hStmt != NULL)
+      {
+         DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
+         DB_RESULT hResult = DBSelectPrepared(hStmt);
+         if (hResult != NULL)
+         {
+            int count = DBGetNumRows(hResult);
+            for(int i = 0; i < count; i++)
+            {
+               m_urls->add(new ObjectUrl(hResult, i));
+            }
+            DBFreeResult(hResult);
+         }
+         else
+         {
+            success = false;
+         }
+         DBFreeStatement(hStmt);
+      }
+      else
+      {
+         success = false;
+      }
+   }
+
        if (success)
                success = loadTrustedNodes(hdb);
 
@@ -483,9 +516,7 @@ bool NetObj::saveCommonProperties(DB_HANDLE hdb)
    // Save dashboard associations
    if (success)
    {
-      TCHAR szQuery[512];
-      _sntprintf(szQuery, 512, _T("DELETE FROM dashboard_associations WHERE object_id=%d"), m_id);
-      success = DBQuery(hdb, szQuery);
+      success = ExecuteQueryOnObject(hdb, m_id, _T("DELETE FROM dashboard_associations WHERE object_id=?"));
       if (success && (m_dashboards->size() > 0))
       {
          hStmt = DBPrepare(hdb, _T("INSERT INTO dashboard_associations (object_id,dashboard_id) VALUES (?,?)"));
@@ -506,6 +537,33 @@ bool NetObj::saveCommonProperties(DB_HANDLE hdb)
       }
    }
 
+   // Save URL associations
+   if (success)
+   {
+      success = ExecuteQueryOnObject(hdb, m_id, _T("DELETE FROM object_urls WHERE object_id=?"));
+      if (success && (m_urls->size() > 0))
+      {
+         hStmt = DBPrepare(hdb, _T("INSERT INTO object_urls (object_id,url_id,url,description) VALUES (?,?,?,?)"));
+         if (hStmt != NULL)
+         {
+            DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
+            for(int i = 0; (i < m_urls->size()) && success; i++)
+            {
+               const ObjectUrl *url = m_urls->get(i);
+               DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, url->getId());
+               DBBind(hStmt, 3, DB_SQLTYPE_VARCHAR, url->getUrl(), DB_BIND_STATIC);
+               DBBind(hStmt, 4, DB_SQLTYPE_VARCHAR, url->getDescription(), DB_BIND_STATIC);
+               success = DBExecute(hStmt);
+            }
+            DBFreeStatement(hStmt);
+         }
+         else
+         {
+            success = false;
+         }
+      }
+   }
+
    // Save module data
    if (success && (m_moduleData != NULL))
    {
@@ -1042,6 +1100,17 @@ void NetObj::fillMessageInternal(NXCPMessage *pMsg)
    pMsg->setField(VID_STREET_ADDRESS, m_postalAddress->getStreetAddress());
    pMsg->setField(VID_POSTCODE, m_postalAddress->getPostCode());
 
+   pMsg->setField(VID_NUM_URLS, (UINT32)m_urls->size());
+   UINT32 fieldId = VID_URL_LIST_BASE;
+   for(int i = 0; i < m_urls->size(); i++)
+   {
+      const ObjectUrl *url = m_urls->get(i);
+      pMsg->setField(fieldId++, url->getId());
+      pMsg->setField(fieldId++, url->getUrl());
+      pMsg->setField(fieldId++, url->getDescription());
+      fieldId += 7;
+   }
+
    if (m_moduleData != NULL)
    {
       pMsg->setField(VID_MODULE_DATA_COUNT, (UINT16)m_moduleData->size());
@@ -1249,6 +1318,19 @@ UINT32 NetObj::modifyFromMessageInternal(NXCPMessage *pRequest)
       pRequest->getFieldAsInt32Array(VID_DASHBOARDS, m_dashboards);
    }
 
+   // Update URL list
+   if (pRequest->isFieldExist(VID_NUM_URLS))
+   {
+      m_urls->clear();
+      int count = pRequest->getFieldAsInt32(VID_NUM_URLS);
+      UINT32 fieldId = VID_URL_LIST_BASE;
+      for(int i = 0; i < count; i++)
+      {
+         m_urls->add(new ObjectUrl(pRequest, fieldId));
+         fieldId += 10;
+      }
+   }
+
    return RCC_SUCCESS;
 }
 
index 8cef77c..cee4b17 100644 (file)
@@ -361,3 +361,42 @@ InetAddress NXCORE_EXPORTABLE ResolveHostName(UINT32 zoneId, const TCHAR *hostna
    }
    return ipAddr;
 }
+
+/**
+ * Create object URL from NXCP message
+ */
+ObjectUrl::ObjectUrl(NXCPMessage *msg, UINT32 baseId)
+{
+   m_id = msg->getFieldAsUInt32(baseId);
+   m_url = msg->getFieldAsString(baseId + 1);
+   m_description = msg->getFieldAsString(baseId + 2);
+}
+
+/**
+ * Create object URL from database result set
+ */
+ObjectUrl::ObjectUrl(DB_RESULT hResult, int row)
+{
+   m_id = DBGetFieldULong(hResult, row, 0);
+   m_url = DBGetField(hResult, row, 1, NULL, 0);
+   m_description = DBGetField(hResult, row, 2, NULL, 0);
+}
+
+/**
+ * Object URL destructor
+ */
+ObjectUrl::~ObjectUrl()
+{
+   free(m_url);
+   free(m_description);
+}
+
+/**
+ * Fill NXCP message
+ */
+void ObjectUrl::fillMessage(NXCPMessage *msg, UINT32 baseId)
+{
+   msg->setField(baseId, m_id);
+   msg->setField(baseId + 1, m_url);
+   msg->setField(baseId + 2, m_description);
+}
index 6ec732e..06aee6e 100644 (file)
@@ -435,6 +435,28 @@ public:
 };
 
 /**
+ * Object-associated URL
+ */
+class NXCORE_EXPORTABLE ObjectUrl
+{
+private:
+   UINT32 m_id;
+   TCHAR *m_url;
+   TCHAR *m_description;
+
+public:
+   ObjectUrl(NXCPMessage *msg, UINT32 baseId);
+   ObjectUrl(DB_RESULT hResult, int row);
+   ~ObjectUrl();
+
+   void fillMessage(NXCPMessage *msg, UINT32 baseId);
+
+   UINT32 getId() const { return m_id; }
+   const TCHAR *getUrl() const { return m_url; }
+   const TCHAR *getDescription() const { return m_description; }
+};
+
+/**
  * Base class for network objects
  */
 class NXCORE_EXPORTABLE NetObj
@@ -475,6 +497,7 @@ protected:
    ClientSession *m_pollRequestor;
        UINT32 m_submapId;                              // Map object which should be open on drill-down request
        IntegerArray<UINT32> *m_dashboards; // Dashboards associated with this object
+       ObjectArray<ObjectUrl> *m_urls;  // URLs associated with this object
 
    ObjectArray<NetObj> *m_childList;     // Array of pointers to child objects
    ObjectArray<NetObj> *m_parentList;    // Array of pointers to parent objects
index 3d33702..e240ff2 100644 (file)
@@ -747,6 +747,22 @@ static bool SetSchemaVersion(int version)
 }
 
 /**
+ * Upgrade from V441 to V442
+ */
+static BOOL H_UpgradeFromV441(int currVersion, int newVersion)
+{
+   CHK_EXEC(CreateTable(
+      _T("CREATE TABLE object_urls (")
+      _T("  object_id integer not null,")
+      _T("  url_id integer not null,")
+      _T("  url varchar(2000) null,")
+      _T("  description varchar(2000) null,")
+      _T("  PRIMARY KEY(object_id,url_id))")));
+   CHK_EXEC(SetSchemaVersion(442));
+   return TRUE;
+}
+
+/**
  * Upgrade from V440 to V441
  */
 static BOOL H_UpgradeFromV440(int currVersion, int newVersion)
@@ -11559,6 +11575,7 @@ static struct
    { 438, 439, H_UpgradeFromV438 },
    { 439, 440, H_UpgradeFromV439 },
    { 440, 441, H_UpgradeFromV440 },
+   { 441, 442, H_UpgradeFromV441 },
    { 0, 0, NULL }
 };
 
index 24df392..13496cd 100644 (file)
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: NXMC Basic Object Management Plug-in
 Bundle-SymbolicName: org.netxms.ui.eclipse.objectmanager;singleton:=true
-Bundle-Version: 2.1.2
+Bundle-Version: 2.1.3
 Bundle-Activator: org.netxms.ui.eclipse.objectmanager.Activator
 Bundle-Vendor: netxms.org
 Require-Bundle: org.eclipse.rap.ui;bundle-version="2.3.0",
index bcfd591..a913715 100644 (file)
               </instanceof>
            </enabledWhen>
         </page>
+        <page
+              class="org.netxms.ui.eclipse.objectmanager.propertypages.ExternalResources"
+              id="org.netxms.ui.eclipse.objectmanager.propertypages.ExternalResources"
+              name="External Resources">
+           <enabledWhen>
+              <instanceof
+                    value="org.netxms.client.objects.AbstractObject">
+              </instanceof>
+           </enabledWhen>
+        </page>
   </extension>
 
    <extension
index 1975b9c..a30ba21 100644 (file)
@@ -20,35 +20,33 @@ package org.netxms.ui.eclipse.objectmanager.dialogs;
 
 import org.eclipse.jface.dialogs.Dialog;
 import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
 import org.netxms.ui.eclipse.objectmanager.Messages;
 import org.netxms.ui.eclipse.tools.WidgetHelper;
-
+import org.netxms.ui.eclipse.widgets.LabeledText;
 
 /**
  * Object's custom attribute edit dialog
- *
  */
 public class AttributeEditDialog extends Dialog
 {
-       private Text textName;
-       private Text textValue;
-       private String attrName;
-       private String attrValue;
+       private LabeledText textName;
+       private LabeledText textValue;
+       private String name;
+       private String value;
        
        /**
         * @param parentShell
         */
-       public AttributeEditDialog(Shell parentShell, String attrName, String attrValue)
+       public AttributeEditDialog(Shell parentShell, String name, String value)
        {
                super(parentShell);
-               this.attrName = attrName;
-               this.attrValue = attrValue;
+               this.name = name;
+               this.value = value;
        }
 
        /* (non-Javadoc)
@@ -59,36 +57,35 @@ public class AttributeEditDialog extends Dialog
        {
                Composite dialogArea = (Composite)super.createDialogArea(parent);
                
-               FillLayout layout = new FillLayout();
-      layout.type = SWT.VERTICAL;
-      layout.marginWidth = WidgetHelper.DIALOG_WIDTH_MARGIN;
+               GridLayout layout = new GridLayout();
       layout.marginHeight = WidgetHelper.DIALOG_HEIGHT_MARGIN;
       dialogArea.setLayout(layout);
                
-      Label label = new Label(dialogArea, SWT.NONE);
-      label.setText(Messages.get().AttributeEditDialog_Name);
-      
-      textName = new Text(dialogArea, SWT.SINGLE | SWT.BORDER);
-      textName.setTextLimit(63);
-      if (attrName != null)
+      textName = new LabeledText(dialogArea, SWT.NONE);
+      textName.setLabel(Messages.get().AttributeEditDialog_Name);
+      textName.getTextControl().setTextLimit(63);
+      if (name != null)
       {
-       textName.setText(attrName);
+       textName.setText(name);
        textName.setEditable(false);
       }
+      GridData gd = new GridData();
+      gd.horizontalAlignment = SWT.FILL;
+      gd.grabExcessHorizontalSpace = true;
+      textName.setLayoutData(gd);
       
-      label = new Label(dialogArea, SWT.NONE);
-      label.setText(""); //$NON-NLS-1$
-
-      label = new Label(dialogArea, SWT.NONE);
-      label.setText(Messages.get().AttributeEditDialog_Value);
-
-      textValue = new Text(dialogArea, SWT.SINGLE | SWT.BORDER);
-      textValue.setTextLimit(255);
-      textValue.getShell().setMinimumSize(300, 0);
-      if (attrValue != null)
-       textValue.setText(attrValue);
+      textValue = new LabeledText(dialogArea, SWT.NONE);
+      textValue.setLabel(Messages.get().AttributeEditDialog_Value);
+      textValue.getTextControl().setTextLimit(255);
+      if (value != null)
+       textValue.setText(value);
+      gd = new GridData();
+      gd.horizontalAlignment = SWT.FILL;
+      gd.grabExcessHorizontalSpace = true;
+      gd.widthHint = 300;
+      textValue.setLayoutData(gd);
       
-      if (attrName != null)
+      if (name != null)
        textValue.setFocus();
       
                return dialogArea;
@@ -101,29 +98,24 @@ public class AttributeEditDialog extends Dialog
        protected void configureShell(Shell newShell)
        {
                super.configureShell(newShell);
-               newShell.setText((attrName == null) ? Messages.get().AttributeEditDialog_AddAttr : Messages.get().AttributeEditDialog_ModifyAttr);
+               newShell.setText((name == null) ? Messages.get().AttributeEditDialog_AddAttr : Messages.get().AttributeEditDialog_ModifyAttr);
        }
        
-       
        /**
         * Get variable name
-        * 
         */
-       public String getAttrName()
+       public String getName()
        {
-               return attrName;
+               return name;
        }
        
-       
        /**
         * Get variable value
-        * 
         */
-       public String getAttrValue()
+       public String getValue()
        {
-               return attrValue;
+               return value;
        }
-
        
        /* (non-Javadoc)
         * @see org.eclipse.jface.dialogs.Dialog#okPressed()
@@ -131,8 +123,8 @@ public class AttributeEditDialog extends Dialog
        @Override
        protected void okPressed()
        {
-               attrName = textName.getText();
-               attrValue = textValue.getText();
+               name = textName.getText().trim();
+               value = textValue.getText();
                super.okPressed();
        }
 }
@@ -1,6 +1,6 @@
 /**
  * NetXMS - open source network management system
- * Copyright (C) 2003-2013 Victor Kirhenshtein
+ * Copyright (C) 2003-2017 Victor Kirhenshtein
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  */
 package org.netxms.ui.eclipse.objectmanager.dialogs;
 
+import java.net.MalformedURLException;
+import java.net.URL;
 import org.eclipse.jface.dialogs.Dialog;
 import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
-import org.netxms.ui.eclipse.objectmanager.Messages;
+import org.netxms.ui.eclipse.tools.MessageDialogHelper;
 import org.netxms.ui.eclipse.tools.WidgetHelper;
-
+import org.netxms.ui.eclipse.widgets.LabeledText;
 
 /**
- * Object's custom attribute edit dialog
- *
+ * Object's associated URL edit dialog
  */
-public class AttributeEditDialog extends Dialog
+public class ObjectUrlEditDialog extends Dialog
 {
-       private Text textName;
-       private Text textValue;
-       private String attrName;
-       private String attrValue;
+       private LabeledText textUrl;
+       private LabeledText textDescription;
+       private URL url;
+       private String description;
        
        /**
         * @param parentShell
         */
-       public AttributeEditDialog(Shell parentShell, String attrName, String attrValue)
+       public ObjectUrlEditDialog(Shell parentShell, URL url, String description)
        {
                super(parentShell);
-               this.attrName = attrName;
-               this.attrValue = attrValue;
+               this.url = url;
+               this.description = description;
        }
 
        /* (non-Javadoc)
@@ -59,37 +59,30 @@ public class AttributeEditDialog extends Dialog
        {
                Composite dialogArea = (Composite)super.createDialogArea(parent);
                
-               FillLayout layout = new FillLayout();
-      layout.type = SWT.VERTICAL;
-      layout.marginWidth = WidgetHelper.DIALOG_WIDTH_MARGIN;
+               GridLayout layout = new GridLayout();
       layout.marginHeight = WidgetHelper.DIALOG_HEIGHT_MARGIN;
       dialogArea.setLayout(layout);
                
-      Label label = new Label(dialogArea, SWT.NONE);
-      label.setText(Messages.get().AttributeEditDialog_Name);
-      
-      textName = new Text(dialogArea, SWT.SINGLE | SWT.BORDER);
-      textName.setTextLimit(63);
-      if (attrName != null)
-      {
-       textName.setText(attrName);
-       textName.setEditable(false);
-      }
-      
-      label = new Label(dialogArea, SWT.NONE);
-      label.setText(""); //$NON-NLS-1$
-
-      label = new Label(dialogArea, SWT.NONE);
-      label.setText(Messages.get().AttributeEditDialog_Value);
-
-      textValue = new Text(dialogArea, SWT.SINGLE | SWT.BORDER);
-      textValue.setTextLimit(255);
-      textValue.getShell().setMinimumSize(300, 0);
-      if (attrValue != null)
-       textValue.setText(attrValue);
+      textUrl = new LabeledText(dialogArea, SWT.NONE);
+      textUrl.setLabel("URL");
+      textUrl.getTextControl().setTextLimit(2000);
+      if (url != null)
+       textUrl.setText(url.toExternalForm());
+      GridData gd = new GridData();
+      gd.horizontalAlignment = SWT.FILL;
+      gd.grabExcessHorizontalSpace = true;
+      textUrl.setLayoutData(gd);
       
-      if (attrName != null)
-       textValue.setFocus();
+      textDescription = new LabeledText(dialogArea, SWT.NONE);
+      textDescription.setLabel("Description");
+      textDescription.getTextControl().setTextLimit(2000);
+      if (description != null)
+       textDescription.setText(description);
+      gd = new GridData();
+      gd.horizontalAlignment = SWT.FILL;
+      gd.grabExcessHorizontalSpace = true;
+      gd.widthHint = 500;
+      textDescription.setLayoutData(gd);
       
                return dialogArea;
        }
@@ -101,29 +94,24 @@ public class AttributeEditDialog extends Dialog
        protected void configureShell(Shell newShell)
        {
                super.configureShell(newShell);
-               newShell.setText((attrName == null) ? Messages.get().AttributeEditDialog_AddAttr : Messages.get().AttributeEditDialog_ModifyAttr);
+               newShell.setText((url == null) ? "Create URL" : "Edit URL");
        }
        
-       
        /**
-        * Get variable name
-        * 
+        * Get URL
         */
-       public String getAttrName()
+       public URL getUrl()
        {
-               return attrName;
+               return url;
        }
        
-       
        /**
-        * Get variable value
-        * 
+        * Get description
         */
-       public String getAttrValue()
+       public String getDescription()
        {
-               return attrValue;
+               return description;
        }
-
        
        /* (non-Javadoc)
         * @see org.eclipse.jface.dialogs.Dialog#okPressed()
@@ -131,8 +119,16 @@ public class AttributeEditDialog extends Dialog
        @Override
        protected void okPressed()
        {
-               attrName = textName.getText();
-               attrValue = textValue.getText();
+               try
+      {
+         url = new URL(textUrl.getText().trim());
+      }
+      catch(MalformedURLException e)
+      {
+         MessageDialogHelper.openWarning(getShell(), "Warning", "Entered URL is invalid. Please enter valid URL.");
+         return;
+      }
+               description = textDescription.getText();
                super.okPressed();
        }
 }
index 2f5d69b..68dab47 100644 (file)
@@ -153,14 +153,14 @@ public class CustomAttributes extends PropertyPage
                                final AttributeEditDialog dlg = new AttributeEditDialog(CustomAttributes.this.getShell(), null, null);
                                if (dlg.open() == Window.OK)
                                {
-                                       if (attributes.containsKey(dlg.getAttrName()))
+                                       if (attributes.containsKey(dlg.getName()))
                                        {
                                                MessageDialogHelper.openWarning(CustomAttributes.this.getShell(), Messages.get().CustomAttributes_Warning, 
-                                                     String.format(Messages.get().CustomAttributes_WarningAlreadyExist, dlg.getAttrName()));
+                                                     String.format(Messages.get().CustomAttributes_WarningAlreadyExist, dlg.getName()));
                                        }
                                        else
                                        {
-                                               attributes.put(dlg.getAttrName(), dlg.getAttrValue());
+                                               attributes.put(dlg.getName(), dlg.getValue());
                                      viewer.setInput(attributes.entrySet());
                                      CustomAttributes.this.isModified = true;
                                        }
@@ -191,7 +191,7 @@ public class CustomAttributes extends PropertyPage
                                        final AttributeEditDialog dlg = new AttributeEditDialog(CustomAttributes.this.getShell(), element.getKey(), element.getValue());
                                        if (dlg.open() == Window.OK)
                                        {
-                                               attributes.put(dlg.getAttrName(), dlg.getAttrValue());
+                                               attributes.put(dlg.getName(), dlg.getValue());
                                      viewer.setInput(attributes.entrySet());
                                      CustomAttributes.this.isModified = true;
                                        }
  */
 package org.netxms.ui.eclipse.objectmanager.propertypages;
 
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Map.Entry;
+import java.util.ArrayList;
+import java.util.List;
 import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.Platform;
 import org.eclipse.jface.viewers.ArrayContentProvider;
 import org.eclipse.jface.viewers.DoubleClickEvent;
 import org.eclipse.jface.viewers.IDoubleClickListener;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
 import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.jface.viewers.SelectionChangedEvent;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.jface.window.Window;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.SelectionEvent;
@@ -47,33 +43,34 @@ import org.eclipse.swt.widgets.Event;
 import org.eclipse.ui.dialogs.PropertyPage;
 import org.netxms.client.NXCObjectModificationData;
 import org.netxms.client.NXCSession;
+import org.netxms.client.ObjectUrl;
 import org.netxms.client.objects.AbstractObject;
 import org.netxms.ui.eclipse.jobs.ConsoleJob;
 import org.netxms.ui.eclipse.objectmanager.Activator;
 import org.netxms.ui.eclipse.objectmanager.Messages;
-import org.netxms.ui.eclipse.objectmanager.dialogs.AttributeEditDialog;
-import org.netxms.ui.eclipse.objectmanager.propertypages.helpers.AttrListLabelProvider;
-import org.netxms.ui.eclipse.objectmanager.propertypages.helpers.AttrViewerComparator;
+import org.netxms.ui.eclipse.objectmanager.dialogs.ObjectUrlEditDialog;
+import org.netxms.ui.eclipse.objectmanager.propertypages.helpers.UrlListLabelProvider;
 import org.netxms.ui.eclipse.shared.ConsoleSharedData;
-import org.netxms.ui.eclipse.tools.MessageDialogHelper;
 import org.netxms.ui.eclipse.tools.WidgetHelper;
 import org.netxms.ui.eclipse.widgets.SortableTableViewer;
 
 /**
- * "Custom Attributes" property page
+ * "External Resources" property page
  */
-public class CustomAttributes extends PropertyPage
+public class ExternalResources extends PropertyPage
 {
        public static final int COLUMN_NAME = 0;
        public static final int COLUMN_VALUE = 1;
        
        private AbstractObject object = null;
        private SortableTableViewer viewer;
+   private Button moveUpButton;
+   private Button moveDownButton;
        private Button addButton;
        private Button editButton;
        private Button deleteButton;
-       private Map<String, String> attributes = null;
-       private boolean isModified = false;
+       private List<ObjectUrl> urls = null;
+       private boolean modified = false;
 
        /* (non-Javadoc)
         * @see org.eclipse.jface.preference.PreferencePage#createContents(org.eclipse.swt.widgets.Composite)
@@ -91,53 +88,91 @@ public class CustomAttributes extends PropertyPage
                layout.verticalSpacing = WidgetHelper.OUTER_SPACING;
                layout.marginWidth = 0;
                layout.marginHeight = 0;
+               layout.numColumns = 2;
       dialogArea.setLayout(layout);
       
-      final String[] columnNames = { Messages.get().CustomAttributes_Name, Messages.get().CustomAttributes_Value };
-      final int[] columnWidths = { 150, 250 };
+      final String[] columnNames = { "URL", "Description" };
+      final int[] columnWidths = { 300, 300 };
       viewer = new SortableTableViewer(dialogArea, columnNames, columnWidths, 0, SWT.UP,
                                        SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION);
       viewer.setContentProvider(new ArrayContentProvider());
-      viewer.setLabelProvider(new AttrListLabelProvider());
-      viewer.setComparator(new AttrViewerComparator());
+      viewer.setLabelProvider(new UrlListLabelProvider());
       
-      attributes = new HashMap<String, String>(object.getCustomAttributes());
-      viewer.setInput(attributes.entrySet());
-      
-      if (!Platform.getPreferencesService().getBoolean("org.netxms.ui.eclipse.console", "SHOW_HIDDEN_ATTRIBUTES", false, null)) //$NON-NLS-1$ //$NON-NLS-2$
-      {
-             viewer.addFilter(new ViewerFilter() {
-                               @SuppressWarnings("unchecked")
-                               @Override
-                               public boolean select(Viewer viewer, Object parentElement, Object element)
-                               {
-                                       return !((Entry<String, String>)element).getKey().startsWith("."); //$NON-NLS-1$
-                               }
-                       });
-      }
+      urls = new ArrayList<ObjectUrl>(object.getUrls());
+      viewer.setInput(urls);
       
       GridData gridData = new GridData();
       gridData.verticalAlignment = GridData.FILL;
       gridData.grabExcessVerticalSpace = true;
       gridData.horizontalAlignment = GridData.FILL;
       gridData.grabExcessHorizontalSpace = true;
+      gridData.horizontalSpan = 2;
       gridData.heightHint = 0;
       viewer.getControl().setLayoutData(gridData);
-      
-      Composite buttons = new Composite(dialogArea, SWT.NONE);
+
+      Composite buttonsLeft = new Composite(dialogArea, SWT.NONE);
       RowLayout buttonLayout = new RowLayout();
       buttonLayout.type = SWT.HORIZONTAL;
       buttonLayout.pack = false;
       buttonLayout.marginWidth = 0;
       buttonLayout.marginRight = 0;
-      buttons.setLayout(buttonLayout);
+      buttonsLeft.setLayout(buttonLayout);
+      gridData = new GridData();
+      gridData.horizontalAlignment = SWT.LEFT;
+      buttonsLeft.setLayoutData(gridData);
+      
+      moveUpButton = new Button(buttonsLeft, SWT.PUSH);
+      moveUpButton.setText("&Up");
+      RowData rd = new RowData();
+      rd.width = WidgetHelper.BUTTON_WIDTH_HINT;
+      moveUpButton.setLayoutData(rd);
+      moveUpButton.addSelectionListener(new SelectionListener() {
+         @Override
+         public void widgetDefaultSelected(SelectionEvent e)
+         {
+            widgetSelected(e);
+         }
+
+         @Override
+         public void widgetSelected(SelectionEvent e)
+         {
+            moveSelection(true);
+         }
+      });
+      
+      moveDownButton = new Button(buttonsLeft, SWT.PUSH);
+      moveDownButton.setText("&Down");
+      rd = new RowData();
+      rd.width = WidgetHelper.BUTTON_WIDTH_HINT;
+      moveDownButton.setLayoutData(rd);
+      moveDownButton.addSelectionListener(new SelectionListener() {
+         @Override
+         public void widgetDefaultSelected(SelectionEvent e)
+         {
+            widgetSelected(e);
+         }
+
+         @Override
+         public void widgetSelected(SelectionEvent e)
+         {
+            moveSelection(false);
+         }
+      });
+      
+      Composite buttonsRight = new Composite(dialogArea, SWT.NONE);
+      buttonLayout = new RowLayout();
+      buttonLayout.type = SWT.HORIZONTAL;
+      buttonLayout.pack = false;
+      buttonLayout.marginWidth = 0;
+      buttonLayout.marginRight = 0;
+      buttonsRight.setLayout(buttonLayout);
       gridData = new GridData();
       gridData.horizontalAlignment = SWT.RIGHT;
-      buttons.setLayoutData(gridData);
+      buttonsRight.setLayoutData(gridData);
 
-      addButton = new Button(buttons, SWT.PUSH);
+      addButton = new Button(buttonsRight, SWT.PUSH);
       addButton.setText(Messages.get().CustomAttributes_Add);
-      RowData rd = new RowData();
+      rd = new RowData();
       rd.width = WidgetHelper.BUTTON_WIDTH_HINT;
       addButton.setLayoutData(rd);
       addButton.addSelectionListener(new SelectionListener() {
@@ -150,25 +185,11 @@ public class CustomAttributes extends PropertyPage
                        @Override
                        public void widgetSelected(SelectionEvent e)
                        {
-                               final AttributeEditDialog dlg = new AttributeEditDialog(CustomAttributes.this.getShell(), null, null);
-                               if (dlg.open() == Window.OK)
-                               {
-                                       if (attributes.containsKey(dlg.getAttrName()))
-                                       {
-                                               MessageDialogHelper.openWarning(CustomAttributes.this.getShell(), Messages.get().CustomAttributes_Warning, 
-                                                     String.format(Messages.get().CustomAttributes_WarningAlreadyExist, dlg.getAttrName()));
-                                       }
-                                       else
-                                       {
-                                               attributes.put(dlg.getAttrName(), dlg.getAttrValue());
-                                     viewer.setInput(attributes.entrySet());
-                                     CustomAttributes.this.isModified = true;
-                                       }
-                               }
+                          addUrl();
                        }
       });
                
-      editButton = new Button(buttons, SWT.PUSH);
+      editButton = new Button(buttonsRight, SWT.PUSH);
       editButton.setText(Messages.get().CustomAttributes_Modify);
       rd = new RowData();
       rd.width = WidgetHelper.BUTTON_WIDTH_HINT;
@@ -180,26 +201,14 @@ public class CustomAttributes extends PropertyPage
                                widgetSelected(e);
                        }
 
-                       @SuppressWarnings("unchecked")
                        @Override
                        public void widgetSelected(SelectionEvent e)
                        {
-                               IStructuredSelection selection = (IStructuredSelection)viewer.getSelection();
-                               if (selection.size() == 1)
-                               {
-                                       Entry<String, String> element = (Entry<String, String>)selection.getFirstElement();
-                                       final AttributeEditDialog dlg = new AttributeEditDialog(CustomAttributes.this.getShell(), element.getKey(), element.getValue());
-                                       if (dlg.open() == Window.OK)
-                                       {
-                                               attributes.put(dlg.getAttrName(), dlg.getAttrValue());
-                                     viewer.setInput(attributes.entrySet());
-                                     CustomAttributes.this.isModified = true;
-                                       }
-                               }
+                          editUrl();
                        }
       });
                
-      deleteButton = new Button(buttons, SWT.PUSH);
+      deleteButton = new Button(buttonsRight, SWT.PUSH);
       deleteButton.setText(Messages.get().CustomAttributes_Delete);
       rd = new RowData();
       rd.width = WidgetHelper.BUTTON_WIDTH_HINT;
@@ -211,22 +220,10 @@ public class CustomAttributes extends PropertyPage
                                widgetSelected(e);
                        }
 
-                       @SuppressWarnings("unchecked")
                        @Override
                        public void widgetSelected(SelectionEvent e)
                        {
-                               IStructuredSelection selection = (IStructuredSelection)viewer.getSelection();
-                               Iterator<Entry<String, String>> it = selection.iterator();
-                               if (it.hasNext())
-                               {
-                                       while(it.hasNext())
-                                       {
-                                               Entry<String, String> element = it.next();
-                                               attributes.remove(element.getKey());
-                                       }
-                             viewer.setInput(attributes.entrySet());
-                             CustomAttributes.this.isModified = true;
-                               }
+                          deleteUrl();
                        }
       });
                
@@ -243,13 +240,97 @@ public class CustomAttributes extends PropertyPage
                        public void selectionChanged(SelectionChangedEvent event)
                        {
                                IStructuredSelection selection = (IStructuredSelection)viewer.getSelection();
-                               editButton.setEnabled(selection.size() == 1);
+                               moveUpButton.setEnabled(selection.size() == 1);
+            moveDownButton.setEnabled(selection.size() == 1);
+            editButton.setEnabled(selection.size() == 1);
                                deleteButton.setEnabled(selection.size() > 0);
                        }
                });
       
                return dialogArea;
        }
+       
+       /**
+        * Add new URL
+        */
+       private void addUrl()
+       {
+          ObjectUrlEditDialog dlg = new ObjectUrlEditDialog(getShell(), null, null);
+          if (dlg.open() != Window.OK)
+             return;
+          
+          urls.add(new ObjectUrl(urls.size(), dlg.getUrl(), dlg.getDescription()));
+          viewer.refresh();
+          modified = true;
+       }
+       
+       /**
+        * Edit selected URL 
+        */
+       private void editUrl()
+       {
+      IStructuredSelection selection = (IStructuredSelection)viewer.getSelection();
+          if (selection.size() != 1)
+             return;
+
+          ObjectUrl url = (ObjectUrl)selection.getFirstElement();
+      ObjectUrlEditDialog dlg = new ObjectUrlEditDialog(getShell(), url.getUrl(), url.getDescription());
+      if (dlg.open() != Window.OK)
+         return;
+
+      int index = urls.indexOf(url);
+      urls.set(index, new ObjectUrl(url.getId(), dlg.getUrl(), dlg.getDescription()));
+      viewer.refresh();
+      viewer.setSelection(new StructuredSelection(urls.get(index)));
+      modified = true;
+       }
+       
+       /**
+        * Delete selected URLs
+        */
+       private void deleteUrl()
+       {
+      IStructuredSelection selection = (IStructuredSelection)viewer.getSelection();
+      if (selection.isEmpty())
+         return;
+      
+          for(Object o : selection.toList())
+             urls.remove(o);
+          for(int i = 0; i < urls.size(); i++)
+          {
+             ObjectUrl u = urls.get(i);
+             urls.set(i, new ObjectUrl(i, u.getUrl(), u.getDescription()));
+          }
+      viewer.refresh();
+      modified = true;
+       }
+       
+       /**
+        * Move selection
+        * 
+        * @param up
+        */
+       private void moveSelection(boolean up)
+       {
+      IStructuredSelection selection = (IStructuredSelection)viewer.getSelection();
+      if (selection.size() != 1)
+         return;
+
+      ObjectUrl url = (ObjectUrl)selection.getFirstElement();
+      int index = urls.indexOf(url);
+      if (((index == 0) && up) || ((index == urls.size() - 1) && !up))
+         return;
+      
+      int swapIndex = up ? index - 1 : index + 1;
+      ObjectUrl swapUrl = urls.get(swapIndex);
+      
+      urls.set(index, new ObjectUrl(index, swapUrl.getUrl(), swapUrl.getDescription()));
+      urls.set(swapIndex, new ObjectUrl(index, url.getUrl(), url.getDescription()));
+      
+      viewer.refresh();
+      viewer.setSelection(new StructuredSelection(urls.get(swapIndex)));
+      modified = true;
+       }
 
        /**
         * Apply changes
@@ -258,27 +339,27 @@ public class CustomAttributes extends PropertyPage
         */
        protected void applyChanges(final boolean isApply)
        {
-               if (!isModified)
+               if (!modified)
                        return;         // Nothing to apply
                
                if (isApply)
                        setValid(false);
                
                final NXCObjectModificationData md = new NXCObjectModificationData(object.getObjectId());
-               md.setCustomAttributes(attributes);
+               md.setUrls(new ArrayList<ObjectUrl>(urls));
                final NXCSession session = (NXCSession)ConsoleSharedData.getSession();
                new ConsoleJob(Messages.get().CustomAttributes_JobName, null, Activator.PLUGIN_ID, null) {
                        @Override
                        protected void runInternal(IProgressMonitor monitor) throws Exception
                        {
                                session.modifyObject(md);
-                               isModified = false;
+                               modified = false;
                        }
 
                        @Override
                        protected String getErrorMessage()
                        {
-                               return Messages.get().CustomAttributes_JobError;
+                               return "Cannot update object's URL list";
                        }
 
                        @Override
@@ -290,7 +371,7 @@ public class CustomAttributes extends PropertyPage
                                                @Override
                                                public void run()
                                                {
-                                                       CustomAttributes.this.setValid(true);
+                                                       ExternalResources.this.setValid(true);
                                                }
                                        });
                                }
diff --git a/webui/webapp/ObjectManager/src/org/netxms/ui/eclipse/objectmanager/propertypages/helpers/UrlListLabelProvider.java b/webui/webapp/ObjectManager/src/org/netxms/ui/eclipse/objectmanager/propertypages/helpers/UrlListLabelProvider.java
new file mode 100644 (file)
index 0000000..c19303d
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ * NetXMS - open source network management system
+ * Copyright (C) 2003-2017 Victor Kirhenshtein
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+package org.netxms.ui.eclipse.objectmanager.propertypages.helpers;
+
+import java.net.URL;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.swt.graphics.Image;
+import org.netxms.client.ObjectUrl;
+
+/**
+ * Label provider for URL list
+ */
+public class UrlListLabelProvider extends LabelProvider implements ITableLabelProvider
+{
+   /* (non-Javadoc)
+    * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int)
+    */
+   @Override
+   public Image getColumnImage(Object element, int columnIndex)
+   {
+      return null;
+   }
+
+   /* (non-Javadoc)
+    * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int)
+    */
+   @Override
+   public String getColumnText(Object element, int columnIndex)
+   {
+      switch(columnIndex)
+      {
+         case 0:
+            URL url = ((ObjectUrl)element).getUrl(); 
+            return (url != null) ? url.toExternalForm() : "";
+         case 1:
+            return ((ObjectUrl)element).getDescription();
+      }
+      return null;
+   }
+}
index 66553f9..68c256b 100644 (file)
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: NXMC Object Viewer Plug-in
 Bundle-SymbolicName: org.netxms.ui.eclipse.objectview;singleton:=true
-Bundle-Version: 2.0.7
+Bundle-Version: 2.1.0
 Bundle-Activator: org.netxms.ui.eclipse.objectview.Activator
 Bundle-Vendor: netxms.org
 Require-Bundle: org.netxms.ui.eclipse.charts;bundle-version="2.0.4",
@@ -11,7 +11,8 @@ Require-Bundle: org.netxms.ui.eclipse.charts;bundle-version="2.0.4",
  org.netxms.ui.eclipse.clientlibrary;bundle-version="2.0.7",
  org.netxms.ui.eclipse.objecttools;bundle-version="2.0.6",
  org.netxms.ui.eclipse.imagelibrary;bundle-version="2.0.0",
- org.netxms.ui.eclipse.objectbrowser;bundle-version="2.0.7"
+ org.netxms.ui.eclipse.objectbrowser;bundle-version="2.0.7",
+ org.eclipse.rap.ui.forms;bundle-version="3.1.0"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.6
 Bundle-ActivationPolicy: lazy
 Export-Package: org.netxms.ui.eclipse.objectview.api,
index 1da53e6..a8a86aa 100644 (file)
@@ -37,6 +37,7 @@ import org.netxms.ui.eclipse.objectview.objecttabs.elements.Capabilities;
 import org.netxms.ui.eclipse.objectview.objecttabs.elements.Commands;
 import org.netxms.ui.eclipse.objectview.objecttabs.elements.Comments;
 import org.netxms.ui.eclipse.objectview.objecttabs.elements.Connection;
+import org.netxms.ui.eclipse.objectview.objecttabs.elements.ExternalResources;
 import org.netxms.ui.eclipse.objectview.objecttabs.elements.GeneralInfo;
 import org.netxms.ui.eclipse.objectview.objecttabs.elements.LastValues;
 import org.netxms.ui.eclipse.objectview.objecttabs.elements.OverviewPageElement;
@@ -100,11 +101,13 @@ public class ObjectOverview extends ObjectTab
                OverviewPageElement e = new GeneralInfo(leftColumn, null, this);
                elements.add(e);
       e = new LastValues(leftColumn, e, this);
-               elements.add(e);
+      elements.add(e);
                e = new Commands(leftColumn, e, this);
                elements.add(e);
                e = new AvailabilityChart(leftColumn, e, this);
                elements.add(e);
+      e = new ExternalResources(leftColumn, e, this);
+      elements.add(e);
                e = new Comments(leftColumn, e, this);
                elements.add(e);
                e = new Capabilities(rightColumn, null, this);
diff --git a/webui/webapp/ObjectView/src/org/netxms/ui/eclipse/objectview/objecttabs/elements/ExternalResources.java b/webui/webapp/ObjectView/src/org/netxms/ui/eclipse/objectview/objecttabs/elements/ExternalResources.java
new file mode 100644 (file)
index 0000000..aae500a
--- /dev/null
@@ -0,0 +1,137 @@
+/**
+ * 
+ */
+package org.netxms.ui.eclipse.objectview.objecttabs.elements;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.client.service.UrlLauncher;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.forms.events.HyperlinkAdapter;
+import org.eclipse.ui.forms.events.HyperlinkEvent;
+import org.eclipse.ui.forms.widgets.Hyperlink;
+import org.netxms.client.ObjectUrl;
+import org.netxms.client.objects.AbstractObject;
+import org.netxms.ui.eclipse.console.resources.SharedColors;
+import org.netxms.ui.eclipse.objectview.objecttabs.ObjectTab;
+
+/**
+ * @author victor
+ *
+ */
+public class ExternalResources extends OverviewPageElement
+{
+   private Composite content;
+   private List<Element> elements = new ArrayList<Element>();
+   
+   /**
+    * @param parent
+    * @param anchor
+    * @param objectTab
+    */
+   public ExternalResources(Composite parent, OverviewPageElement anchor, ObjectTab objectTab)
+   {
+      super(parent, anchor, objectTab);
+   }
+
+   /* (non-Javadoc)
+    * @see org.netxms.ui.eclipse.objectview.objecttabs.elements.OverviewPageElement#getTitle()
+    */
+   @Override
+   protected String getTitle()
+   {
+      return "External Resources";
+   }
+
+   /* (non-Javadoc)
+    * @see org.netxms.ui.eclipse.objectview.objecttabs.elements.OverviewPageElement#isApplicableForObject(org.netxms.client.objects.AbstractObject)
+    */
+   @Override
+   public boolean isApplicableForObject(AbstractObject object)
+   {
+      return object.hasUrls();
+   }
+
+   /* (non-Javadoc)
+    * @see org.netxms.ui.eclipse.objectview.objecttabs.elements.OverviewPageElement#createClientArea(org.eclipse.swt.widgets.Composite)
+    */
+   @Override
+   protected Control createClientArea(Composite parent)
+   {
+      content = new Composite(parent, SWT.NONE);
+      GridLayout layout = new GridLayout();
+      layout.numColumns = 2;
+      content.setLayout(layout);
+      content.setBackground(SharedColors.getColor(SharedColors.OBJECT_TAB_BACKGROUND, parent.getDisplay()));
+      return content;
+   }
+
+   /* (non-Javadoc)
+    * @see org.netxms.ui.eclipse.objectview.objecttabs.elements.OverviewPageElement#onObjectChange()
+    */
+   @Override
+   protected void onObjectChange()
+   {
+      for(Element e : elements)
+         e.dispose();
+      elements.clear();
+      for(ObjectUrl u : getObject().getUrls())
+         elements.add(new Element(content, u));
+      content.layout();
+   }
+   
+   /**
+    * Open URL
+    * 
+    * @param url URL to open
+    */
+   private void openUrl(URL url)
+   {
+      final UrlLauncher launcher = RWT.getClient().getService(UrlLauncher.class);
+      launcher.openURL(url.toExternalForm());
+   }
+   
+   /**
+    * Display element
+    */
+   private class Element
+   {
+      ObjectUrl url;
+      Hyperlink link;
+      Label description;
+      
+      Element(Composite parent, ObjectUrl url)
+      {
+         this.url = url;
+         
+         link = new Hyperlink(parent, SWT.NONE);
+         link.setBackground(content.getBackground());
+         link.setForeground(SharedColors.getColor(SharedColors.COMMAND_BOX_TEXT, link.getDisplay()));
+         link.setText(url.getUrl().toExternalForm());
+         link.addHyperlinkListener(new HyperlinkAdapter() {
+            @Override
+            public void linkActivated(HyperlinkEvent e)
+            {
+               openUrl(Element.this.url.getUrl());
+            }
+            
+         });
+         
+         description = new Label(parent, SWT.NONE);
+         description.setBackground(content.getBackground());
+         description.setText(url.getDescription());
+      }
+      
+      void dispose()
+      {
+         link.dispose();
+         description.dispose();
+      }
+   }
+}