Implemented rear view for racks. Fixes #NX-1142
authorEriks Jenkevics <eriks@netxms.org>
Thu, 23 Nov 2017 15:15:03 +0000 (17:15 +0200)
committerEriks Jenkevics <eriks@netxms.org>
Thu, 23 Nov 2017 15:52:07 +0000 (17:52 +0200)
24 files changed:
include/netxmsdb.h
include/nms_cscp.h
sql/schema.in
src/client/java/netxms-client/src/main/java/org/netxms/client/NXCObjectModificationData.java
src/client/java/netxms-client/src/main/java/org/netxms/client/NXCSession.java
src/client/java/netxms-client/src/main/java/org/netxms/client/objects/AbstractNode.java
src/client/java/netxms-client/src/main/java/org/netxms/client/objects/Chassis.java
src/client/java/netxms-client/src/main/java/org/netxms/client/objects/RackElement.java
src/java/netxms-eclipse/Dashboard/src/org/netxms/ui/eclipse/dashboard/widgets/RackDiagramElement.java
src/java/netxms-eclipse/ObjectManager/src/org/netxms/ui/eclipse/objectmanager/propertypages/RackPlacement.java
src/java/netxms-eclipse/ObjectView/icons/rack-default-rear.png [new file with mode: 0644]
src/java/netxms-eclipse/ObjectView/src/org/netxms/ui/eclipse/objectview/objecttabs/RackTab.java
src/java/netxms-eclipse/ObjectView/src/org/netxms/ui/eclipse/objectview/widgets/RackWidget.java
src/java/netxms-eclipse/ServerConfig/src/org/netxms/ui/eclipse/serverconfig/views/ExportFileBuilder.java
src/libnxjava/java/base/netxms-base/src/main/java/org/netxms/base/NXCPCodes.java
src/server/core/chassis.cpp
src/server/core/node.cpp
src/server/include/nms_objects.h
src/server/tools/nxdbmgr/upgrade_v30.cpp
webui/webapp/Dashboard/src/org/netxms/ui/eclipse/dashboard/widgets/RackDiagramElement.java
webui/webapp/ObjectManager/src/org/netxms/ui/eclipse/objectmanager/propertypages/RackPlacement.java
webui/webapp/ObjectView/icons/rack-default-rear.png [new file with mode: 0644]
webui/webapp/ObjectView/src/org/netxms/ui/eclipse/objectview/objecttabs/RackTab.java
webui/webapp/ObjectView/src/org/netxms/ui/eclipse/objectview/widgets/RackWidget.java

index 5ef464b..7a532a0 100644 (file)
@@ -25,7 +25,7 @@
 
 #define DB_LEGACY_SCHEMA_VERSION       700
 #define DB_SCHEMA_VERSION_MAJOR        30
-#define DB_SCHEMA_VERSION_MINOR        13
+#define DB_SCHEMA_VERSION_MINOR        14
 
 #define DB_SCHEMA_VERSION_V30_MINOR    DB_SCHEMA_VERSION_MINOR
 
index a90d945..cc2042c 100644 (file)
@@ -1218,6 +1218,7 @@ typedef struct
 #define VID_INCLUDE_RAW_VALUES      ((UINT32)608)
 #define VID_JOB_CANCELED            ((UINT32)609)
 #define VID_INSTANCE_RETENTION      ((UINT32)610)
+#define VID_RACK_ORIENTATION        ((UINT32)611)
 
 // Base variabe for single threshold in message
 #define VID_THRESHOLD_BASE          ((UINT32)0x00800000)
index 377904f..7bcac71 100644 (file)
@@ -274,6 +274,7 @@ CREATE TABLE chassis
   rack_image varchar(36) null,
   rack_position integer not null,
   rack_height integer not null,
+  rack_orientation integer not null,
   PRIMARY KEY(id)
 ) TABLE_TYPE;
 
index 3b0d877..8720a1a 100644 (file)
@@ -232,6 +232,7 @@ public class NXCObjectModificationData
    private long sensorProxy;
    private String xmlConfig;
    private List<String> snmpPorts;
+   private short rackOrientation;
        
        /**
         * Constructor for creating modification data for given object
@@ -1624,12 +1625,13 @@ public class NXCObjectModificationData
     * @param rackPosition The rack position to set
     * @param rackHeight the rack height to set
     */
-   public void setRackPlacement(long rackId, UUID rackImage, short rackPosition, short rackHeight)
+   public void setRackPlacement(long rackId, UUID rackImage, short rackPosition, short rackHeight, short rackOrientation)
    {
       this.rackId = rackId;
       this.rackImage = rackImage;
       this.rackPosition = rackPosition;
       this.rackHeight = rackHeight;
+      this.rackOrientation = rackOrientation;
       fieldSet.add(RACK_PLACEMENT);
    }
 
@@ -1953,4 +1955,22 @@ public class NXCObjectModificationData
    {
       return snmpPorts;
    }
+   
+   /**
+    * Set rack orientation
+    * @param rackOrientation to set
+    */
+   public void setRackOrientation(short rackOrientation)
+   {
+      this.rackOrientation = rackOrientation;
+   }
+   
+   /**
+    * Get rack orientation
+    * @return rack orientation
+    */
+   public short getRackOrientation()
+   {
+      return rackOrientation;
+   }
 }
index 3f7f2c0..30594f2 100644 (file)
@@ -5080,6 +5080,7 @@ public class NXCSession
          msg.setField(NXCPCodes.VID_RACK_IMAGE, data.getRackImage());
          msg.setFieldInt16(NXCPCodes.VID_RACK_POSITION, data.getRackPosition());
          msg.setFieldInt16(NXCPCodes.VID_RACK_HEIGHT, data.getRackHeight());
+         msg.setFieldInt16(NXCPCodes.VID_RACK_ORIENTATION, data.getRackOrientation());
       }
 
       if (data.isFieldSet(NXCObjectModificationData.DASHBOARD_LIST))
index 84f3dab..47b5079 100644 (file)
@@ -138,6 +138,7 @@ public abstract class AbstractNode extends DataCollectionTarget implements RackE
    protected long sshProxyId;
    protected int portRowCount;
    protected int portNumberingScheme;
+   protected int rackOrientation;
        
        /**
         * Create new node object.
@@ -209,6 +210,7 @@ public abstract class AbstractNode extends DataCollectionTarget implements RackE
       sshProxyId = msg.getFieldAsInt64(NXCPCodes.VID_SSH_PROXY);
       portRowCount = msg.getFieldAsInt16(NXCPCodes.VID_PORT_ROW_COUNT);
       portNumberingScheme = msg.getFieldAsInt16(NXCPCodes.VID_PORT_NUMBERING_SCHEME);
+      rackOrientation = msg.getFieldAsInt16(NXCPCodes.VID_RACK_ORIENTATION);
                
                long bootTimeSeconds = msg.getFieldAsInt64(NXCPCodes.VID_BOOT_TIME);
                bootTime = (bootTimeSeconds > 0) ? new Date(bootTimeSeconds * 1000) : null;
@@ -788,4 +790,20 @@ public abstract class AbstractNode extends DataCollectionTarget implements RackE
       addString(strings, platformName);
       return strings;
    }
+   
+   /* (non-Javadoc)
+    * @see org.netxms.client.objects.RackElement#getRackOrientation()
+    */
+   public int getRackOrientation()
+   {
+      return rackOrientation;
+   }
+   
+   /* (non-Javadoc)
+    * @see org.netxms.client.objects.RackElement#setRackOrientation(int)
+    */
+   public void setRackOrientation(int rackOrientation)
+   {
+      this.rackOrientation = rackOrientation;
+   }
 }
index d3e20cd..db16a62 100644 (file)
@@ -33,6 +33,7 @@ public class Chassis extends DataCollectionTarget implements RackElement
    protected UUID rackImage;
    protected short rackPosition;
    protected short rackHeight;
+   protected int rackOrientation;
 
    /**
     * @param msg
@@ -46,6 +47,7 @@ public class Chassis extends DataCollectionTarget implements RackElement
       rackImage = msg.getFieldAsUUID(NXCPCodes.VID_RACK_IMAGE);
       rackPosition = msg.getFieldAsInt16(NXCPCodes.VID_RACK_POSITION);
       rackHeight = msg.getFieldAsInt16(NXCPCodes.VID_RACK_HEIGHT);
+      rackOrientation = msg.getFieldAsInt16(NXCPCodes.VID_RACK_ORIENTATION);
    }
 
    /* (non-Javadoc)
@@ -109,4 +111,22 @@ public class Chassis extends DataCollectionTarget implements RackElement
    {
       return rackHeight;
    }
+
+   /* (non-Javadoc)
+    * @see org.netxms.client.objects.RackElement#getRackOrientation()
+    */
+   @Override
+   public int getRackOrientation()
+   {
+      return rackOrientation;
+   }
+
+   /* (non-Javadoc)
+    * @see org.netxms.client.objects.RackElement#setRackOrientation(int)
+    */
+   @Override
+   public void setRackOrientation(int rackOrientation)
+   {
+      this.rackOrientation = rackOrientation;
+   }
 }
index 1a81c0a..9f89fae 100644 (file)
@@ -26,6 +26,10 @@ import org.netxms.client.constants.ObjectStatus;
  */
 public interface RackElement
 {
+   public static final int RACK_POSITION_FRONT = 0;
+   public static final int RACK_POSITION_REAR = 1;
+   public static final int RACK_POSITION_FILL = 2;
+   
    /**
     * Get object ID
     * 
@@ -74,4 +78,18 @@ public interface RackElement
     * @return device height in rack units
     */
    public short getRackHeight();
+   
+   /**
+    * Get orientation of object in rack
+    * 
+    * @return orientation of object in rack
+    */
+   public int getRackOrientation();
+   
+   /**
+    * Set orientation of object in rack
+    * 
+    * @param rackOrientation to set
+    */
+   public void setRackOrientation(int rackOrientation);
 }
index 50bec5e..d77f1a7 100644 (file)
 package org.netxms.ui.eclipse.dashboard.widgets;
 
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
 import org.eclipse.ui.IViewPart;
 import org.netxms.client.NXCSession;
 import org.netxms.client.dashboards.DashboardElement;
 import org.netxms.client.objects.Rack;
+import org.netxms.ui.eclipse.console.resources.SharedColors;
 import org.netxms.ui.eclipse.dashboard.widgets.internal.RackDiagramConfig;
 import org.netxms.ui.eclipse.objectview.widgets.RackWidget;
 import org.netxms.ui.eclipse.shared.ConsoleSharedData;
@@ -33,9 +38,11 @@ import org.netxms.ui.eclipse.shared.ConsoleSharedData;
  */
 public class RackDiagramElement extends ElementWidget
 {
-   private RackWidget rackWidget;
+   private RackWidget rackFrontWidget;
+   private RackWidget rackRearWidget;
    private NXCSession session;
    private RackDiagramConfig config;
+   private Composite rackArea;
 
    /**
     * Create new rack diagram element
@@ -62,30 +69,77 @@ public class RackDiagramElement extends ElementWidget
       Rack rack = session.findObjectById(config.getObjectId(), Rack.class);
       
       if (rack != null)
-         setRackWidget(new RackWidget(this, SWT.NONE, rack));
-      
-      FillLayout layout = new FillLayout();
-      layout.marginHeight = 0;
-      layout.marginWidth = 0;
-      setLayout(layout);
+      {
+         rackArea = new Composite(this, SWT.NONE) {
+            @Override
+            public Point computeSize(int wHint, int hHint, boolean changed)
+            {
+               if ((rackFrontWidget == null) || (rackRearWidget == null) || (hHint == SWT.DEFAULT))
+                  return super.computeSize(wHint, hHint, changed);
+               
+               Point s = rackFrontWidget.computeSize(wHint, hHint, changed);
+               return new Point(s.x * 2, s.y);
+            }
+         };
+         rackArea.setBackground(SharedColors.getColor(SharedColors.RACK_BACKGROUND, parent.getDisplay()));
+         rackArea.addControlListener(new ControlAdapter() {
+            @Override
+            public void controlResized(ControlEvent e)
+            {
+               if ((rackFrontWidget == null) || (rackRearWidget == null))
+                  return;
+               
+               int height = rackArea.getSize().y;
+               Point size = rackFrontWidget.computeSize(SWT.DEFAULT, height, true);
+               rackFrontWidget.setSize(size);
+               rackRearWidget.setSize(size);
+               rackRearWidget.setLocation(size.x, 0);
+            }
+         });
+         
+         setRackFrontWidget(new RackWidget(rackArea, SWT.NONE, rack, RackWidget.RACK_FRONT_VIEW));
+         setRackRearWidget(new RackWidget(rackArea, SWT.NONE, rack, RackWidget.RACK_REAR_VIEW));
+      }
+      setLayout(new FillLayout());
+   }
+
+   /**
+    * Get rear rack widget
+    * 
+    * @return Rear rack widget
+    */
+   public RackWidget getRackRearWidget()
+   {
+      return rackRearWidget;
    }
 
    /**
-    * Get rack widget
-    * @return rack widget
+    * Set rear rack widget
+    * 
+    * @param rackRearWidget to set
     */
-   public RackWidget getRackWidget()
+   public void setRackRearWidget(RackWidget rackRearWidget)
    {
-      return rackWidget;
+      this.rackRearWidget = rackRearWidget;
    }
 
    /**
-    * Set rack widget
-    * @param rackWidget to set
+    * Get front rack widget
+    * 
+    * @return Front rack widget
     */
-   public void setRackWidget(RackWidget rackWidget)
+   public RackWidget getRackFrontWidget()
    {
-      this.rackWidget = rackWidget;
+      return rackFrontWidget;
    }
 
+   /**
+    * Set front rack widget
+    * 
+    * @param rackFrontWidget to set
+    */
+   public void setRackFrontWidget(RackWidget rackFrontWidget)
+   {
+      this.rackFrontWidget = rackFrontWidget;
+   }
 }
index e16aa48..a36fe9b 100644 (file)
@@ -22,6 +22,7 @@ import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Combo;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
 import org.eclipse.ui.dialogs.PropertyPage;
@@ -44,11 +45,14 @@ import org.netxms.ui.eclipse.widgets.LabeledSpinner;
  */
 public class RackPlacement extends PropertyPage
 {
+   private final static String[] ORIENTATION = { "Front", "Rear", "Fill" };
+   
        private RackElement object;
        private ObjectSelector rackSelector;
        private ImageSelector rackImageSelector;
        private LabeledSpinner rackHeight;
        private LabeledSpinner rackPosition;
+       private Combo rackOrientation;
        
        /* (non-Javadoc)
         * @see org.eclipse.jface.preference.PreferencePage#createContents(org.eclipse.swt.widgets.Composite)
@@ -64,7 +68,7 @@ public class RackPlacement extends PropertyPage
                layout.verticalSpacing = WidgetHelper.OUTER_SPACING;
                layout.marginWidth = 0;
                layout.marginHeight = 0;
-               layout.numColumns = 2;
+               layout.numColumns = 3;
       dialogArea.setLayout(layout);
 
       rackSelector = new ObjectSelector(dialogArea, SWT.NONE, true);
@@ -74,7 +78,7 @@ public class RackPlacement extends PropertyPage
                GridData gd = new GridData();
                gd.grabExcessHorizontalSpace = true;
                gd.horizontalAlignment = SWT.FILL;
-               gd.horizontalSpan = 2;
+               gd.horizontalSpan = 3;
                rackSelector.setLayoutData(gd);
                
                rackImageSelector = new ImageSelector(dialogArea, SWT.NONE);
@@ -83,7 +87,7 @@ public class RackPlacement extends PropertyPage
       gd = new GridData();
       gd.grabExcessHorizontalSpace = true;
       gd.horizontalAlignment = SWT.FILL;
-      gd.horizontalSpan = 2;
+      gd.horizontalSpan = 3;
       rackImageSelector.setLayoutData(gd);
       
       rackPosition = new LabeledSpinner(dialogArea, SWT.NONE);
@@ -104,6 +108,14 @@ public class RackPlacement extends PropertyPage
       gd.horizontalAlignment = SWT.FILL;
       rackHeight.setLayoutData(gd);
       
+      gd = new GridData();
+      gd.grabExcessHorizontalSpace = true;
+      gd.horizontalAlignment = SWT.FILL;
+      rackHeight.setLayoutData(gd);
+      rackOrientation = WidgetHelper.createLabeledCombo(dialogArea, SWT.READ_ONLY, "Orientation", gd);
+      rackOrientation.setItems(ORIENTATION);
+      rackOrientation.setText(ORIENTATION[object.getRackOrientation()]);
+      
                return dialogArea;
        }
 
@@ -118,7 +130,8 @@ public class RackPlacement extends PropertyPage
                        setValid(false);
                
                final NXCObjectModificationData md = new NXCObjectModificationData(object.getObjectId());
-               md.setRackPlacement(rackSelector.getObjectId(), rackImageSelector.getImageGuid(), (short)rackPosition.getSelection(), (short)rackHeight.getSelection());
+               md.setRackPlacement(rackSelector.getObjectId(), rackImageSelector.getImageGuid(), (short)rackPosition.getSelection(), (short)rackHeight.getSelection(),
+                                   (short)rackOrientation.getSelectionIndex());
                
                final NXCSession session = (NXCSession)ConsoleSharedData.getSession();
                new ConsoleJob(String.format(Messages.get().RackPlacement_UpdatingRackPlacement, object.getObjectName()), null, Activator.PLUGIN_ID, null) {
diff --git a/src/java/netxms-eclipse/ObjectView/icons/rack-default-rear.png b/src/java/netxms-eclipse/ObjectView/icons/rack-default-rear.png
new file mode 100644 (file)
index 0000000..356e509
Binary files /dev/null and b/src/java/netxms-eclipse/ObjectView/icons/rack-default-rear.png differ
index 2774f82..b7004f5 100644 (file)
@@ -32,7 +32,7 @@ import org.eclipse.swt.SWT;
 import org.eclipse.swt.custom.ScrolledComposite;
 import org.eclipse.swt.events.ControlAdapter;
 import org.eclipse.swt.events.ControlEvent;
-import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Menu;
 import org.netxms.client.objects.AbstractObject;
@@ -49,7 +49,8 @@ public class RackTab extends ObjectTab implements ISelectionProvider
 {
    private ScrolledComposite scroller;
    private Composite content;
-   private RackWidget rackWidget;
+   private RackWidget rackFrontWidget;
+   private RackWidget rackRearWidget;
    private ISelection selection = new StructuredSelection();
    private Set<ISelectionChangedListener> selectionListeners = new HashSet<ISelectionChangedListener>();
    
@@ -61,9 +62,32 @@ public class RackTab extends ObjectTab implements ISelectionProvider
        {
           scroller = new ScrolledComposite(parent, SWT.H_SCROLL);
           
-          content = new Composite(scroller, SWT.NONE);
-          content.setLayout(new FillLayout());
+          content = new Composite(scroller, SWT.NONE) {
+         @Override
+         public Point computeSize(int wHint, int hHint, boolean changed)
+         {
+            if ((rackFrontWidget == null) || (rackRearWidget == null) || (hHint == SWT.DEFAULT))
+               return super.computeSize(wHint, hHint, changed);
+            
+            Point s = rackFrontWidget.computeSize(wHint, hHint, changed);
+            return new Point(s.x * 2, s.y);
+         }
+          };
           content.setBackground(SharedColors.getColor(SharedColors.RACK_BACKGROUND, parent.getDisplay()));
+          content.addControlListener(new ControlAdapter() {
+         @Override
+         public void controlResized(ControlEvent e)
+         {
+            if ((rackFrontWidget == null) || (rackRearWidget == null))
+               return;
+            
+            int height = content.getSize().y;
+            Point size = rackFrontWidget.computeSize(SWT.DEFAULT, height, true);
+            rackFrontWidget.setSize(size);
+            rackRearWidget.setSize(size);
+            rackRearWidget.setLocation(size.x, 0);
+         }
+      });
           
           scroller.setContent(content);
       scroller.setExpandHorizontal(true);
@@ -93,8 +117,11 @@ public class RackTab extends ObjectTab implements ISelectionProvider
       });
 
       // Create menu.
-      Menu menu = menuMgr.createContextMenu(rackWidget);
-      rackWidget.setMenu(menu);
+      Menu menu = menuMgr.createContextMenu(rackFrontWidget);
+      rackFrontWidget.setMenu(menu);
+      
+      menu = menuMgr.createContextMenu(rackRearWidget);
+      rackRearWidget.setMenu(menu);
 
       // Register menu for extension.
       getViewPart().getSite().registerContextMenu(menuMgr, this);
@@ -133,18 +160,20 @@ public class RackTab extends ObjectTab implements ISelectionProvider
        @Override
        public void objectChanged(final AbstractObject object)
        {
-      if (rackWidget != null)
+      if (rackFrontWidget != null)
+      {
+         rackFrontWidget.dispose();
+         rackFrontWidget = null;
+      }
+      if (rackRearWidget != null)
       {
-         rackWidget.dispose();
-         rackWidget = null;
+         rackRearWidget.dispose();
+         rackRearWidget = null;
       }
 
       if (object != null)
           {
-             rackWidget = new RackWidget(content, SWT.NONE, (Rack)object);
-             content.layout(true, true);
-         scroller.setMinSize(content.computeSize(SWT.DEFAULT, scroller.getSize().y));
-         rackWidget.addSelectionListener(new RackSelectionListener() {
+         RackSelectionListener listener = new RackSelectionListener() {
             @Override
             public void objectSelected(AbstractObject object)
             {
@@ -152,7 +181,15 @@ public class RackTab extends ObjectTab implements ISelectionProvider
                for(ISelectionChangedListener listener : selectionListeners)
                   listener.selectionChanged(new SelectionChangedEvent(RackTab.this, selection));
             }
-         });
+         };
+         
+         rackFrontWidget = new RackWidget(content, SWT.NONE, (Rack)object, RackWidget.RACK_FRONT_VIEW);
+         rackFrontWidget.addSelectionListener(listener);
+
+         rackRearWidget = new RackWidget(content, SWT.NONE, (Rack)object, RackWidget.RACK_REAR_VIEW);
+         rackRearWidget.addSelectionListener(listener);
+         
+         scroller.setMinSize(content.computeSize(SWT.DEFAULT, scroller.getSize().y));
          createPopupMenu();
           }
        }
@@ -201,4 +238,14 @@ public class RackTab extends ObjectTab implements ISelectionProvider
    {
       this.selection = selection;
    }
+
+   /* (non-Javadoc)
+    * @see org.netxms.ui.eclipse.objectview.objecttabs.ObjectTab#selected()
+    */
+   @Override
+   public void selected()
+   {
+      super.selected();
+      scroller.setContent(content);
+   }
 }
index 9a82da0..1a50c3a 100644 (file)
@@ -62,6 +62,11 @@ import org.netxms.ui.eclipse.tools.WidgetHelper;
  */
 public class RackWidget extends Canvas implements PaintListener, DisposeListener, ImageUpdateListener, MouseListener, MouseTrackListener, MouseMoveListener
 {
+   // Rack views
+   public static final int RACK_FRONT_VIEW = 0;
+   public static final int RACK_REAR_VIEW = 1;
+   private static final String[] VIEW_LABELS = { "Front", "Back" };
+   
    private static final double UNIT_WH_RATIO = 10.85;
    private static final int BORDER_WIDTH_RATIO = 15;
    private static final int FULL_UNIT_WIDTH = 482;
@@ -69,6 +74,7 @@ public class RackWidget extends Canvas implements PaintListener, DisposeListener
    private static final int MARGIN_HEIGHT = 10;
    private static final int MARGIN_WIDTH = 10;
    private static final int UNIT_NUMBER_WIDTH = 30;
+   private static final int TITLE_HEIGHT = 20;
    private static final int OBJECT_TOOLTIP_X_MARGIN = 6;
    private static final int OBJECT_TOOLTIP_Y_MARGIN = 6;
    private static final int OBJECT_TOOLTIP_SPACING = 6;
@@ -76,9 +82,11 @@ public class RackWidget extends Canvas implements PaintListener, DisposeListener
    
    private Rack rack;
    private Font[] labelFonts;
+   private Font[] titleFonts;
    private Image imageDefaultTop;
    private Image imageDefaultMiddle;
    private Image imageDefaultBottom;
+   private Image imageDefaultRear;
    private List<ObjectImage> objects = new ArrayList<ObjectImage>();
    private AbstractObject selectedObject = null;
    private Set<RackSelectionListener> selectionListeners = new HashSet<RackSelectionListener>(0);
@@ -87,15 +95,17 @@ public class RackWidget extends Canvas implements PaintListener, DisposeListener
    private Font objectToolTipHeaderFont;
    private AbstractObject tooltipObject = null;
    private ColorCache colorCache;
+   private int view;
    
    /**
     * @param parent
     * @param style
     */
-   public RackWidget(Composite parent, int style, Rack rack)
+   public RackWidget(Composite parent, int style, Rack rack, int view)
    {
       super(parent, style | SWT.DOUBLE_BUFFERED);
       this.rack = rack;
+      this.view = (view > 1 ? 0 : view);
       
       colorCache = new ColorCache(this);
       
@@ -105,12 +115,17 @@ public class RackWidget extends Canvas implements PaintListener, DisposeListener
       
       final String fontName = FontTools.findFirstAvailableFont(FONT_NAMES);
       labelFonts = new Font[16];
+      titleFonts = new Font[16];
       for(int i = 0; i < labelFonts.length; i++)
+      {
          labelFonts[i] = new Font(getDisplay(), fontName, i + 6, SWT.NORMAL);
+         titleFonts[i] = new Font(getDisplay(), fontName, i + 6, SWT.BOLD);
+      }
       
       imageDefaultTop = Activator.getImageDescriptor("icons/rack-default-top.png").createImage(); //$NON-NLS-1$
       imageDefaultMiddle = Activator.getImageDescriptor("icons/rack-default-middle.png").createImage(); //$NON-NLS-1$
       imageDefaultBottom = Activator.getImageDescriptor("icons/rack-default-bottom.png").createImage(); //$NON-NLS-1$
+      imageDefaultRear = Activator.getImageDescriptor("icons/rack-default-rear.png").createImage(); //$NON-NLS-1$
       
       addPaintListener(this);
       addMouseListener(this);
@@ -142,8 +157,8 @@ public class RackWidget extends Canvas implements PaintListener, DisposeListener
       // Calculate bounding box for rack picture
       Rectangle rect = getClientArea();
       rect.x += MARGIN_WIDTH + UNIT_NUMBER_WIDTH;
-      rect.y += MARGIN_HEIGHT;
-      rect.height -= MARGIN_HEIGHT * 2;
+      rect.y += MARGIN_HEIGHT + MARGIN_HEIGHT / 2 + TITLE_HEIGHT;
+      rect.height -= MARGIN_HEIGHT * 2 + MARGIN_HEIGHT / 2 + TITLE_HEIGHT;
       
       // Estimated unit width/height and calculate border width
       double unitHeight = (double)rect.height / (double)rack.getHeight();
@@ -158,6 +173,11 @@ public class RackWidget extends Canvas implements PaintListener, DisposeListener
       unitWidth = (int)(unitHeight * UNIT_WH_RATIO);
       rect.width = unitWidth + borderWidth * 2;
       
+      // Title
+      gc.setFont(WidgetHelper.getBestFittingFont(gc, titleFonts, VIEW_LABELS[0], rect.width, TITLE_HEIGHT)); //$NON-NLS-1$
+      Point titleSize = gc.textExtent(VIEW_LABELS[view]);
+      gc.drawText(VIEW_LABELS[view], (rect.width / 2 - titleSize.x / 2) + UNIT_NUMBER_WIDTH + MARGIN_WIDTH, rect.y - TITLE_HEIGHT - MARGIN_HEIGHT / 2);
+
       // Rack itself
       gc.setBackground(SharedColors.getColor(SharedColors.RACK_EMPTY_SPACE, getDisplay()));
       gc.fillRoundRectangle(rect.x, rect.y, rect.width, rect.height, 3, 3);
@@ -207,7 +227,8 @@ public class RackWidget extends Canvas implements PaintListener, DisposeListener
       {
          if ((n.getRackPosition() < 1) || (n.getRackPosition() > rack.getHeight()) || 
              (rack.isTopBottomNumbering() && (n.getRackPosition() + n.getRackHeight() > rack.getHeight() + 1)) ||
-             (!rack.isTopBottomNumbering() && (n.getRackPosition() - n.getRackHeight() < 0)))
+             (!rack.isTopBottomNumbering() && (n.getRackPosition() - n.getRackHeight() < 0)) || 
+             ((n.getRackOrientation() == view) ? false : ((n.getRackOrientation() == RackElement.RACK_POSITION_FILL) ? false : true)))
             continue;
          
          int topLine, bottomLine;
@@ -240,50 +261,54 @@ public class RackWidget extends Canvas implements PaintListener, DisposeListener
          }
          else // Draw default representation
          {
-            Rectangle r = imageDefaultTop.getBounds();
+            Image imageTop = (view == RACK_REAR_VIEW && n.getRackOrientation() == RackElement.RACK_POSITION_FILL) ? imageDefaultRear : imageDefaultTop;
+            
+            Rectangle r = imageTop.getBounds();
             if (n.getRackHeight() == 1)
             {
-               gc.drawImage(imageDefaultTop, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
+                  gc.drawImage(imageTop, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
             }
             else
             {
+               Image imageMiddle = (view == RACK_REAR_VIEW && n.getRackOrientation() == RackElement.RACK_POSITION_FILL) ? imageDefaultRear : imageDefaultMiddle;
+               Image imageBottom = (view == RACK_REAR_VIEW && n.getRackOrientation() == RackElement.RACK_POSITION_FILL) ? imageDefaultRear : imageDefaultBottom;
                if (rack.isTopBottomNumbering())
                {
                   unitRect.height = unitBaselines[n.getRackPosition()] - topLine;
-                  gc.drawImage(imageDefaultTop, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
+                  gc.drawImage(imageTop, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
                   
-                  r = imageDefaultMiddle.getBounds();
+                  r = imageMiddle.getBounds();
                   int u = n.getRackPosition() + 1;
                   for(int i = 1; i < n.getRackHeight() - 1; i++, u++)
                   {
                      unitRect.y = unitBaselines[u - 1];
                      unitRect.height = unitBaselines[u] - unitRect.y;
-                     gc.drawImage(imageDefaultMiddle, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
+                     gc.drawImage(imageMiddle, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
                   }
                   
-                  r = imageDefaultBottom.getBounds();
+                  r = imageBottom.getBounds();
                   unitRect.y = unitBaselines[u - 1];
                   unitRect.height = unitBaselines[u] - unitRect.y;
-                  gc.drawImage(imageDefaultBottom, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
+                  gc.drawImage(imageBottom, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
                }
                else
                {
                   unitRect.height = unitBaselines[n.getRackPosition() - 1] - topLine;
-                  gc.drawImage(imageDefaultTop, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
+                  gc.drawImage(imageTop, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
    
-                  r = imageDefaultMiddle.getBounds();
+                  r = imageMiddle.getBounds();
                   int u = n.getRackPosition() - 1;
                   for(int i = 1; i < n.getRackHeight() - 1; i++, u--)
                   {
                      unitRect.y = unitBaselines[u];
                      unitRect.height = unitBaselines[u - 1] - unitRect.y;
-                     gc.drawImage(imageDefaultMiddle, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
+                     gc.drawImage(imageMiddle, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
                   }
                   
-                  r = imageDefaultBottom.getBounds();
+                  r = imageBottom.getBounds();
                   unitRect.y = unitBaselines[u];
                   unitRect.height = unitBaselines[u - 1] - unitRect.y;
-                  gc.drawImage(imageDefaultBottom, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
+                  gc.drawImage(imageBottom, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
                }
             }
          }
@@ -434,6 +459,9 @@ public class RackWidget extends Canvas implements PaintListener, DisposeListener
    @Override
    public Point computeSize(int wHint, int hHint, boolean changed)
    {
+      if (hHint == SWT.DEFAULT && wHint == SWT.DEFAULT)
+         return new Point(10, 10);
+
       if (hHint == SWT.DEFAULT)
       {
          int borderWidth = FULL_UNIT_WIDTH / BORDER_WIDTH_RATIO;
@@ -457,13 +485,17 @@ public class RackWidget extends Canvas implements PaintListener, DisposeListener
    public void widgetDisposed(DisposeEvent e)
    {
       for(int i = 0; i < labelFonts.length; i++)
+      {
          labelFonts[i].dispose();
+         titleFonts[i].dispose();
+      }
       
       objectToolTipHeaderFont.dispose();
       
       imageDefaultTop.dispose();
       imageDefaultMiddle.dispose();
       imageDefaultBottom.dispose();
+      imageDefaultRear.dispose();
       
       ImageProvider.getInstance().removeUpdateListener(this);
    }
index 07748f3..aa68317 100644 (file)
@@ -101,7 +101,6 @@ import org.netxms.ui.eclipse.serverconfig.views.helpers.ToolComparator;
 import org.netxms.ui.eclipse.serverconfig.views.helpers.ToolLabelProvider;
 import org.netxms.ui.eclipse.shared.ConsoleSharedData;
 import org.netxms.ui.eclipse.tools.ObjectLabelComparator;
-import org.netxms.ui.eclipse.tools.WidgetHelper;
 import org.netxms.ui.eclipse.widgets.LabeledText;
 
 /**
index ab87c26..9176cf1 100644 (file)
@@ -998,6 +998,7 @@ public class NXCPCodes
    public static final long VID_INCLUDE_RAW_VALUES = 608;
    public static final long VID_JOB_CANCELED = 609;
    public static final long VID_INSTANCE_RETENTION = 610;
+   public static final long VID_RACK_ORIENTATION = 611;
 
        public static final long VID_ACL_USER_BASE = 0x00001000L;
        public static final long VID_ACL_USER_LAST = 0x00001FFFL;
index d3c3572..6a128c7 100644 (file)
@@ -31,6 +31,7 @@ Chassis::Chassis() : DataCollectionTarget()
    m_rackId = 0;
    m_rackPosition = 0;
    m_rackHeight = 1;
+   m_rackOrientation = RACK_POSITION_FILL;
 }
 
 /**
@@ -42,6 +43,7 @@ Chassis::Chassis(const TCHAR *name, UINT32 controllerId) : DataCollectionTarget(
    m_rackId = 0;
    m_rackPosition = 0;
    m_rackHeight = 1;
+   m_rackOrientation = RACK_POSITION_FILL;
 }
 
 /**
@@ -162,6 +164,7 @@ void Chassis::fillMessageInternal(NXCPMessage *msg, UINT32 userId)
    msg->setField(VID_RACK_IMAGE, m_rackImage);
    msg->setField(VID_RACK_POSITION, m_rackPosition);
    msg->setField(VID_RACK_HEIGHT, m_rackHeight);
+   msg->setField(VID_RACK_ORIENTATION, m_rackOrientation);
 }
 
 /**
@@ -182,6 +185,8 @@ UINT32 Chassis::modifyFromMessageInternal(NXCPMessage *request)
       m_rackPosition = request->getFieldAsInt16(VID_RACK_POSITION);
    if (request->isFieldExist(VID_RACK_HEIGHT))
       m_rackHeight = request->getFieldAsInt16(VID_RACK_HEIGHT);
+   if (request->isFieldExist(VID_RACK_ORIENTATION))
+      m_rackOrientation = request->getFieldAsInt16(VID_RACK_ORIENTATION);
 
    return DataCollectionTarget::modifyFromMessageInternal(request);
 }
@@ -197,9 +202,9 @@ bool Chassis::saveToDatabase(DB_HANDLE hdb)
    {
       DB_STATEMENT hStmt;
       if (IsDatabaseRecordExist(hdb, _T("chassis"), _T("id"), m_id))
-         hStmt = DBPrepare(hdb, _T("UPDATE chassis SET controller_id=?,rack_id=?,rack_image=?,rack_position=?,rack_height=? WHERE id=?"));
+         hStmt = DBPrepare(hdb, _T("UPDATE chassis SET controller_id=?,rack_id=?,rack_image=?,rack_position=?,rack_height=?,rack_orientation=? WHERE id=?"));
       else
-         hStmt = DBPrepare(hdb, _T("INSERT INTO chassis (controller_id,rack_id,rack_image,rack_position,rack_height,id) VALUES (?,?,?,?,?,?)"));
+         hStmt = DBPrepare(hdb, _T("INSERT INTO chassis (controller_id,rack_id,rack_image,rack_position,rack_height,rack_orientation,id) VALUES (?,?,?,?,?,?,?)"));
       if (hStmt != NULL)
       {
          DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_controllerId);
@@ -207,7 +212,8 @@ bool Chassis::saveToDatabase(DB_HANDLE hdb)
          DBBind(hStmt, 3, DB_SQLTYPE_VARCHAR, m_rackImage);
          DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, m_rackPosition);
          DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, m_rackHeight);
-         DBBind(hStmt, 6, DB_SQLTYPE_INTEGER, m_id);
+         DBBind(hStmt, 6, DB_SQLTYPE_INTEGER, m_rackOrientation);
+         DBBind(hStmt, 7, DB_SQLTYPE_INTEGER, m_id);
          success = DBExecute(hStmt);
          DBFreeStatement(hStmt);
       }
@@ -258,7 +264,7 @@ bool Chassis::loadFromDatabase(DB_HANDLE hdb, UINT32 id)
       return false;
    }
 
-   DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT controller_id,rack_id,rack_image,rack_position,rack_height FROM chassis WHERE id=?"));
+   DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT controller_id,rack_id,rack_image,rack_position,rack_height,rack_orientation FROM chassis WHERE id=?"));
    if (hStmt == NULL)
       return false;
 
@@ -275,6 +281,7 @@ bool Chassis::loadFromDatabase(DB_HANDLE hdb, UINT32 id)
    m_rackImage = DBGetFieldGUID(hResult, 0, 2);
    m_rackPosition = DBGetFieldULong(hResult, 0, 3);
    m_rackHeight = DBGetFieldULong(hResult, 0, 4);
+   m_rackHeight = DBGetFieldULong(hResult, 0, 5);
 
    DBFreeResult(hResult);
    DBFreeStatement(hStmt);
@@ -399,6 +406,7 @@ json_t *Chassis::toJson()
    json_object_set_new(root, "controllerId", json_integer(m_controllerId));
    json_object_set_new(root, "rackHeight", json_integer(m_rackHeight));
    json_object_set_new(root, "rackPosition", json_integer(m_rackPosition));
+   json_object_set_new(root, "rackOrientation", json_integer(m_rackPosition));
    json_object_set_new(root, "rackId", json_integer(m_rackId));
    json_object_set_new(root, "rackImage", m_rackImage.toJson());
    return root;
index caa4889..58bf109 100644 (file)
@@ -125,6 +125,7 @@ Node::Node() : DataCollectionTarget()
    m_portNumberingScheme = NDD_PN_UNKNOWN;
    m_portRowCount = 0;
    m_agentCompressionMode = NODE_AGENT_COMPRESSION_DEFAULT;
+   m_rackOrientation = RACK_POSITION_FILL;
 }
 
 /**
@@ -228,6 +229,7 @@ Node::Node(const InetAddress& addr, UINT32 flags, UINT32 capabilities, UINT32 ag
    m_portNumberingScheme = NDD_PN_UNKNOWN;
    m_portRowCount = 0;
    m_agentCompressionMode = NODE_AGENT_COMPRESSION_DEFAULT;
+   m_rackOrientation = RACK_POSITION_FILL;
 }
 
 /**
@@ -305,7 +307,8 @@ bool Node::loadFromDatabase(DB_HANDLE hdb, UINT32 dwId)
       _T("last_agent_comm_time,syslog_msg_count,snmp_trap_count,")
       _T("node_type,node_subtype,ssh_login,ssh_password,ssh_proxy,")
       _T("port_rows,port_numbering_scheme,agent_comp_mode,")
-      _T("tunnel_id,lldp_id,capabilities,fail_time_snmp,fail_time_agent FROM nodes WHERE id=?"));
+      _T("tunnel_id,lldp_id,capabilities,fail_time_snmp,fail_time_agent,rack_orientation")
+      _T(" FROM nodes WHERE id=?"));
    if (hStmt == NULL)
       return false;
 
@@ -413,6 +416,7 @@ bool Node::loadFromDatabase(DB_HANDLE hdb, UINT32 dwId)
    m_capabilities = DBGetFieldULong(hResult, 0, 48);
    m_failTimeSNMP = DBGetFieldLong(hResult, 0, 49);
    m_failTimeAgent = DBGetFieldLong(hResult, 0, 50);
+   m_rackOrientation = DBGetFieldULong(hResult, 0, 51);
 
    DBFreeResult(hResult);
    DBFreeStatement(hStmt);
@@ -508,7 +512,7 @@ bool Node::saveToDatabase(DB_HANDLE hdb)
             _T("agent_cache_mode=?,snmp_sys_contact=?,snmp_sys_location=?,last_agent_comm_time=?,")
             _T("syslog_msg_count=?,snmp_trap_count=?,node_type=?,node_subtype=?,ssh_login=?,ssh_password=?,")
             _T("ssh_proxy=?,chassis_id=?,port_rows=?,port_numbering_scheme=?,agent_comp_mode=?,tunnel_id=?,")
-            _T("lldp_id=?,fail_time_snmp=?,fail_time_agent=? WHERE id=?"));
+            _T("lldp_id=?,fail_time_snmp=?,fail_time_agent=?,rack_orientation=? WHERE id=?"));
       }
       else
       {
@@ -519,8 +523,8 @@ bool Node::saveToDatabase(DB_HANDLE hdb)
            _T("snmp_sys_name,bridge_base_addr,down_since,driver_name,rack_image,rack_position,rack_height,rack_id,boot_time,")
            _T("agent_cache_mode,snmp_sys_contact,snmp_sys_location,last_agent_comm_time,syslog_msg_count,snmp_trap_count,")
            _T("node_type,node_subtype,ssh_login,ssh_password,ssh_proxy,chassis_id,port_rows,port_numbering_scheme,agent_comp_mode,")
-           _T("tunnel_id,lldp_id,fail_time_snmp,fail_time_agent,id) ")
-           _T("VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
+           _T("tunnel_id,lldp_id,fail_time_snmp,fail_time_agent,rack_orientation,id) ")
+           _T("VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
       }
       if (hStmt != NULL)
       {
@@ -587,7 +591,8 @@ bool Node::saveToDatabase(DB_HANDLE hdb)
          DBBind(hStmt, 50, DB_SQLTYPE_VARCHAR, m_lldpNodeId, DB_BIND_STATIC);
          DBBind(hStmt, 51, DB_SQLTYPE_INTEGER, (LONG)m_failTimeSNMP);
          DBBind(hStmt, 52, DB_SQLTYPE_INTEGER, (LONG)m_failTimeAgent);
-         DBBind(hStmt, 53, DB_SQLTYPE_INTEGER, m_id);
+         DBBind(hStmt, 53, DB_SQLTYPE_INTEGER, m_rackOrientation);
+         DBBind(hStmt, 54, DB_SQLTYPE_INTEGER, m_id);
 
          success = DBExecute(hStmt);
          DBFreeStatement(hStmt);
@@ -4781,6 +4786,7 @@ void Node::fillMessageInternal(NXCPMessage *pMsg, UINT32 userId)
    pMsg->setField(VID_PORT_ROW_COUNT, m_portRowCount);
    pMsg->setField(VID_PORT_NUMBERING_SCHEME, m_portNumberingScheme);
    pMsg->setField(VID_AGENT_COMPRESSION_MODE, m_agentCompressionMode);
+   pMsg->setField(VID_RACK_ORIENTATION, m_rackOrientation);
 }
 
 /**
@@ -5040,6 +5046,9 @@ UINT32 Node::modifyFromMessageInternal(NXCPMessage *pRequest)
    if (pRequest->isFieldExist(VID_AGENT_COMPRESSION_MODE))
       m_agentCompressionMode = pRequest->getFieldAsInt16(VID_AGENT_COMPRESSION_MODE);
 
+   if (pRequest->isFieldExist(VID_RACK_ORIENTATION))
+      m_rackOrientation = pRequest->getFieldAsUInt16(VID_RACK_ORIENTATION);
+
    return DataCollectionTarget::modifyFromMessageInternal(pRequest);
 }
 
@@ -7849,6 +7858,7 @@ json_t *Node::toJson()
    json_object_set_new(root, "baseBridgeAddress", json_string_a(BinToStrA(m_baseBridgeAddress, MAC_ADDR_LENGTH, baseBridgeAddrText)));
    json_object_set_new(root, "rackHeight", json_integer(m_rackHeight));
    json_object_set_new(root, "rackPosition", json_integer(m_rackPosition));
+   json_object_set_new(root, "rackOrientation", json_integer(m_rackOrientation));
    json_object_set_new(root, "rackId", json_integer(m_rackId));
    json_object_set_new(root, "rackImage", m_rackImage.toJson());
    json_object_set_new(root, "chassisId", json_integer(m_chassisId));
index f5129a1..b8d48ce 100644 (file)
@@ -1428,6 +1428,11 @@ public:
    NXSL_Array *getNodesForNXSL();
 };
 
+// Rack element orientation
+#define RACK_POSITION_FRONT 0
+#define RACK_POSITION_REAR  1
+#define RACK_POSITION_FILL  2
+
 /**
  * Chassis (represents physical chassis)
  */
@@ -1439,6 +1444,7 @@ protected:
    INT16 m_rackPosition;
    UINT32 m_rackId;
    uuid m_rackImage;
+   INT16 m_rackOrientation;
 
    virtual void fillMessageInternal(NXCPMessage *msg, UINT32 userId);
    virtual UINT32 modifyFromMessageInternal(NXCPMessage *request);
@@ -1749,6 +1755,7 @@ protected:
        UINT32 m_sshProxy;
        UINT32 m_portNumberingScheme;
        UINT32 m_portRowCount;
+       INT16 m_rackOrientation;
 
    virtual void statusPoll(PollerInfo *poller, ClientSession *session, UINT32 rqId);
    virtual void configurationPoll(PollerInfo *poller, ClientSession *session, UINT32 rqId);
index ea15e22..b9579aa 100644 (file)
 #include "nxdbmgr.h"
 
 /**
- * Upgrade from 30.12 to 30.13
+ * Upgrade from 30.13 to 30.14
  */
-static bool H_UpgradeFromV12()
+static bool H_UpgradeFromV13()
 {
-   static const TCHAR *batch =
+   static const TCHAR *batch = 
             _T("ALTER TABLE items ADD instance_retention_time integer\n")
             _T("ALTER TABLE dc_tables ADD instance_retention_time integer\n")
             _T("UPDATE items SET instance_retention_time=-1\n")
@@ -40,6 +40,26 @@ static bool H_UpgradeFromV12()
    CHK_EXEC(DBSetNotNullConstraint(g_hCoreDB, _T("items"), _T("instance_retention_time")));
    CHK_EXEC(DBSetNotNullConstraint(g_hCoreDB, _T("dc_tables"), _T("instance_retention_time")));
 
+   CHK_EXEC(SetMinorSchemaVersion(14));
+   return true;
+}
+
+/**
+ * Upgrade from 30.12 to 30.13
+ */
+static bool H_UpgradeFromV12()
+{
+   static const TCHAR *batch =
+            _T("ALTER TABLE nodes ADD rack_orientation integer null\n")
+            _T("ALTER TABLE chassis ADD rack_orientation integer null\n")
+            _T("UPDATE nodes SET rack_orientation=2\n")
+            _T("UPDATE chassis SET rack_orientation=2\n")
+            _T("<END>");
+   CHK_EXEC(SQLBatch(batch));
+
+   CHK_EXEC(DBSetNotNullConstraint(g_hCoreDB, _T("nodes"), _T("rack_orientation")));
+   CHK_EXEC(DBSetNotNullConstraint(g_hCoreDB, _T("chassis"), _T("rack_orientation")));
+
    CHK_EXEC(SetMinorSchemaVersion(13));
    return true;
 }
@@ -583,6 +603,10 @@ static struct
    bool (* upgradeProc)();
 } s_dbUpgradeMap[] =
 {
+<<<<<<< HEAD
+   { 13, 30, 14, H_UpgradeFromV13 },
+=======
+>>>>>>> a5831b94e... Implemented rear view for racks
    { 12, 30, 13, H_UpgradeFromV12 },
    { 11, 30, 12, H_UpgradeFromV11 },
    { 10, 30, 11, H_UpgradeFromV10 },
index 50bec5e..d77f1a7 100644 (file)
 package org.netxms.ui.eclipse.dashboard.widgets;
 
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
 import org.eclipse.ui.IViewPart;
 import org.netxms.client.NXCSession;
 import org.netxms.client.dashboards.DashboardElement;
 import org.netxms.client.objects.Rack;
+import org.netxms.ui.eclipse.console.resources.SharedColors;
 import org.netxms.ui.eclipse.dashboard.widgets.internal.RackDiagramConfig;
 import org.netxms.ui.eclipse.objectview.widgets.RackWidget;
 import org.netxms.ui.eclipse.shared.ConsoleSharedData;
@@ -33,9 +38,11 @@ import org.netxms.ui.eclipse.shared.ConsoleSharedData;
  */
 public class RackDiagramElement extends ElementWidget
 {
-   private RackWidget rackWidget;
+   private RackWidget rackFrontWidget;
+   private RackWidget rackRearWidget;
    private NXCSession session;
    private RackDiagramConfig config;
+   private Composite rackArea;
 
    /**
     * Create new rack diagram element
@@ -62,30 +69,77 @@ public class RackDiagramElement extends ElementWidget
       Rack rack = session.findObjectById(config.getObjectId(), Rack.class);
       
       if (rack != null)
-         setRackWidget(new RackWidget(this, SWT.NONE, rack));
-      
-      FillLayout layout = new FillLayout();
-      layout.marginHeight = 0;
-      layout.marginWidth = 0;
-      setLayout(layout);
+      {
+         rackArea = new Composite(this, SWT.NONE) {
+            @Override
+            public Point computeSize(int wHint, int hHint, boolean changed)
+            {
+               if ((rackFrontWidget == null) || (rackRearWidget == null) || (hHint == SWT.DEFAULT))
+                  return super.computeSize(wHint, hHint, changed);
+               
+               Point s = rackFrontWidget.computeSize(wHint, hHint, changed);
+               return new Point(s.x * 2, s.y);
+            }
+         };
+         rackArea.setBackground(SharedColors.getColor(SharedColors.RACK_BACKGROUND, parent.getDisplay()));
+         rackArea.addControlListener(new ControlAdapter() {
+            @Override
+            public void controlResized(ControlEvent e)
+            {
+               if ((rackFrontWidget == null) || (rackRearWidget == null))
+                  return;
+               
+               int height = rackArea.getSize().y;
+               Point size = rackFrontWidget.computeSize(SWT.DEFAULT, height, true);
+               rackFrontWidget.setSize(size);
+               rackRearWidget.setSize(size);
+               rackRearWidget.setLocation(size.x, 0);
+            }
+         });
+         
+         setRackFrontWidget(new RackWidget(rackArea, SWT.NONE, rack, RackWidget.RACK_FRONT_VIEW));
+         setRackRearWidget(new RackWidget(rackArea, SWT.NONE, rack, RackWidget.RACK_REAR_VIEW));
+      }
+      setLayout(new FillLayout());
+   }
+
+   /**
+    * Get rear rack widget
+    * 
+    * @return Rear rack widget
+    */
+   public RackWidget getRackRearWidget()
+   {
+      return rackRearWidget;
    }
 
    /**
-    * Get rack widget
-    * @return rack widget
+    * Set rear rack widget
+    * 
+    * @param rackRearWidget to set
     */
-   public RackWidget getRackWidget()
+   public void setRackRearWidget(RackWidget rackRearWidget)
    {
-      return rackWidget;
+      this.rackRearWidget = rackRearWidget;
    }
 
    /**
-    * Set rack widget
-    * @param rackWidget to set
+    * Get front rack widget
+    * 
+    * @return Front rack widget
     */
-   public void setRackWidget(RackWidget rackWidget)
+   public RackWidget getRackFrontWidget()
    {
-      this.rackWidget = rackWidget;
+      return rackFrontWidget;
    }
 
+   /**
+    * Set front rack widget
+    * 
+    * @param rackFrontWidget to set
+    */
+   public void setRackFrontWidget(RackWidget rackFrontWidget)
+   {
+      this.rackFrontWidget = rackFrontWidget;
+   }
 }
index e16aa48..a36fe9b 100644 (file)
@@ -22,6 +22,7 @@ import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Combo;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
 import org.eclipse.ui.dialogs.PropertyPage;
@@ -44,11 +45,14 @@ import org.netxms.ui.eclipse.widgets.LabeledSpinner;
  */
 public class RackPlacement extends PropertyPage
 {
+   private final static String[] ORIENTATION = { "Front", "Rear", "Fill" };
+   
        private RackElement object;
        private ObjectSelector rackSelector;
        private ImageSelector rackImageSelector;
        private LabeledSpinner rackHeight;
        private LabeledSpinner rackPosition;
+       private Combo rackOrientation;
        
        /* (non-Javadoc)
         * @see org.eclipse.jface.preference.PreferencePage#createContents(org.eclipse.swt.widgets.Composite)
@@ -64,7 +68,7 @@ public class RackPlacement extends PropertyPage
                layout.verticalSpacing = WidgetHelper.OUTER_SPACING;
                layout.marginWidth = 0;
                layout.marginHeight = 0;
-               layout.numColumns = 2;
+               layout.numColumns = 3;
       dialogArea.setLayout(layout);
 
       rackSelector = new ObjectSelector(dialogArea, SWT.NONE, true);
@@ -74,7 +78,7 @@ public class RackPlacement extends PropertyPage
                GridData gd = new GridData();
                gd.grabExcessHorizontalSpace = true;
                gd.horizontalAlignment = SWT.FILL;
-               gd.horizontalSpan = 2;
+               gd.horizontalSpan = 3;
                rackSelector.setLayoutData(gd);
                
                rackImageSelector = new ImageSelector(dialogArea, SWT.NONE);
@@ -83,7 +87,7 @@ public class RackPlacement extends PropertyPage
       gd = new GridData();
       gd.grabExcessHorizontalSpace = true;
       gd.horizontalAlignment = SWT.FILL;
-      gd.horizontalSpan = 2;
+      gd.horizontalSpan = 3;
       rackImageSelector.setLayoutData(gd);
       
       rackPosition = new LabeledSpinner(dialogArea, SWT.NONE);
@@ -104,6 +108,14 @@ public class RackPlacement extends PropertyPage
       gd.horizontalAlignment = SWT.FILL;
       rackHeight.setLayoutData(gd);
       
+      gd = new GridData();
+      gd.grabExcessHorizontalSpace = true;
+      gd.horizontalAlignment = SWT.FILL;
+      rackHeight.setLayoutData(gd);
+      rackOrientation = WidgetHelper.createLabeledCombo(dialogArea, SWT.READ_ONLY, "Orientation", gd);
+      rackOrientation.setItems(ORIENTATION);
+      rackOrientation.setText(ORIENTATION[object.getRackOrientation()]);
+      
                return dialogArea;
        }
 
@@ -118,7 +130,8 @@ public class RackPlacement extends PropertyPage
                        setValid(false);
                
                final NXCObjectModificationData md = new NXCObjectModificationData(object.getObjectId());
-               md.setRackPlacement(rackSelector.getObjectId(), rackImageSelector.getImageGuid(), (short)rackPosition.getSelection(), (short)rackHeight.getSelection());
+               md.setRackPlacement(rackSelector.getObjectId(), rackImageSelector.getImageGuid(), (short)rackPosition.getSelection(), (short)rackHeight.getSelection(),
+                                   (short)rackOrientation.getSelectionIndex());
                
                final NXCSession session = (NXCSession)ConsoleSharedData.getSession();
                new ConsoleJob(String.format(Messages.get().RackPlacement_UpdatingRackPlacement, object.getObjectName()), null, Activator.PLUGIN_ID, null) {
diff --git a/webui/webapp/ObjectView/icons/rack-default-rear.png b/webui/webapp/ObjectView/icons/rack-default-rear.png
new file mode 100644 (file)
index 0000000..356e509
Binary files /dev/null and b/webui/webapp/ObjectView/icons/rack-default-rear.png differ
index 4112b01..dd3d3ad 100644 (file)
@@ -32,7 +32,7 @@ import org.eclipse.swt.SWT;
 import org.eclipse.swt.custom.ScrolledComposite;
 import org.eclipse.swt.events.ControlAdapter;
 import org.eclipse.swt.events.ControlEvent;
-import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Menu;
 import org.netxms.client.objects.AbstractObject;
@@ -49,7 +49,8 @@ public class RackTab extends ObjectTab implements ISelectionProvider
 {
    private ScrolledComposite scroller;
    private Composite content;
-   private RackWidget rackWidget;
+   private RackWidget rackFrontWidget;
+   private RackWidget rackRearWidget;
    private ISelection selection = new StructuredSelection();
    private Set<ISelectionChangedListener> selectionListeners = new HashSet<ISelectionChangedListener>();
    
@@ -61,9 +62,32 @@ public class RackTab extends ObjectTab implements ISelectionProvider
        {
           scroller = new ScrolledComposite(parent, SWT.H_SCROLL);
           
-          content = new Composite(scroller, SWT.NONE);
-          content.setLayout(new FillLayout());
+          content = new Composite(scroller, SWT.NONE) {
+         @Override
+         public Point computeSize(int wHint, int hHint, boolean changed)
+         {
+            if ((rackFrontWidget == null) || (rackRearWidget == null) || (hHint == SWT.DEFAULT))
+               return super.computeSize(wHint, hHint, changed);
+            
+            Point s = rackFrontWidget.computeSize(wHint, hHint, changed);
+            return new Point(s.x * 2, s.y);
+         }
+          };
           content.setBackground(SharedColors.getColor(SharedColors.RACK_BACKGROUND, parent.getDisplay()));
+          content.addControlListener(new ControlAdapter() {
+         @Override
+         public void controlResized(ControlEvent e)
+         {
+            if ((rackFrontWidget == null) || (rackRearWidget == null))
+               return;
+            
+            int height = content.getSize().y;
+            Point size = rackFrontWidget.computeSize(SWT.DEFAULT, height, true);
+            rackFrontWidget.setSize(size);
+            rackRearWidget.setSize(size);
+            rackRearWidget.setLocation(size.x, 0);
+         }
+      });
           
           scroller.setContent(content);
       scroller.setExpandHorizontal(true);
@@ -92,8 +116,11 @@ public class RackTab extends ObjectTab implements ISelectionProvider
       });
 
       // Create menu.
-      Menu menu = menuMgr.createContextMenu(rackWidget);
-      rackWidget.setMenu(menu);
+      Menu menu = menuMgr.createContextMenu(rackFrontWidget);
+      rackFrontWidget.setMenu(menu);
+      
+      menu = menuMgr.createContextMenu(rackRearWidget);
+      rackRearWidget.setMenu(menu);
 
       // Register menu for extension.
       getViewPart().getSite().registerContextMenu(menuMgr, this);
@@ -132,18 +159,20 @@ public class RackTab extends ObjectTab implements ISelectionProvider
        @Override
        public void objectChanged(final AbstractObject object)
        {
-      if (rackWidget != null)
+      if (rackFrontWidget != null)
+      {
+         rackFrontWidget.dispose();
+         rackFrontWidget = null;
+      }
+      if (rackRearWidget != null)
       {
-         rackWidget.dispose();
-         rackWidget = null;
+         rackRearWidget.dispose();
+         rackRearWidget = null;
       }
 
       if (object != null)
           {
-             rackWidget = new RackWidget(content, SWT.NONE, (Rack)object);
-             content.layout(true, true);
-         scroller.setMinSize(content.computeSize(SWT.DEFAULT, scroller.getSize().y));
-         rackWidget.addSelectionListener(new RackSelectionListener() {
+         RackSelectionListener listener = new RackSelectionListener() {
             @Override
             public void objectSelected(AbstractObject object)
             {
@@ -151,7 +180,15 @@ public class RackTab extends ObjectTab implements ISelectionProvider
                for(ISelectionChangedListener listener : selectionListeners)
                   listener.selectionChanged(new SelectionChangedEvent(RackTab.this, selection));
             }
-         });
+         };
+         
+         rackFrontWidget = new RackWidget(content, SWT.NONE, (Rack)object, RackWidget.RACK_FRONT_VIEW);
+         rackFrontWidget.addSelectionListener(listener);
+
+         rackRearWidget = new RackWidget(content, SWT.NONE, (Rack)object, RackWidget.RACK_REAR_VIEW);
+         rackRearWidget.addSelectionListener(listener);
+         
+         scroller.setMinSize(content.computeSize(SWT.DEFAULT, scroller.getSize().y));
          createPopupMenu();
           }
        }
@@ -200,4 +237,14 @@ public class RackTab extends ObjectTab implements ISelectionProvider
    {
       this.selection = selection;
    }
+
+   /* (non-Javadoc)
+    * @see org.netxms.ui.eclipse.objectview.objecttabs.ObjectTab#selected()
+    */
+   @Override
+   public void selected()
+   {
+      super.selected();
+      scroller.setContent(content);
+   }
 }
index 8af8787..a759e85 100644 (file)
@@ -62,6 +62,11 @@ import org.netxms.ui.eclipse.tools.WidgetHelper;
  */
 public class RackWidget extends Canvas implements PaintListener, DisposeListener, ImageUpdateListener, MouseListener, MouseTrackListener, MouseMoveListener
 {
+   // Rack views
+   public static final int RACK_FRONT_VIEW = 0;
+   public static final int RACK_REAR_VIEW = 1;
+   private static final String[] VIEW_LABELS = { "Front", "Back" };
+   
    private static final double UNIT_WH_RATIO = 10.85;
    private static final int BORDER_WIDTH_RATIO = 15;
    private static final int FULL_UNIT_WIDTH = 482;
@@ -69,16 +74,19 @@ public class RackWidget extends Canvas implements PaintListener, DisposeListener
    private static final int MARGIN_HEIGHT = 10;
    private static final int MARGIN_WIDTH = 10;
    private static final int UNIT_NUMBER_WIDTH = 30;
+   private static final int TITLE_HEIGHT = 20;
    private static final int OBJECT_TOOLTIP_X_MARGIN = 6;
    private static final int OBJECT_TOOLTIP_Y_MARGIN = 6;
    private static final int OBJECT_TOOLTIP_SPACING = 6;
-   private static final String[] FONT_NAMES = { "Segoe UI", "Liberation Sans", "DejaVu Sans", "Verdana", "Arial" };
+   private static final String[] FONT_NAMES = { "Segoe UI", "Liberation Sans", "DejaVu Sans", "Verdana", "Arial" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
    
    private Rack rack;
    private Font[] labelFonts;
+   private Font[] titleFonts;
    private Image imageDefaultTop;
    private Image imageDefaultMiddle;
    private Image imageDefaultBottom;
+   private Image imageDefaultRear;
    private List<ObjectImage> objects = new ArrayList<ObjectImage>();
    private AbstractObject selectedObject = null;
    private Set<RackSelectionListener> selectionListeners = new HashSet<RackSelectionListener>(0);
@@ -87,15 +95,17 @@ public class RackWidget extends Canvas implements PaintListener, DisposeListener
    private Font objectToolTipHeaderFont;
    private AbstractObject tooltipObject = null;
    private ColorCache colorCache;
+   private int view;
    
    /**
     * @param parent
     * @param style
     */
-   public RackWidget(Composite parent, int style, Rack rack)
+   public RackWidget(Composite parent, int style, Rack rack, int view)
    {
       super(parent, style | SWT.DOUBLE_BUFFERED);
       this.rack = rack;
+      this.view = (view > 1 ? 0 : view);
       
       colorCache = new ColorCache(this);
       
@@ -105,12 +115,17 @@ public class RackWidget extends Canvas implements PaintListener, DisposeListener
       
       final String fontName = FontTools.findFirstAvailableFont(FONT_NAMES);
       labelFonts = new Font[16];
+      titleFonts = new Font[16];
       for(int i = 0; i < labelFonts.length; i++)
+      {
          labelFonts[i] = new Font(getDisplay(), fontName, i + 6, SWT.NORMAL);
+         titleFonts[i] = new Font(getDisplay(), fontName, i + 6, SWT.BOLD);
+      }
       
-      imageDefaultTop = Activator.getImageDescriptor("icons/rack-default-top.png").createImage();
-      imageDefaultMiddle = Activator.getImageDescriptor("icons/rack-default-middle.png").createImage();
-      imageDefaultBottom = Activator.getImageDescriptor("icons/rack-default-bottom.png").createImage();
+      imageDefaultTop = Activator.getImageDescriptor("icons/rack-default-top.png").createImage(); //$NON-NLS-1$
+      imageDefaultMiddle = Activator.getImageDescriptor("icons/rack-default-middle.png").createImage(); //$NON-NLS-1$
+      imageDefaultBottom = Activator.getImageDescriptor("icons/rack-default-bottom.png").createImage(); //$NON-NLS-1$
+      imageDefaultRear = Activator.getImageDescriptor("icons/rack-default-rear.png").createImage(); //$NON-NLS-1$
       
       addPaintListener(this);
       addMouseListener(this);
@@ -142,8 +157,8 @@ public class RackWidget extends Canvas implements PaintListener, DisposeListener
       // Calculate bounding box for rack picture
       Rectangle rect = getClientArea();
       rect.x += MARGIN_WIDTH + UNIT_NUMBER_WIDTH;
-      rect.y += MARGIN_HEIGHT;
-      rect.height -= MARGIN_HEIGHT * 2;
+      rect.y += MARGIN_HEIGHT + MARGIN_HEIGHT / 2 + TITLE_HEIGHT;
+      rect.height -= MARGIN_HEIGHT * 2 + MARGIN_HEIGHT / 2 + TITLE_HEIGHT;
       
       // Estimated unit width/height and calculate border width
       double unitHeight = (double)rect.height / (double)rack.getHeight();
@@ -158,6 +173,11 @@ public class RackWidget extends Canvas implements PaintListener, DisposeListener
       unitWidth = (int)(unitHeight * UNIT_WH_RATIO);
       rect.width = unitWidth + borderWidth * 2;
       
+      // Title
+      gc.setFont(WidgetHelper.getBestFittingFont(gc, titleFonts, VIEW_LABELS[0], rect.width, TITLE_HEIGHT)); //$NON-NLS-1$
+      Point titleSize = gc.textExtent(VIEW_LABELS[view]);
+      gc.drawText(VIEW_LABELS[view], (rect.width / 2 - titleSize.x / 2) + UNIT_NUMBER_WIDTH + MARGIN_WIDTH, rect.y - TITLE_HEIGHT - MARGIN_HEIGHT / 2);
+
       // Rack itself
       gc.setBackground(SharedColors.getColor(SharedColors.RACK_EMPTY_SPACE, getDisplay()));
       gc.fillRoundRectangle(rect.x, rect.y, rect.width, rect.height, 3, 3);
@@ -172,7 +192,7 @@ public class RackWidget extends Canvas implements PaintListener, DisposeListener
 
       // Draw unit numbers
       int[] unitBaselines = new int[rack.getHeight() + 1];
-      gc.setFont(WidgetHelper.getBestFittingFont(gc, labelFonts, "00", UNIT_NUMBER_WIDTH, (int)unitHeight - 2));
+      gc.setFont(WidgetHelper.getBestFittingFont(gc, labelFonts, "00", UNIT_NUMBER_WIDTH, (int)unitHeight - 2)); //$NON-NLS-1$
       gc.setForeground(SharedColors.getColor(SharedColors.RACK_TEXT, getDisplay()));
       gc.setBackground(SharedColors.getColor(SharedColors.RACK_BACKGROUND, getDisplay()));
       gc.setLineWidth(1);
@@ -207,7 +227,8 @@ public class RackWidget extends Canvas implements PaintListener, DisposeListener
       {
          if ((n.getRackPosition() < 1) || (n.getRackPosition() > rack.getHeight()) || 
              (rack.isTopBottomNumbering() && (n.getRackPosition() + n.getRackHeight() > rack.getHeight() + 1)) ||
-             (!rack.isTopBottomNumbering() && (n.getRackPosition() - n.getRackHeight() < 0)))
+             (!rack.isTopBottomNumbering() && (n.getRackPosition() - n.getRackHeight() < 0)) || 
+             ((n.getRackOrientation() == view) ? false : ((n.getRackOrientation() == RackElement.RACK_POSITION_FILL) ? false : true)))
             continue;
          
          int topLine, bottomLine;
@@ -240,50 +261,54 @@ public class RackWidget extends Canvas implements PaintListener, DisposeListener
          }
          else // Draw default representation
          {
-            Rectangle r = imageDefaultTop.getBounds();
+            Image imageTop = (view == RACK_REAR_VIEW && n.getRackOrientation() == RackElement.RACK_POSITION_FILL) ? imageDefaultRear : imageDefaultTop;
+            
+            Rectangle r = imageTop.getBounds();
             if (n.getRackHeight() == 1)
             {
-               gc.drawImage(imageDefaultTop, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
+                  gc.drawImage(imageTop, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
             }
             else
             {
+               Image imageMiddle = (view == RACK_REAR_VIEW && n.getRackOrientation() == RackElement.RACK_POSITION_FILL) ? imageDefaultRear : imageDefaultMiddle;
+               Image imageBottom = (view == RACK_REAR_VIEW && n.getRackOrientation() == RackElement.RACK_POSITION_FILL) ? imageDefaultRear : imageDefaultBottom;
                if (rack.isTopBottomNumbering())
                {
                   unitRect.height = unitBaselines[n.getRackPosition()] - topLine;
-                  gc.drawImage(imageDefaultTop, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
+                  gc.drawImage(imageTop, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
                   
-                  r = imageDefaultMiddle.getBounds();
+                  r = imageMiddle.getBounds();
                   int u = n.getRackPosition() + 1;
                   for(int i = 1; i < n.getRackHeight() - 1; i++, u++)
                   {
                      unitRect.y = unitBaselines[u - 1];
                      unitRect.height = unitBaselines[u] - unitRect.y;
-                     gc.drawImage(imageDefaultMiddle, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
+                     gc.drawImage(imageMiddle, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
                   }
                   
-                  r = imageDefaultBottom.getBounds();
+                  r = imageBottom.getBounds();
                   unitRect.y = unitBaselines[u - 1];
                   unitRect.height = unitBaselines[u] - unitRect.y;
-                  gc.drawImage(imageDefaultBottom, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
+                  gc.drawImage(imageBottom, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
                }
                else
                {
                   unitRect.height = unitBaselines[n.getRackPosition() - 1] - topLine;
-                  gc.drawImage(imageDefaultTop, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
+                  gc.drawImage(imageTop, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
    
-                  r = imageDefaultMiddle.getBounds();
+                  r = imageMiddle.getBounds();
                   int u = n.getRackPosition() - 1;
                   for(int i = 1; i < n.getRackHeight() - 1; i++, u--)
                   {
                      unitRect.y = unitBaselines[u];
                      unitRect.height = unitBaselines[u - 1] - unitRect.y;
-                     gc.drawImage(imageDefaultMiddle, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
+                     gc.drawImage(imageMiddle, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
                   }
                   
-                  r = imageDefaultBottom.getBounds();
+                  r = imageBottom.getBounds();
                   unitRect.y = unitBaselines[u];
                   unitRect.height = unitBaselines[u - 1] - unitRect.y;
-                  gc.drawImage(imageDefaultBottom, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
+                  gc.drawImage(imageBottom, 0, 0, r.width, r.height, unitRect.x, unitRect.y, unitRect.width, unitRect.height);
                }
             }
          }
@@ -315,7 +340,7 @@ public class RackWidget extends Canvas implements PaintListener, DisposeListener
          texts.add(((AbstractNode)tooltipObject).getPlatformName());
          String sd = ((AbstractNode)tooltipObject).getSystemDescription();
          if (sd.length() > 127)
-            sd = sd.substring(0, 127) + "...";
+            sd = sd.substring(0, 127) + "..."; //$NON-NLS-1$
          texts.add(sd);
          texts.add(((AbstractNode)tooltipObject).getSnmpSysName());
          texts.add(((AbstractNode)tooltipObject).getSnmpSysContact());
@@ -337,7 +362,7 @@ public class RackWidget extends Canvas implements PaintListener, DisposeListener
       {
          for(DciValue v : values)
          {
-            Point pt = gc.textExtent(v.getName() + "  " + v.getValue());
+            Point pt = gc.textExtent(v.getName() + "  " + v.getValue()); //$NON-NLS-1$
             if (width < pt.x)
                width = pt.x;
             height += pt.y;
@@ -434,6 +459,9 @@ public class RackWidget extends Canvas implements PaintListener, DisposeListener
    @Override
    public Point computeSize(int wHint, int hHint, boolean changed)
    {
+      if (hHint == SWT.DEFAULT && wHint == SWT.DEFAULT)
+         return new Point(10, 10);
+
       if (hHint == SWT.DEFAULT)
       {
          int borderWidth = FULL_UNIT_WIDTH / BORDER_WIDTH_RATIO;
@@ -457,7 +485,10 @@ public class RackWidget extends Canvas implements PaintListener, DisposeListener
    public void widgetDisposed(DisposeEvent e)
    {
       for(int i = 0; i < labelFonts.length; i++)
+      {
          labelFonts[i].dispose();
+         titleFonts[i].dispose();
+      }
       
       objectToolTipHeaderFont.dispose();