From 136fddd058fb8f7c6e98e27f17f7379b96760a2e Mon Sep 17 00:00:00 2001 From: Dhandapani Date: Fri, 10 Jun 2011 12:04:06 +0530 Subject: Checkbox selection enabled on Bricks page, Volumes page and Disk page --- src/com.gluster.storage.management.gui/plugin.xml | 12 +++++++++ .../gui/views/details/AbstractBricksPage.java | 7 +++-- .../gui/views/details/AbstractDisksPage.java | 13 +++++----- .../management/gui/views/pages/VolumesPage.java | 30 ++++++++++++---------- .../server/resources/VolumesResource.java | 3 ++- 5 files changed, 42 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/com.gluster.storage.management.gui/plugin.xml b/src/com.gluster.storage.management.gui/plugin.xml index f4c3c8f6..76d36d5c 100644 --- a/src/com.gluster.storage.management.gui/plugin.xml +++ b/src/com.gluster.storage.management.gui/plugin.xml @@ -910,6 +910,18 @@ standalone="false" visible="false"> + + volumes) { super(parent, SWT.NONE); @@ -74,7 +74,7 @@ public class VolumesPage extends Composite { setupVolumeTableViewer(site, volumes); parent.layout(); // Important - this actually paints the table - + /** * Ideally not required. However the table viewer is not getting laid out properly on performing * "maximize + restore" So this is a hack to make sure that the table is laid out again on re-size of the window @@ -85,9 +85,9 @@ public class VolumesPage extends Composite { public void paintControl(PaintEvent e) { parent.layout(); } - }); + }); } - + public void addDoubleClickListener(IDoubleClickListener listener) { tableViewer.addDoubleClickListener(listener); } @@ -102,7 +102,7 @@ public class VolumesPage extends Composite { private void setupVolumeTable(Composite parent, Table table) { table.setHeaderVisible(true); table.setLinesVisible(true); - + TableColumnLayout columnLayout = guiHelper.createTableColumnLayout(table, VOLUME_TABLE_COLUMN_NAMES); parent.setLayout(columnLayout); @@ -110,14 +110,18 @@ public class VolumesPage extends Composite { setColumnProperties(table, VOLUME_TABLE_COLUMN_INDICES.NUM_OF_DISKS, SWT.CENTER, 50); setColumnProperties(table, VOLUME_TABLE_COLUMN_INDICES.TRANSPORT_TYPE, SWT.CENTER, 70); } - - private TableViewer createVolumeTableViewer(Composite parent) { - TableViewer tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI); + + private CheckboxTableViewer createVolumeTableViewer(Composite parent) { + CheckboxTableViewer tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.FLAT | SWT.FULL_SELECTION + | SWT.MULTI); tableViewer.setLabelProvider(new VolumeTableLabelProvider()); tableViewer.setContentProvider(new EntityGroupContentProvider()); setupVolumeTable(parent, tableViewer.getTable()); + // make sure that table selection is driven by checkbox selection + guiHelper.configureCheckboxTableViewer(tableViewer); + return tableViewer; } @@ -134,10 +138,10 @@ public class VolumesPage extends Composite { Composite tableViewerComposite = createTableViewerComposite(); tableViewer = createVolumeTableViewer(tableViewerComposite); site.setSelectionProvider(tableViewer); - + // Create a case insensitive filter for the table viewer using the filter text field guiHelper.createFilter(tableViewer, filterText, false); - tableViewer.setInput(volumes); + tableViewer.setInput(volumes); } /** @@ -155,7 +159,7 @@ public class VolumesPage extends Composite { TableColumnLayout tableColumnLayout = (TableColumnLayout) table.getParent().getLayout(); tableColumnLayout.setColumnData(column, new ColumnWeightData(weight)); } - + public void setInput(EntityGroup volumes) { tableViewer.setInput(volumes); tableViewer.refresh(); diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/VolumesResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/VolumesResource.java index a2dfe2e3..53354706 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/VolumesResource.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/VolumesResource.java @@ -380,7 +380,8 @@ public class VolumesResource { diskName = diskInfo[1]; Object response = serverUtil.executeOnServer(true, serverName, VOLUME_DIRECTORY_CLEANUP_SCRIPT + " " - + diskName + " " + volumeName + " " + (deleteFlag ? "-d" : ""), GenericResponse.class); + + diskName.substring(0, diskName.lastIndexOf("/")) + " " + volumeName + " " + + (deleteFlag ? "-d" : ""), GenericResponse.class); if (response instanceof GenericResponse) { result = ((GenericResponse) response).getStatus(); if (!result.isSuccess()) { -- cgit From 7e460734791cf51b16161c6cb42474c0c8cf5d17 Mon Sep 17 00:00:00 2001 From: Dhandapani Date: Fri, 10 Jun 2011 12:04:06 +0530 Subject: Checkbox selection enabled on Bricks page, Volumes page and Disk page --- src/com.gluster.storage.management.gui/plugin.xml | 2 +- .../management/server/resources/VolumesResource.java | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/com.gluster.storage.management.gui/plugin.xml b/src/com.gluster.storage.management.gui/plugin.xml index 76d36d5c..4a7cdafe 100644 --- a/src/com.gluster.storage.management.gui/plugin.xml +++ b/src/com.gluster.storage.management.gui/plugin.xml @@ -900,7 +900,7 @@ disks, String volumeName, int maxIndex, boolean deleteFlag) { - String serverName, diskName, diskInfo[]; + private Status cleanupDirectories(List bricks, String volumeName, int maxIndex, boolean deleteFlag) { Status result; for (int i = 0; i < maxIndex; i++) { - diskInfo = disks.get(i).split(":"); - serverName = diskInfo[0]; - diskName = diskInfo[1]; + String[] brickInfo = bricks.get(i).split(":"); + String serverName = brickInfo[0]; + String brickDirectory = brickInfo[1]; + String mountPoint = brickDirectory.substring(0, brickDirectory.lastIndexOf("/")); Object response = serverUtil.executeOnServer(true, serverName, VOLUME_DIRECTORY_CLEANUP_SCRIPT + " " - + diskName.substring(0, diskName.lastIndexOf("/")) + " " + volumeName + " " - + (deleteFlag ? "-d" : ""), GenericResponse.class); + + mountPoint + " " + volumeName + " " + (deleteFlag ? "-d" : ""), GenericResponse.class); if (response instanceof GenericResponse) { result = ((GenericResponse) response).getStatus(); if (!result.isSuccess()) { -- cgit From 8d0fdb3cfc10ef6aaa37034c988118b1c1c6f440 Mon Sep 17 00:00:00 2001 From: Dhandapani Date: Fri, 10 Jun 2011 14:18:38 +0530 Subject: Duplicate Volume bricks view removed --- src/com.gluster.storage.management.gui/plugin.xml | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'src') diff --git a/src/com.gluster.storage.management.gui/plugin.xml b/src/com.gluster.storage.management.gui/plugin.xml index 4a7cdafe..56f08793 100644 --- a/src/com.gluster.storage.management.gui/plugin.xml +++ b/src/com.gluster.storage.management.gui/plugin.xml @@ -910,18 +910,6 @@ standalone="false" visible="false"> - - Date: Fri, 10 Jun 2011 16:11:36 +0530 Subject: Bug 2897 - Complete brick log file will not be downloaded --- .../storage/management/core/utils/FileUtil.java | 22 +++++++++++++++------- .../server/resources/VolumesResource.java | 8 ++++++++ 2 files changed, 23 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/FileUtil.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/FileUtil.java index d93ab2fb..d10dfee5 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/FileUtil.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/FileUtil.java @@ -107,20 +107,28 @@ public class FileUtil { * the file or dir to delete * @return true if all files are successfully deleted */ - public static boolean recursiveDelete(File fileOrDir) + public static void recursiveDelete(File fileOrDir) { if(fileOrDir.isDirectory()) { // recursively delete contents for(File innerFile: fileOrDir.listFiles()) { - if(!recursiveDelete(innerFile)) - { - return false; - } + recursiveDelete(innerFile); } } - return fileOrDir.delete(); + if(!fileOrDir.delete()) { + throw new GlusterRuntimeException("Couldn't delete file/directory [" + fileOrDir + "]"); + } + } + + public static void renameFile(String fromPath, String toPath) { + File fromFile = new File(fromPath); + File toFile = new File(toPath); + + if(!fromFile.renameTo(toFile)) { + throw new GlusterRuntimeException("Couldn't rename [" + fromFile + "] to [" + toFile + "]"); + } } -} \ No newline at end of file +} diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/VolumesResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/VolumesResource.java index c8796d27..1cbab5b0 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/VolumesResource.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/VolumesResource.java @@ -453,6 +453,7 @@ public class VolumesResource { output.write(FileUtil.readFileAsByteArray(archiveFile)); archiveFile.delete(); } catch (Exception e) { + // TODO: Log the exception e.printStackTrace(); throw new GlusterRuntimeException("Exception while downloading/archiving volume log files!", e); } @@ -472,6 +473,13 @@ public class VolumesResource { String logFilePath = logDir + CoreConstants.FILE_SEPARATOR + logFileName; serverUtil.getFileFromServer(brick.getServerName(), logFilePath, tempDirPath); + + String fetchedLogFile = tempDirPath + File.separator + logFileName; + // append log file name with server name so that log files don't overwrite each other + // in cases where the brick log file names are same on multiple servers + String localLogFile = tempDirPath + File.separator + brick.getServerName() + "-" + logFileName; + + FileUtil.renameFile(fetchedLogFile, localLogFile); } String gzipPath = FileUtil.getTempDirName() + CoreConstants.FILE_SEPARATOR + volume.getName() + "-logs.tar.gz"; -- cgit From 84b76fc94d2591af6507da452b7cc1c4d240a1b8 Mon Sep 17 00:00:00 2001 From: Shireesh Anjal Date: Fri, 10 Jun 2011 20:13:55 +0530 Subject: Introduced select all/none links in discovered servers and gluster servers views, removed redundant classes and performed some refactoring. --- .../storage/management/core/model/EntityGroup.java | 13 +- src/com.gluster.storage.management.gui/plugin.xml | 2 +- .../management/gui/BrickTableLabelProvider.java | 4 +- .../management/gui/DiskTableLabelProvider.java | 2 +- .../gui/GlusterServerTableLabelProvider.java | 2 +- .../gui/ServerDiskTableLabelProvider.java | 2 +- .../gui/VolumeLogTableLabelProvider.java | 2 +- .../gui/VolumeOptionsTableLabelProvider.java | 2 +- .../management/gui/actions/AddServerAction.java | 15 +- .../management/gui/actions/RemoveServerAction.java | 23 +- .../storage/management/gui/utils/GUIHelper.java | 5 +- .../gui/views/ClusterAdapterFactory.java | 101 +++ .../storage/management/gui/views/DisksView.java | 2 +- .../gui/views/GlusterServerDisksView.java | 2 +- .../gui/views/GlusterServerLogsView.java | 2 +- .../management/gui/views/GlusterServersView.java | 2 +- .../gui/views/NavigationTreeLabelDecorator.java | 87 +++ .../management/gui/views/NavigationView.java | 1 - .../management/gui/views/VolumeBricksView.java | 2 +- .../management/gui/views/VolumeLogsView.java | 2 +- .../management/gui/views/VolumeOptionsView.java | 2 +- .../gui/views/details/AbstractBricksPage.java | 156 ----- .../gui/views/details/AbstractDisksPage.java | 309 --------- .../management/gui/views/details/BricksPage.java | 107 ---- .../management/gui/views/details/DisksPage.java | 70 -- .../gui/views/details/GlusterServersPage.java | 197 ------ .../gui/views/details/OptionKeyEditingSupport.java | 125 ---- .../views/details/OptionValueEditingSupport.java | 115 ---- .../gui/views/details/ServerDisksPage.java | 68 -- .../gui/views/details/ServerLogsPage.java | 179 ------ .../management/gui/views/details/TabCreator.java | 49 -- .../gui/views/details/TabCreatorFactory.java | 32 - .../gui/views/details/TabCreatorFactoryImpl.java | 72 --- .../gui/views/details/VolumeLogsPage.java | 409 ------------ .../gui/views/details/VolumeOptionsPage.java | 359 ----------- .../gui/views/navigator/ClusterAdapterFactory.java | 101 --- .../navigator/NavigationTreeLabelDecorator.java | 87 --- .../gui/views/pages/AbstractBricksPage.java | 156 +++++ .../gui/views/pages/AbstractDisksPage.java | 309 +++++++++ .../gui/views/pages/AbstractTableViewerPage.java | 194 ++++++ .../management/gui/views/pages/BricksPage.java | 107 ++++ .../management/gui/views/pages/DisksPage.java | 70 ++ .../gui/views/pages/GlusterServersPage.java | 126 ++++ .../gui/views/pages/OptionKeyEditingSupport.java | 125 ++++ .../gui/views/pages/OptionValueEditingSupport.java | 115 ++++ .../gui/views/pages/ServerDisksPage.java | 68 ++ .../management/gui/views/pages/ServerLogsPage.java | 179 ++++++ .../management/gui/views/pages/ServersPage.java | 144 +---- .../management/gui/views/pages/VolumeLogsPage.java | 409 ++++++++++++ .../gui/views/pages/VolumeOptionsPage.java | 359 +++++++++++ .../WebContent/scripts/Protocol.py | 438 +++++++++++++ .../WebContent/scripts/Utils.py | 705 +++++++++++++++++++++ .../WebContent/scripts/XmlHandler.py | 346 ++++++++++ 53 files changed, 3982 insertions(+), 2578 deletions(-) create mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/ClusterAdapterFactory.java create mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/NavigationTreeLabelDecorator.java delete mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/AbstractBricksPage.java delete mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/AbstractDisksPage.java delete mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/BricksPage.java delete mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/DisksPage.java delete mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/GlusterServersPage.java delete mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/OptionKeyEditingSupport.java delete mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/OptionValueEditingSupport.java delete mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/ServerDisksPage.java delete mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/ServerLogsPage.java delete mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/TabCreator.java delete mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/TabCreatorFactory.java delete mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/TabCreatorFactoryImpl.java delete mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeLogsPage.java delete mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeOptionsPage.java delete mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/navigator/ClusterAdapterFactory.java delete mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/navigator/NavigationTreeLabelDecorator.java create mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractBricksPage.java create mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractDisksPage.java create mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableViewerPage.java create mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/BricksPage.java create mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/DisksPage.java create mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/GlusterServersPage.java create mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/OptionKeyEditingSupport.java create mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/OptionValueEditingSupport.java create mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServerDisksPage.java create mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServerLogsPage.java create mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumeLogsPage.java create mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumeOptionsPage.java create mode 100644 src/com.gluster.storage.management.server/WebContent/scripts/Protocol.py create mode 100644 src/com.gluster.storage.management.server/WebContent/scripts/Utils.py create mode 100644 src/com.gluster.storage.management.server/WebContent/scripts/XmlHandler.py (limited to 'src') diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/EntityGroup.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/EntityGroup.java index 0fc0f507..8e0311f5 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/EntityGroup.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/model/EntityGroup.java @@ -20,20 +20,21 @@ package com.gluster.storage.management.core.model; import java.util.List; -public class EntityGroup extends Entity { - private Class type; +public class EntityGroup extends Entity { + private Class type; - public EntityGroup(String name, Class type, Cluster cluster) { + public EntityGroup(String name, Class type, Cluster cluster) { this(name, type, cluster, null); } - public EntityGroup(String name, Class type, Cluster cluster, List entities) { + @SuppressWarnings("unchecked") + public EntityGroup(String name, Class type, Cluster cluster, List entities) { super(name, cluster, (List)entities); this.type = type; } - public List getEntities() { - return children; + public List getEntities() { + return (List)children; } public void setEntities(List entities) { diff --git a/src/com.gluster.storage.management.gui/plugin.xml b/src/com.gluster.storage.management.gui/plugin.xml index 56f08793..af065b7d 100644 --- a/src/com.gluster.storage.management.gui/plugin.xml +++ b/src/com.gluster.storage.management.gui/plugin.xml @@ -1012,7 +1012,7 @@ point="org.eclipse.ui.decorators"> selectedServers = GUIHelper.getInstance().getSelectedEntities(getWindow(), + Set selectedServers = guiHelper.getSelectedEntities(getWindow(), GlusterServer.class); if (!validate(action, selectedServers)) { @@ -66,6 +67,8 @@ public class RemoveServerAction extends AbstractActionDelegate { Set successServers = new HashSet(); String errMsg = ""; for (GlusterServer server : selectedServers) { + guiHelper.setStatusMessage("Removing server [" + server.getName() + "]..."); + GlusterServersClient client = new GlusterServersClient(); Status status = client.removeServer(server.getName()); if (status.isSuccess()) { @@ -77,8 +80,16 @@ public class RemoveServerAction extends AbstractActionDelegate { } } + guiHelper.clearStatusMessage(); showStatusMessage(action.getDescription(), selectedServers, successServers, errMsg); } + }; + + BusyIndicator.showWhile(Display.getDefault(), new Runnable() { + @Override + public void run() { + Display.getDefault().asyncExec(removeServerThread); + } }); } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/GUIHelper.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/GUIHelper.java index 9e2ec9e0..ac29ecf0 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/GUIHelper.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/GUIHelper.java @@ -290,15 +290,16 @@ public class GUIHelper { final String tooltipMessage = "Start typing to filter table contents."; final Text filterText = toolkit.createText(parent, "", SWT.FLAT); - GridData data = new GridData(SWT.LEFT, SWT.CENTER, false, false); + GridData data = new GridData(SWT.RIGHT, SWT.CENTER, false, false); data.widthHint = 300; filterText.setLayoutData(data); - ControlDecoration searchDecoration = new ControlDecoration(filterText, SWT.RIGHT); + ControlDecoration searchDecoration = new ControlDecoration(filterText, SWT.LEFT); searchDecoration.setImage(getImage(IImageKeys.SEARCH)); searchDecoration.show(); searchDecoration.setShowHover(true); searchDecoration.setDescriptionText(tooltipMessage); + searchDecoration.setMarginWidth(5); filterText.setToolTipText(tooltipMessage); return filterText; diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/ClusterAdapterFactory.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/ClusterAdapterFactory.java new file mode 100644 index 00000000..95c16a3c --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/ClusterAdapterFactory.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * This file is part of Gluster Management Console. + * + * Gluster Management Console is free software; you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Gluster Management Console 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 Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * . + *******************************************************************************/ +package com.gluster.storage.management.gui.views; + +import org.eclipse.core.runtime.IAdapterFactory; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.model.IWorkbenchAdapter; +import org.eclipse.ui.plugin.AbstractUIPlugin; + +import com.gluster.storage.management.core.model.Cluster; +import com.gluster.storage.management.core.model.Entity; +import com.gluster.storage.management.core.model.EntityGroup; +import com.gluster.storage.management.core.model.GlusterDataModel; +import com.gluster.storage.management.core.model.GlusterServer; +import com.gluster.storage.management.core.model.Server; +import com.gluster.storage.management.core.model.Volume; +import com.gluster.storage.management.gui.Application; +import com.gluster.storage.management.gui.IImageKeys; + +public class ClusterAdapterFactory implements IAdapterFactory { + private IWorkbenchAdapter entityAdapter = new IWorkbenchAdapter() { + + @Override + public Object getParent(Object o) { + return ((Entity) o).getParent(); + } + + @Override + public String getLabel(Object o) { + return ((Entity)o).getName(); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public ImageDescriptor getImageDescriptor(Object object) { + String iconPath = null; + + if(object instanceof GlusterDataModel || object instanceof Cluster) { + iconPath = IImageKeys.CLUSTER; + } + + if(object instanceof EntityGroup) { + Class entityType = ((EntityGroup) object).getEntityType(); + if(entityType == Volume.class) { + iconPath = IImageKeys.VOLUMES; + } else { + iconPath = IImageKeys.SERVERS; + } + } + + if(object instanceof Volume) { + iconPath = IImageKeys.VOLUME; + } + + if(object instanceof Server || object instanceof GlusterServer) { + iconPath = IImageKeys.SERVER; + } + + return AbstractUIPlugin.imageDescriptorFromPlugin( + Application.PLUGIN_ID, iconPath); + } + + @Override + public Object[] getChildren(Object o) { + return ((Entity)o).getChildren().toArray(); + } + }; + + @SuppressWarnings("rawtypes") + @Override + public Object getAdapter(Object adaptableObject, Class adapterType) { + if (adapterType == IWorkbenchAdapter.class) { + if (adaptableObject instanceof Entity) { + return entityAdapter; + } + } + return null; + } + + @SuppressWarnings("rawtypes") + @Override + public Class[] getAdapterList() { + return new Class[] { IWorkbenchAdapter.class }; + } +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/DisksView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/DisksView.java index 260d0d4c..0910c080 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/DisksView.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/DisksView.java @@ -11,7 +11,7 @@ import com.gluster.storage.management.core.model.Disk; import com.gluster.storage.management.core.model.EntityGroup; import com.gluster.storage.management.core.model.GlusterServer; import com.gluster.storage.management.gui.utils.GUIHelper; -import com.gluster.storage.management.gui.views.details.DisksPage; +import com.gluster.storage.management.gui.views.pages.DisksPage; public class DisksView extends ViewPart { public static final String ID = DisksView.class.getName(); diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServerDisksView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServerDisksView.java index 624d968d..2a240706 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServerDisksView.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServerDisksView.java @@ -26,7 +26,7 @@ import org.eclipse.ui.part.ViewPart; import com.gluster.storage.management.core.model.GlusterServer; import com.gluster.storage.management.gui.utils.GUIHelper; -import com.gluster.storage.management.gui.views.details.ServerDisksPage; +import com.gluster.storage.management.gui.views.pages.ServerDisksPage; public class GlusterServerDisksView extends ViewPart { public static final String ID = GlusterServerDisksView.class.getName(); diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServerLogsView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServerLogsView.java index acc8144d..84568ca6 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServerLogsView.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServerLogsView.java @@ -26,7 +26,7 @@ import org.eclipse.ui.part.ViewPart; import com.gluster.storage.management.core.model.GlusterServer; import com.gluster.storage.management.gui.utils.GUIHelper; -import com.gluster.storage.management.gui.views.details.ServerLogsPage; +import com.gluster.storage.management.gui.views.pages.ServerLogsPage; public class GlusterServerLogsView extends ViewPart { public static final String ID = GlusterServerLogsView.class.getName(); diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServersView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServersView.java index dfaf904a..05bf6778 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServersView.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServersView.java @@ -31,7 +31,7 @@ import com.gluster.storage.management.core.model.Entity; import com.gluster.storage.management.core.model.EntityGroup; import com.gluster.storage.management.core.model.GlusterServer; import com.gluster.storage.management.gui.utils.GUIHelper; -import com.gluster.storage.management.gui.views.details.GlusterServersPage; +import com.gluster.storage.management.gui.views.pages.GlusterServersPage; /** * @author root diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/NavigationTreeLabelDecorator.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/NavigationTreeLabelDecorator.java new file mode 100644 index 00000000..241b6967 --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/NavigationTreeLabelDecorator.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * This file is part of Gluster Management Console. + * + * Gluster Management Console is free software; you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Gluster Management Console 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 Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * . + *******************************************************************************/ +package com.gluster.storage.management.gui.views; + +import org.eclipse.jface.viewers.IDecoration; +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.jface.viewers.ILightweightLabelDecorator; +import org.eclipse.ui.plugin.AbstractUIPlugin; + +import com.gluster.storage.management.core.model.EntityGroup; +import com.gluster.storage.management.core.model.GlusterServer; +import com.gluster.storage.management.core.model.Server; +import com.gluster.storage.management.core.model.Volume; +import com.gluster.storage.management.gui.Application; +import com.gluster.storage.management.gui.IImageKeys; + +public class NavigationTreeLabelDecorator implements ILightweightLabelDecorator { + + @Override + public void addListener(ILabelProviderListener listener) { + } + + @Override + public void dispose() { + } + + @Override + public boolean isLabelProperty(Object element, String property) { + return false; + } + + @Override + public void removeListener(ILabelProviderListener listener) { + } + + @SuppressWarnings("rawtypes") + @Override + public void decorate(Object element, IDecoration decoration) { + if (element instanceof Volume) { + Volume volume = (Volume) element; + if (volume.getStatus() == Volume.VOLUME_STATUS.OFFLINE) { + decoration.addOverlay(AbstractUIPlugin.imageDescriptorFromPlugin(Application.PLUGIN_ID, + IImageKeys.OVERLAY_OFFLINE)); + } else { + decoration.addOverlay(AbstractUIPlugin.imageDescriptorFromPlugin(Application.PLUGIN_ID, + IImageKeys.OVERLAY_ONLINE)); + } + } + + if (element instanceof GlusterServer) { + GlusterServer server = (GlusterServer) element; + if (server.getStatus() == GlusterServer.SERVER_STATUS.OFFLINE) { + decoration.addOverlay(AbstractUIPlugin.imageDescriptorFromPlugin(Application.PLUGIN_ID, + IImageKeys.OVERLAY_OFFLINE)); + } else { + decoration.addOverlay(AbstractUIPlugin.imageDescriptorFromPlugin(Application.PLUGIN_ID, + IImageKeys.OVERLAY_ONLINE)); + } + } + + if (element instanceof Server) { + decoration.addOverlay(AbstractUIPlugin.imageDescriptorFromPlugin(Application.PLUGIN_ID, + IImageKeys.OVERLAY_STAR)); + } + + if(element instanceof EntityGroup && ((EntityGroup)element).getEntityType() == Server.class) { + decoration.addOverlay(AbstractUIPlugin.imageDescriptorFromPlugin(Application.PLUGIN_ID, + IImageKeys.OVERLAY_STAR)); + } + } +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/NavigationView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/NavigationView.java index a5da2f62..f737ea9d 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/NavigationView.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/NavigationView.java @@ -41,7 +41,6 @@ import com.gluster.storage.management.core.model.Event; import com.gluster.storage.management.core.model.GlusterDataModel; import com.gluster.storage.management.core.model.Volume; import com.gluster.storage.management.gui.toolbar.GlusterToolbarManager; -import com.gluster.storage.management.gui.views.navigator.ClusterAdapterFactory; public class NavigationView extends ViewPart implements ISelectionListener { public static final String ID = NavigationView.class.getName(); diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumeBricksView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumeBricksView.java index e6b9bec3..712882ee 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumeBricksView.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumeBricksView.java @@ -7,7 +7,7 @@ import org.eclipse.ui.part.ViewPart; import com.gluster.storage.management.client.GlusterDataModelManager; import com.gluster.storage.management.core.model.Volume; import com.gluster.storage.management.gui.utils.GUIHelper; -import com.gluster.storage.management.gui.views.details.BricksPage; +import com.gluster.storage.management.gui.views.pages.BricksPage; public class VolumeBricksView extends ViewPart { public static final String ID = VolumeBricksView.class.getName(); diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumeLogsView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumeLogsView.java index b6c98ad3..89c343d7 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumeLogsView.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumeLogsView.java @@ -6,7 +6,7 @@ import org.eclipse.ui.part.ViewPart; import com.gluster.storage.management.core.model.Volume; import com.gluster.storage.management.gui.utils.GUIHelper; -import com.gluster.storage.management.gui.views.details.VolumeLogsPage; +import com.gluster.storage.management.gui.views.pages.VolumeLogsPage; public class VolumeLogsView extends ViewPart { VolumeLogsPage logsPage; diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumeOptionsView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumeOptionsView.java index e8695737..0780cf6a 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumeOptionsView.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumeOptionsView.java @@ -6,7 +6,7 @@ import org.eclipse.ui.part.ViewPart; import com.gluster.storage.management.core.model.Volume; import com.gluster.storage.management.gui.utils.GUIHelper; -import com.gluster.storage.management.gui.views.details.VolumeOptionsPage; +import com.gluster.storage.management.gui.views.pages.VolumeOptionsPage; public class VolumeOptionsView extends ViewPart { public static final String ID = VolumeOptionsView.class.getName(); diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/AbstractBricksPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/AbstractBricksPage.java deleted file mode 100644 index 412a1ef2..00000000 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/AbstractBricksPage.java +++ /dev/null @@ -1,156 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * This file is part of Gluster Management Console. - * - * Gluster Management Console is free software; you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Gluster Management Console 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 Affero General Public License - * for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see - * . - *******************************************************************************/ -package com.gluster.storage.management.gui.views.details; - -import java.util.List; - -import org.eclipse.jface.viewers.ArrayContentProvider; -import org.eclipse.jface.viewers.CheckboxTableViewer; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.custom.TableEditor; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.events.PaintEvent; -import org.eclipse.swt.events.PaintListener; -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.Display; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableItem; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.IWorkbenchSite; -import org.eclipse.ui.forms.events.HyperlinkAdapter; -import org.eclipse.ui.forms.events.HyperlinkEvent; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.ImageHyperlink; - -import com.gluster.storage.management.core.model.Brick; -import com.gluster.storage.management.core.model.Disk; -import com.gluster.storage.management.core.model.Disk.DISK_STATUS; -import com.gluster.storage.management.core.model.Entity; -import com.gluster.storage.management.gui.Application; -import com.gluster.storage.management.gui.IEntityListener; -import com.gluster.storage.management.gui.jobs.InitializeDiskJob; -import com.gluster.storage.management.gui.utils.GUIHelper; - -public abstract class AbstractBricksPage extends Composite implements IEntityListener { - protected final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); - protected CheckboxTableViewer tableViewer; - private IWorkbenchSite site; - protected static final GUIHelper guiHelper = GUIHelper.getInstance(); - - /** - * Setup properties of the table e.g. column headers, widths, etc. - * - * @param parent - * The parent composite. (TableColumnLayout has to be set on this) - * @param table - * The table to be set up - */ - protected abstract void setupDiskTable(Composite parent, Table table); - - /** - * @return The label provider to be used with the disk table viewer - */ - protected abstract ITableLabelProvider getTableLabelProvider(); - - /** - * @return Index of the "status" column in the table. Return -1 if status column is not displayed - */ - protected abstract int getStatusColumnIndex(); - - private void init(final Composite parent, IWorkbenchSite site, List bricks) { - addDisposeListener(new DisposeListener() { - public void widgetDisposed(DisposeEvent e) { - toolkit.dispose(); - } - }); - - this.site = site; - - setupPageLayout(); - Text filterText = guiHelper.createFilterText(toolkit, this); - setupBrickTableViewer(createTableViewerComposite(), filterText); - site.setSelectionProvider(tableViewer); - - tableViewer.setInput(bricks); - - site.setSelectionProvider(tableViewer); - Application.getApplication().addEntityListener(this); - - parent.layout(); // Important - this actually paints the table - - toolkit.adapt(this); - toolkit.paintBordersFor(this); - - /** - * Ideally not required. However the table viewer is not getting laid out properly on performing - * "maximize + restore" So this is a hack to make sure that the table is laid out again on re-size of the window - */ - addPaintListener(new PaintListener() { - @Override - public void paintControl(PaintEvent e) { - parent.layout(); - } - }); - } - - public AbstractBricksPage(final Composite parent, int style, IWorkbenchSite site, List bricks) { - super(parent, style); - init(parent, site, bricks); - } - - private void setupPageLayout() { - final GridLayout layout = new GridLayout(1, false); - layout.verticalSpacing = 10; - layout.marginTop = 10; - setLayout(layout); - } - - private Composite createTableViewerComposite() { - Composite tableViewerComposite = new Composite(this, SWT.NO); - tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); - tableViewerComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - return tableViewerComposite; - } - - private CheckboxTableViewer createBrickTableViewer(Composite parent) { - tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI ); - - tableViewer.setLabelProvider(getTableLabelProvider()); - tableViewer.setContentProvider(new ArrayContentProvider()); - - setupDiskTable(parent, tableViewer.getTable()); - - // make sure that table selection is driven by checkbox selection - guiHelper.configureCheckboxTableViewer(tableViewer); - - return tableViewer; - } - - private void setupBrickTableViewer(Composite parent, final Text filterText) { - tableViewer = createBrickTableViewer(parent); - // Create a case insensitive filter for the table viewer using the filter text field - guiHelper.createFilter(tableViewer, filterText, false); - } -} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/AbstractDisksPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/AbstractDisksPage.java deleted file mode 100644 index 105fa824..00000000 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/AbstractDisksPage.java +++ /dev/null @@ -1,309 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * This file is part of Gluster Management Console. - * - * Gluster Management Console is free software; you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Gluster Management Console 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 Affero General Public License - * for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see - * . - *******************************************************************************/ -package com.gluster.storage.management.gui.views.details; - -import java.util.List; - -import org.eclipse.jface.viewers.ArrayContentProvider; -import org.eclipse.jface.viewers.CheckboxTableViewer; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.custom.TableEditor; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.events.PaintEvent; -import org.eclipse.swt.events.PaintListener; -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.Display; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableItem; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.IWorkbenchSite; -import org.eclipse.ui.forms.events.HyperlinkAdapter; -import org.eclipse.ui.forms.events.HyperlinkEvent; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.ImageHyperlink; - -import com.gluster.storage.management.core.model.Disk; -import com.gluster.storage.management.core.model.Disk.DISK_STATUS; -import com.gluster.storage.management.core.model.Entity; -import com.gluster.storage.management.gui.Application; -import com.gluster.storage.management.gui.IEntityListener; -import com.gluster.storage.management.gui.jobs.InitializeDiskJob; -import com.gluster.storage.management.gui.utils.GUIHelper; - -public abstract class AbstractDisksPage extends Composite implements IEntityListener { - protected final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); - protected CheckboxTableViewer tableViewer; - private IWorkbenchSite site; - protected static final GUIHelper guiHelper = GUIHelper.getInstance(); - - /** - * Setup properties of the table e.g. column headers, widths, etc. - * - * @param parent - * The parent composite. (TableColumnLayout has to be set on this) - * @param table - * The table to be set up - */ - protected abstract void setupDiskTable(Composite parent, Table table); - - /** - * @return The label provider to be used with the disk table viewer - */ - protected abstract ITableLabelProvider getTableLabelProvider(); - - /** - * @return Index of the "status" column in the table. Return -1 if status column is not displayed - */ - protected abstract int getStatusColumnIndex(); - - private void init(final Composite parent, IWorkbenchSite site, List disks) { - addDisposeListener(new DisposeListener() { - public void widgetDisposed(DisposeEvent e) { - toolkit.dispose(); - } - }); - - this.site = site; - - setupPageLayout(); - Text filterText = guiHelper.createFilterText(toolkit, this); - setupDiskTableViewer(createTableViewerComposite(), filterText); - site.setSelectionProvider(tableViewer); - - tableViewer.setInput(disks); - setupStatusCellEditor(); // creates hyperlinks for "unitialized" disks - - site.setSelectionProvider(tableViewer); - Application.getApplication().addEntityListener(this); - - parent.layout(); // Important - this actually paints the table - - toolkit.adapt(this); - toolkit.paintBordersFor(this); - - /** - * Ideally not required. However the table viewer is not getting laid out properly on performing - * "maximize + restore" So this is a hack to make sure that the table is laid out again on re-size of the window - */ - addPaintListener(new PaintListener() { - - @Override - public void paintControl(PaintEvent e) { - parent.layout(); - } - }); - } - - public AbstractDisksPage(final Composite parent, int style, IWorkbenchSite site, List disks) { - super(parent, style); - init(parent, site, disks); - } - - private void setupPageLayout() { - final GridLayout layout = new GridLayout(1, false); - layout.verticalSpacing = 10; - layout.marginTop = 10; - setLayout(layout); - } - - private void createInitializeLink(final TableItem item, final int rowNum, final Disk disk) { - final Table table = tableViewer.getTable(); - final TableEditor editor = new TableEditor(table); - editor.grabHorizontal = true; - editor.horizontalAlignment = SWT.RIGHT; - - table.addPaintListener(new PaintListener() { - private TableItem myItem = item; - private int myRowNum = rowNum; - private ImageHyperlink myLink = null; - private TableEditor myEditor = null; - - private void createLinkFor(Disk disk1, TableItem item1, int rowNum1) { - myItem = item1; - myRowNum = rowNum1; - - myEditor = new TableEditor(table); - myEditor.grabHorizontal = true; - myEditor.horizontalAlignment = SWT.RIGHT; - - myLink = toolkit.createImageHyperlink(table, SWT.NONE); - // link.setImage(guiHelper.getImage(IImageKeys.DISK_UNINITIALIZED)); - myLink.setText("Initialize"); - myLink.addHyperlinkListener(new StatusLinkListener(myLink, myEditor, myItem, tableViewer, disk1, site)); - - myEditor.setEditor(myLink, item1, getStatusColumnIndex()); - - myItem.addDisposeListener(new DisposeListener() { - @Override - public void widgetDisposed(DisposeEvent e) { - myLink.dispose(); - myEditor.dispose(); - } - }); - } - - @Override - public void paintControl(PaintEvent e) { - int itemCount = table.getItemCount(); - - // Find the table item corresponding to our disk - Disk disk1 = null; - int rowNum1 = -1; - TableItem item1 = null; - for (int i = 0; i < itemCount; i++) { - item1 = table.getItem(i); - disk1 = (Disk) item1.getData(); - if (disk1 != null && disk1 == disk) { - rowNum1 = i; - break; - } - } - - if (rowNum1 == -1) { - // item disposed and disk not visible. nothing to do. - return; - } - - if (myEditor == null || myItem.isDisposed()) { - // item visible, and - // either editor never created, OR - // old item disposed. create the link for it - createLinkFor(disk1, item1, rowNum1); - } - - if (rowNum1 != myRowNum) { - // disk visible, but at a different row num. re-create the link - myLink.dispose(); - myEditor.dispose(); - createLinkFor(disk1, item1, rowNum1); - } - - myEditor.layout(); // IMPORTANT. Without this, the link location goes for a toss on maximize + restore - } - }); - } - - private void setupStatusCellEditor() { - final TableViewer viewer = tableViewer; - final Table table = viewer.getTable(); - for (int i = 0; i < table.getItemCount(); i++) { - final TableItem item = table.getItem(i); - if (item.isDisposed() || item.getData() == null) { - continue; - } - final Disk disk = (Disk) item.getData(); - if (disk.isUninitialized()) { - createInitializeLink(item, i, disk); - } - } - } - - private Composite createTableViewerComposite() { - Composite tableViewerComposite = new Composite(this, SWT.NO); - tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); - tableViewerComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - return tableViewerComposite; - } - - private CheckboxTableViewer createDiskTableViewer(Composite parent) { - tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI ); - - tableViewer.setLabelProvider(getTableLabelProvider()); - tableViewer.setContentProvider(new ArrayContentProvider()); - - setupDiskTable(parent, tableViewer.getTable()); - - // make sure that table selection is driven by checkbox selection - guiHelper.configureCheckboxTableViewer(tableViewer); - - return tableViewer; - } - - private void setupDiskTableViewer(Composite parent, final Text filterText) { - tableViewer = createDiskTableViewer(parent); - // Create a case insensitive filter for the table viewer using the filter text field - guiHelper.createFilter(tableViewer, filterText, false); - } - - private final class StatusLinkListener extends HyperlinkAdapter { - private final Disk disk; - private final TableEditor myEditor; - private final ImageHyperlink myLink; - private final TableViewer viewer; - private final IWorkbenchSite site; - - private StatusLinkListener(ImageHyperlink link, TableEditor editor, TableItem item, TableViewer viewer, - Disk disk, IWorkbenchSite site) { - this.disk = disk; - this.viewer = viewer; - this.myEditor = editor; - this.myLink = link; - this.site = site; - } - - private void updateStatus(final DISK_STATUS status, final boolean disposeEditor) { - if (disposeEditor) { - myLink.dispose(); - myEditor.dispose(); - } - disk.setStatus(status); - viewer.update(disk, new String[] { "status" }); - Application.getApplication().entityChanged(disk, new String[] { "status" }); - } - - @Override - public void linkActivated(HyperlinkEvent e) { - updateStatus(DISK_STATUS.INITIALIZING, true); - guiHelper.showProgressView(); - - new InitializeDiskJob(disk).schedule(); - } - } - - @Override - public void entityChanged(final Entity entity, final String[] paremeters) { - if (!(entity instanceof Disk)) { - return; - } - final Disk disk = (Disk) entity; - - Display.getDefault().syncExec(new Runnable() { - public void run() { - tableViewer.update(disk, paremeters); - - if (disk.isUninitialized()) { - Table table = tableViewer.getTable(); - - for (int rowNum = 0; rowNum < table.getItemCount(); rowNum++) { - TableItem item = table.getItem(rowNum); - if (item.getData() == disk) { - createInitializeLink(item, rowNum, disk); - } - } - } - } - }); - } -} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/BricksPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/BricksPage.java deleted file mode 100644 index 51425174..00000000 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/BricksPage.java +++ /dev/null @@ -1,107 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * This file is part of Gluster Management Console. - * - * Gluster Management Console is free software; you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Gluster Management Console 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 Affero General Public License - * for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see - * . - *******************************************************************************/ -package com.gluster.storage.management.gui.views.details; - -import java.util.List; - -import org.eclipse.jface.layout.TableColumnLayout; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Table; -import org.eclipse.ui.IWorkbenchSite; - -import com.gluster.storage.management.client.GlusterDataModelManager; -import com.gluster.storage.management.core.model.Brick; -import com.gluster.storage.management.core.model.ClusterListener; -import com.gluster.storage.management.core.model.DefaultClusterListener; -import com.gluster.storage.management.core.model.Entity; -import com.gluster.storage.management.core.model.Event; -import com.gluster.storage.management.core.model.Volume; -import com.gluster.storage.management.core.model.Event.EVENT_TYPE; -import com.gluster.storage.management.gui.BrickTableLabelProvider; - -public class BricksPage extends AbstractBricksPage { - private Composite parent; - - public enum BRICK_TABLE_COLUMN_INDICES { - SERVER, BRICK, FREE_SPACE, TOTAL_SPACE, STATUS - }; - - private static final String[] DISK_TABLE_COLUMN_NAMES = new String[] { "Server", "Brick Directory", "Free Space (GB)", - "Total Space (GB)", "Status" }; - - public BricksPage(final Composite parent, int style, IWorkbenchSite site, final List bricks) { - super(parent, style, site, bricks); - createListeners(); - } - - private void createListeners() { - final ClusterListener clusterListener = new DefaultClusterListener() { - @Override - public void volumeChanged(Volume volume, Event event) { - if (event.getEventType() == EVENT_TYPE.BRICKS_ADDED || event.getEventType() == EVENT_TYPE.BRICKS_REMOVED) { - tableViewer.refresh(); - parent.update(); - } - - } - }; - GlusterDataModelManager.getInstance().addClusterListener(clusterListener); - addDisposeListener(new DisposeListener() { - - @Override - public void widgetDisposed(DisposeEvent e) { - GlusterDataModelManager.getInstance().removeClusterListener(clusterListener); - } - }); - } - - @Override - protected void setupDiskTable(Composite parent, Table table) { - this.parent = parent; - table.setHeaderVisible(true); - table.setLinesVisible(false); - - TableColumnLayout tableColumnLayout = guiHelper.createTableColumnLayout(table, DISK_TABLE_COLUMN_NAMES); - parent.setLayout(tableColumnLayout); - - guiHelper.setColumnProperties(table, BRICK_TABLE_COLUMN_INDICES.SERVER.ordinal(), SWT.CENTER, 100); - guiHelper.setColumnProperties(table, BRICK_TABLE_COLUMN_INDICES.BRICK.ordinal(), SWT.CENTER, 100); - guiHelper.setColumnProperties(table, BRICK_TABLE_COLUMN_INDICES.FREE_SPACE.ordinal(), SWT.CENTER, 90); - guiHelper.setColumnProperties(table, BRICK_TABLE_COLUMN_INDICES.TOTAL_SPACE.ordinal(), SWT.CENTER, 90); - - } - - @Override - protected ITableLabelProvider getTableLabelProvider() { - return new BrickTableLabelProvider(); - } - - @Override - protected int getStatusColumnIndex() { - return BRICK_TABLE_COLUMN_INDICES.STATUS.ordinal(); - } - - @Override - public void entityChanged(Entity entity, String[] paremeters) { - } -} \ No newline at end of file diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/DisksPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/DisksPage.java deleted file mode 100644 index 9076d498..00000000 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/DisksPage.java +++ /dev/null @@ -1,70 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * This file is part of Gluster Management Console. - * - * Gluster Management Console is free software; you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Gluster Management Console 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 Affero General Public License - * for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see - * . - *******************************************************************************/ -package com.gluster.storage.management.gui.views.details; - -import java.util.List; - -import org.eclipse.jface.layout.TableColumnLayout; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.swt.SWT; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Table; -import org.eclipse.ui.IWorkbenchSite; - -import com.gluster.storage.management.core.model.Disk; -import com.gluster.storage.management.gui.DiskTableLabelProvider; - -public class DisksPage extends AbstractDisksPage { - - public enum DISK_TABLE_COLUMN_INDICES { - SERVER, DISK, FREE_SPACE, TOTAL_SPACE, STATUS - }; - - private static final String[] DISK_TABLE_COLUMN_NAMES = new String[] { "Server", "Disk", "Free Space (GB)", - "Total Space (GB)", "Status" }; - - public DisksPage(final Composite parent, int style, IWorkbenchSite site, List disks) { - super(parent, style, site, disks); - } - - @Override - protected void setupDiskTable(Composite parent, Table table) { - table.setHeaderVisible(true); - table.setLinesVisible(false); - - TableColumnLayout tableColumnLayout = guiHelper.createTableColumnLayout(table, DISK_TABLE_COLUMN_NAMES); - parent.setLayout(tableColumnLayout); - - guiHelper.setColumnProperties(table, DISK_TABLE_COLUMN_INDICES.SERVER.ordinal(), SWT.CENTER, 100); - guiHelper.setColumnProperties(table, DISK_TABLE_COLUMN_INDICES.DISK.ordinal(), SWT.CENTER, 100); - guiHelper.setColumnProperties(table, DISK_TABLE_COLUMN_INDICES.FREE_SPACE.ordinal(), SWT.CENTER, 90); - guiHelper.setColumnProperties(table, DISK_TABLE_COLUMN_INDICES.TOTAL_SPACE.ordinal(), SWT.CENTER, 90); - // guiHelper.setColumnProperties(table, DISK_TABLE_COLUMN_INDICES.SPACE_IN_USE.ordinal(), SWT.CENTER, 90); - } - - @Override - protected ITableLabelProvider getTableLabelProvider() { - return new DiskTableLabelProvider(); - } - - @Override - protected int getStatusColumnIndex() { - return DISK_TABLE_COLUMN_INDICES.STATUS.ordinal(); - } -} \ No newline at end of file diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/GlusterServersPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/GlusterServersPage.java deleted file mode 100644 index 36f60998..00000000 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/GlusterServersPage.java +++ /dev/null @@ -1,197 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * This file is part of Gluster Management Console. - * - * Gluster Management Console is free software; you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Gluster Management Console 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 Affero General Public License - * for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see - * . - *******************************************************************************/ -package com.gluster.storage.management.gui.views.details; - -import org.eclipse.jface.layout.TableColumnLayout; -import org.eclipse.jface.viewers.CheckboxTableViewer; -import org.eclipse.jface.viewers.ColumnWeightData; -import org.eclipse.jface.viewers.IDoubleClickListener; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.events.PaintEvent; -import org.eclipse.swt.events.PaintListener; -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.Display; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.IWorkbenchSite; -import org.eclipse.ui.forms.widgets.FormToolkit; - -import com.gluster.storage.management.client.GlusterDataModelManager; -import com.gluster.storage.management.core.model.ClusterListener; -import com.gluster.storage.management.core.model.DefaultClusterListener; -import com.gluster.storage.management.core.model.EntityGroup; -import com.gluster.storage.management.core.model.Event; -import com.gluster.storage.management.core.model.GlusterServer; -import com.gluster.storage.management.gui.EntityGroupContentProvider; -import com.gluster.storage.management.gui.GlusterServerTableLabelProvider; -import com.gluster.storage.management.gui.utils.GUIHelper; - -public class GlusterServersPage extends Composite { - - private final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); - private CheckboxTableViewer tableViewer; - private GUIHelper guiHelper = GUIHelper.getInstance(); - - public enum GLUSTER_SERVER_TABLE_COLUMN_INDICES { - NAME, IP_ADDRESSES, NUM_OF_CPUS, TOTAL_MEMORY, TOTAL_DISK_SPACE, AVAILABLE_DISK_SPACE, STATUS // Removed PREFERRED_NETWORK - }; - - private static final String[] GLUSTER_SERVER_TABLE_COLUMN_NAMES = new String[] { "Name", - "IP Address(es)", "Number\nof CPUs", "Total\nMemory (GB)", "Space (GB)", "Space\nAvailable (GB)", "Status" }; // Removed "Preferred\nNetwork", - - public GlusterServersPage(IWorkbenchSite site, final Composite parent, int style, EntityGroup servers) { - super(parent, style); - - toolkit.adapt(this); - toolkit.paintBordersFor(this); - - setupPageLayout(); - Text filterText = guiHelper.createFilterText(toolkit, this); - setupServerTableViewer(site, filterText); - - tableViewer.setInput(servers); - parent.layout(); // Important - this actually paints the table - - createListeners(parent); - } - - private void createListeners(final Composite parent) { - /** - * Ideally not required. However the table viewer is not getting laid out properly on performing - * "maximize + restore" So this is a hack to make sure that the table is laid out again on re-size of the window - */ - addPaintListener(new PaintListener() { - - @Override - public void paintControl(PaintEvent e) { - parent.layout(); - } - }); - - final ClusterListener clusterListener = new DefaultClusterListener() { - - @Override - public void serverAdded(GlusterServer server) { - tableViewer.refresh(); - } - - @Override - public void serverRemoved(GlusterServer server) { - tableViewer.refresh(); - } - - @Override - public void serverChanged(GlusterServer server, Event event) { - tableViewer.update(server, null); - } - }; - - final GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance(); - modelManager.addClusterListener(clusterListener); - - addDisposeListener(new DisposeListener() { - public void widgetDisposed(DisposeEvent e) { - toolkit.dispose(); - modelManager.removeClusterListener(clusterListener); - } - }); - } - - public void addDoubleClickListener(IDoubleClickListener listener) { - tableViewer.addDoubleClickListener(listener); - } - - private void setupPageLayout() { - final GridLayout layout = new GridLayout(1, false); - layout.verticalSpacing = 10; - layout.marginTop = 10; - setLayout(layout); - } - - private void setupServerTable(Composite parent, Table table) { - table.setHeaderVisible(true); - table.setLinesVisible(false); - - TableColumnLayout tableColumnLayout = guiHelper.createTableColumnLayout(table, GLUSTER_SERVER_TABLE_COLUMN_NAMES); - parent.setLayout(tableColumnLayout); - - setColumnProperties(table, GLUSTER_SERVER_TABLE_COLUMN_INDICES.NAME, SWT.CENTER, 100); - setColumnProperties(table, GLUSTER_SERVER_TABLE_COLUMN_INDICES.STATUS, SWT.CENTER, 70); - // setColumnProperties(table, GLUSTER_SERVER_TABLE_COLUMN_INDICES.PREFERRED_NETWORK, SWT.CENTER, 90); - setColumnProperties(table, GLUSTER_SERVER_TABLE_COLUMN_INDICES.NUM_OF_CPUS, SWT.CENTER, 90); - //setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.CPU_USAGE, SWT.CENTER, 90); - setColumnProperties(table, GLUSTER_SERVER_TABLE_COLUMN_INDICES.TOTAL_MEMORY, SWT.CENTER, 90); - //setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.MEMORY_IN_USE, SWT.CENTER, 90); - setColumnProperties(table, GLUSTER_SERVER_TABLE_COLUMN_INDICES.TOTAL_DISK_SPACE, SWT.CENTER, 90); - setColumnProperties(table, GLUSTER_SERVER_TABLE_COLUMN_INDICES.AVAILABLE_DISK_SPACE, SWT.CENTER, 90); - //setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.DISK_SPACE_IN_USE, SWT.CENTER, 90); - } - - private CheckboxTableViewer createServerTableViewer(Composite parent) { - CheckboxTableViewer tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI); - //TableViewer tableViewer = new TableViewer(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI); - tableViewer.setLabelProvider(new GlusterServerTableLabelProvider()); - tableViewer.setContentProvider(new EntityGroupContentProvider()); - - setupServerTable(parent, tableViewer.getTable()); - - return tableViewer; - } - - private Composite createTableViewerComposite() { - Composite tableViewerComposite = new Composite(this, SWT.NO); - tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); - tableViewerComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - return tableViewerComposite; - } - - private void setupServerTableViewer(IWorkbenchSite site, final Text filterText) { - Composite tableViewerComposite = createTableViewerComposite(); - tableViewer = createServerTableViewer(tableViewerComposite); - site.setSelectionProvider(tableViewer); - - // make sure that table selection is driven by checkbox selection - guiHelper.configureCheckboxTableViewer(tableViewer); - - // Create a case insensitive filter for the table viewer using the filter text field - guiHelper.createFilter(tableViewer, filterText, false); - } - - /** - * Sets properties for alignment and weight of given column of given table - * - * @param table - * @param columnIndex - * @param alignment - * @param weight - */ - public void setColumnProperties(Table table, GLUSTER_SERVER_TABLE_COLUMN_INDICES columnIndex, int alignment, int weight) { - TableColumn column = table.getColumn(columnIndex.ordinal()); - column.setAlignment(alignment); - - TableColumnLayout tableColumnLayout = (TableColumnLayout) table.getParent().getLayout(); - tableColumnLayout.setColumnData(column, new ColumnWeightData(weight)); - } -} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/OptionKeyEditingSupport.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/OptionKeyEditingSupport.java deleted file mode 100644 index 27dc8d4b..00000000 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/OptionKeyEditingSupport.java +++ /dev/null @@ -1,125 +0,0 @@ -/** - * - */ -package com.gluster.storage.management.gui.views.details; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import org.eclipse.jface.viewers.CellEditor; -import org.eclipse.jface.viewers.ColumnViewer; -import org.eclipse.jface.viewers.ComboBoxCellEditor; -import org.eclipse.jface.viewers.EditingSupport; -import org.eclipse.swt.SWT; -import org.eclipse.swt.widgets.Composite; - -import com.gluster.storage.management.client.GlusterDataModelManager; -import com.gluster.storage.management.core.model.Volume; -import com.gluster.storage.management.core.model.VolumeOptionInfo; - -/** - * Editing support for the "value" column in volume options table viewer. - */ -public class OptionKeyEditingSupport extends EditingSupport { - private CellEditor cellEditor; - private Volume volume; - private List defaults = GlusterDataModelManager.getInstance().getVolumeOptionsDefaults(); - private String[] allowedKeys; - private ColumnViewer viewer; - - public OptionKeyEditingSupport(ColumnViewer viewer, Volume volume) { - super(viewer); - this.volume = volume; - this.viewer = viewer; - } - - /** - * @return array of option keys that are not already set on the volume - */ - private String[] getAllowedKeys() { - ArrayList keys = new ArrayList(); - Map volumeOptions = volume.getOptions(); - for(VolumeOptionInfo optionInfo : defaults) { - String optionName = optionInfo.getName(); - if(!volumeOptions.containsKey(optionName) || volumeOptions.get(optionName).isEmpty()) { - // key not set => available for setting - // value not set => this is the row being edited - keys.add(optionName); - } - } - return keys.toArray(new String[0]); - } - - @SuppressWarnings("unchecked") - @Override - protected void setValue(final Object element, final Object value) { - Entry oldEntry = (Entry)element; - Integer newValue = (Integer)value; - String newKey = allowedKeys[newValue]; - - if (((Entry)element).getKey().equals(newKey)) { - // selected value is same as old one. - return; - } - - // value has changed. set new value and refresh the viewer. - volume.getOptions().remove(oldEntry.getKey()); - volume.setOption(newKey, ""); - getViewer().refresh(); - } - - @Override - protected Object getValue(Object element) { - Entry entryBeingAdded = getEntryBeingAdded(); - if(entryBeingAdded == null) { - return cellEditor.getValue(); - } - - if(entryBeingAdded.getKey().isEmpty()) { - // editing just about to start. set first element as default. - return 0; - } - - return getIndexOfEntry(entryBeingAdded); - } - - @Override - protected CellEditor getCellEditor(Object element) { - allowedKeys = getAllowedKeys(); - cellEditor = new ComboBoxCellEditor((Composite) viewer.getControl(), allowedKeys, SWT.READ_ONLY); - return cellEditor; - } - - private int getIndexOfEntry(Entry entryBeingAdded) { - for(int index = 0; index < allowedKeys.length; index++) { - if(allowedKeys[index].equals(entryBeingAdded.getKey())) { - return index; - } - } - return -1; - } - - protected Entry getEntryBeingAdded() { - Entry entryBeingAdded = null; - Iterator> iter = volume.getOptions().entrySet().iterator(); - while(iter.hasNext()) { - Entry nextEntry = iter.next(); - if(!iter.hasNext() && nextEntry.getValue().isEmpty()) { - // it's the LAST entry, and it's value is empty. - // means this is a new row being added in the table viewer. - entryBeingAdded = nextEntry; - } - } - return entryBeingAdded; - } - - @SuppressWarnings("unchecked") - @Override - protected boolean canEdit(Object element) { - Entry entry = (Entry)element; - return (entry.getKey().isEmpty() || entry.getValue().isEmpty()); - } -} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/OptionValueEditingSupport.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/OptionValueEditingSupport.java deleted file mode 100644 index ca222dd0..00000000 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/OptionValueEditingSupport.java +++ /dev/null @@ -1,115 +0,0 @@ -/** - * - */ -package com.gluster.storage.management.gui.views.details; - -import java.util.List; -import java.util.Map.Entry; - -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.viewers.CellEditor; -import org.eclipse.jface.viewers.ColumnViewer; -import org.eclipse.jface.viewers.EditingSupport; -import org.eclipse.jface.viewers.TextCellEditor; -import org.eclipse.swt.custom.BusyIndicator; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; - -import com.gluster.storage.management.client.GlusterDataModelManager; -import com.gluster.storage.management.client.VolumesClient; -import com.gluster.storage.management.core.model.Status; -import com.gluster.storage.management.core.model.Volume; -import com.gluster.storage.management.core.model.VolumeOptionInfo; -import com.gluster.storage.management.gui.utils.GUIHelper; - -/** - * Editing support for the "value" column in volume options table viewer. - */ -public class OptionValueEditingSupport extends EditingSupport { - private CellEditor cellEditor; - private Volume volume; - private List defaults = GlusterDataModelManager.getInstance().getVolumeOptionsDefaults(); - private GUIHelper guiHelper = GUIHelper.getInstance(); - - public OptionValueEditingSupport(ColumnViewer viewer, Volume volume) { - super(viewer); - this.volume = volume; - this.cellEditor = new TextCellEditor((Composite) viewer.getControl()); - } - - @SuppressWarnings("unchecked") - @Override - protected void setValue(final Object element, final Object value) { - final Entry entry = (Entry) element; - final String optionKey = entry.getKey(); - final String optionValue = (String)value; - final String oldValue = entry.getValue(); - - // It is not allowed to change value to empty string - if(optionValue.isEmpty()) { - MessageDialog.openError(Display.getDefault().getActiveShell(), "Set Volume Option", - "Option value can't be empty! Please enter a valid value."); - cellEditor.setFocus(); - return; - } - - if (oldValue.equals(optionValue)) { - // value is same as that present in the model. return without doing anything. - return; - } - - // value has changed. set volume option at back-end and update model accordingly - guiHelper.setStatusMessage("Setting option [" + optionKey + " = " + optionValue + "]..."); - getViewer().getControl().update(); - - BusyIndicator.showWhile(Display.getDefault(), new Runnable() { - - @Override - public void run() { - VolumesClient client = new VolumesClient(); - Status status = client.setVolumeOption(volume.getName(), entry.getKey(), (String) value); - if (status.isSuccess()) { - entry.setValue((String)value); - GlusterDataModelManager.getInstance().setVolumeOption(volume, entry); - } else { - MessageDialog.openError(Display.getDefault().getActiveShell(), "Set Volume Option", - status.getMessage()); - } - getViewer().update(entry, null); - } - }); - - guiHelper.clearStatusMessage(); - getViewer().getControl().update(); - } - - /** - * @param key Key whose default value is to be fetched - * @return Default value of the volume option with given key - */ - private String getDefaultValue(String key) { - for(VolumeOptionInfo optionInfo : defaults) { - if(optionInfo.getName().equals(key)) { - return optionInfo.getDefaultValue(); - } - } - return ""; - } - - @SuppressWarnings("unchecked") - @Override - protected Object getValue(Object element) { - Entry entry = (Entry) element; - return entry.getValue().isEmpty() ? getDefaultValue(entry.getKey()) : entry.getValue(); - } - - @Override - protected CellEditor getCellEditor(Object element) { - return cellEditor; - } - - @Override - protected boolean canEdit(Object element) { - return true; - } -} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/ServerDisksPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/ServerDisksPage.java deleted file mode 100644 index bace2af9..00000000 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/ServerDisksPage.java +++ /dev/null @@ -1,68 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * This file is part of Gluster Management Console. - * - * Gluster Management Console is free software; you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Gluster Management Console 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 Affero General Public License - * for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see - * . - *******************************************************************************/ -package com.gluster.storage.management.gui.views.details; - -import java.util.List; - -import org.eclipse.jface.layout.TableColumnLayout; -import org.eclipse.swt.SWT; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Table; -import org.eclipse.ui.IWorkbenchSite; - -import com.gluster.storage.management.core.model.Disk; -import com.gluster.storage.management.gui.ServerDiskTableLabelProvider; -import com.gluster.storage.management.gui.TableLabelProviderAdapter; - -public class ServerDisksPage extends AbstractDisksPage { - public ServerDisksPage(Composite parent, int style, IWorkbenchSite site, List disks) { - super(parent, style, site, disks); - } - - public enum SERVER_DISK_TABLE_COLUMN_INDICES { - DISK, SPACE, SPACE_IN_USE, STATUS - }; - - private static final String[] SERVER_DISK_TABLE_COLUMN_NAMES = new String[] { "Disk", "Space (GB)", - "Space in Use (GB)", "Status" }; - - @Override - protected void setupDiskTable(Composite parent, Table table) { - table.setHeaderVisible(true); - table.setLinesVisible(false); - - TableColumnLayout tableColumnLayout = guiHelper.createTableColumnLayout(table, SERVER_DISK_TABLE_COLUMN_NAMES); - parent.setLayout(tableColumnLayout); - - guiHelper.setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.DISK.ordinal(), SWT.CENTER, 100); - guiHelper.setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.SPACE.ordinal(), SWT.CENTER, 90); - guiHelper.setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.SPACE_IN_USE.ordinal(), SWT.CENTER, 90); - guiHelper.setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.STATUS.ordinal(), SWT.LEFT, 90); - } - - @Override - protected int getStatusColumnIndex() { - return SERVER_DISK_TABLE_COLUMN_INDICES.STATUS.ordinal(); - } - - @Override - protected TableLabelProviderAdapter getTableLabelProvider() { - return new ServerDiskTableLabelProvider(); - } -} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/ServerLogsPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/ServerLogsPage.java deleted file mode 100644 index a499caf3..00000000 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/ServerLogsPage.java +++ /dev/null @@ -1,179 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * This file is part of Gluster Management Console. - * - * Gluster Management Console is free software; you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Gluster Management Console 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 Affero General Public License - * for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see - * . - *******************************************************************************/ -package com.gluster.storage.management.gui.views.details; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.jface.viewers.ArrayContentProvider; -import org.eclipse.jface.viewers.ListViewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.forms.widgets.FormToolkit; - -import com.gluster.storage.management.core.model.GlusterServer; -import com.gluster.storage.management.gui.utils.GUIHelper; - -public class ServerLogsPage extends Composite { - - private final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); - private final GUIHelper guiHelper = GUIHelper.getInstance(); - private Text text; - private Table table; - - public enum LOG_TABLE_COLUMN_INDICES { - DATE, TIME, DISK, SEVERITY, MESSAGE - }; - - private static final String[] LOG_TABLE_COLUMN_NAMES = new String[] { "Date", "Time", "Disk", "Severity", "Message" }; - - /** - * Create the composite. - * - * @param parent - * @param style - */ - public ServerLogsPage(Composite parent, int style, GlusterServer server) { - super(parent, style); - addDisposeListener(new DisposeListener() { - public void widgetDisposed(DisposeEvent e) { - toolkit.dispose(); - } - }); - toolkit.adapt(this); - toolkit.paintBordersFor(this); - - setLayout(new GridLayout(1, false)); - GridData layoutData = new GridData(); - layoutData.grabExcessHorizontalSpace = true; - layoutData.grabExcessVerticalSpace = true; - setLayoutData(layoutData); - - Composite composite = toolkit.createComposite(this, SWT.NONE); - toolkit.paintBordersFor(composite); - - Label lblScanLast = toolkit.createLabel(composite, "Scan last", SWT.NONE); - lblScanLast.setBounds(0, 15, 80, 20); - - text = toolkit.createText(composite, "100", SWT.NONE); - text.setBounds(85, 15, 60, 20); - - Label lblMessagesAndFilter = toolkit.createLabel(composite, " messages from ", SWT.CENTER); - lblMessagesAndFilter.setBounds(160, 15, 110, 20); - - Combo combo = new Combo(composite, SWT.CENTER); - combo.setBounds(295, 15, 100, 20); - combo.setItems(new String[] { "syslog", "dmesg" }); - toolkit.adapt(combo); - toolkit.paintBordersFor(combo); - combo.select(0); - - Button btngo = toolkit.createButton(composite, "&Go", SWT.NONE); - btngo.setBounds(410, 13, 50, 30); - - Label separator = toolkit.createLabel(composite, "", SWT.SEPARATOR | SWT.HORIZONTAL | SWT.FILL); - separator.setBounds(0, 50, 500, 2); - - Label lblFilterString = toolkit.createLabel(composite, "Filter String", SWT.LEFT); - lblFilterString.setBounds(0, 65, 100, 20); - - text = guiHelper.createFilterText(toolkit, composite); - text.setBounds(105, 65, 250, 20); - - Composite logContentsComposite = createLogContentsComposite(toolkit); - // Text logContentsText = toolkit.createText(logContentsComposite, "", SWT.MULTI | SWT.FLAT | SWT.BORDER); - // logContentsText.setEditable(false); - // populateDummyLogContent(logContentsText); - - ListViewer logViewer = new ListViewer(logContentsComposite, SWT.BORDER | SWT.V_SCROLL | SWT.NO); - logViewer.setContentProvider(new ArrayContentProvider()); - guiHelper.createFilter(logViewer, text, false); - logViewer.setInput(getDummyLogContents()); - - // TODO: Link the filter string with the contents text - } - - private Composite createLogContentsComposite(FormToolkit toolkit) { - Composite tableViewerComposite = toolkit.createComposite(this, SWT.NONE); - tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); - GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true); - layoutData.verticalIndent = 10; - tableViewerComposite.setLayoutData(layoutData); - return tableViewerComposite; - } - - private String[] getDummyLogContents() { - - String[] logMessages = { - "Jan 19 13:43:08 shireesh-laptop dhclient: last message repeated 6 times", - "Jan 19 13:44:08 shireesh-laptop dhclient: last message repeated 5 times", - "Jan 19 13:44:47 shireesh-laptop dhclient: last message repeated 2 times", - "Jan 19 13:44:47 shireesh-laptop dhclient: DHCPREQUEST of 192.168.1.174 on eth1 to 255.255.255.255 port 67", - "Jan 19 13:45:49 shireesh-laptop dhclient: last message repeated 6 times", - "Jan 19 13:46:59 shireesh-laptop dhclient: last message repeated 6 times", - "Jan 19 13:48:01 shireesh-laptop dhclient: last message repeated 4 times", - "Jan 19 13:49:02 shireesh-laptop dhclient: last message repeated 5 times", - "Jan 19 13:50:08 shireesh-laptop dhclient: last message repeated 4 times", - "Jan 19 13:51:08 shireesh-laptop dhclient: last message repeated 6 times", - "Jan 19 13:52:08 shireesh-laptop dhclient: last message repeated 4 times", - "Jan 19 13:53:08 shireesh-laptop dhclient: last message repeated 6 times", - "Jan 19 13:54:08 shireesh-laptop dhclient: last message repeated 5 times", - "Jan 19 13:55:08 shireesh-laptop dhclient: last message repeated 4 times", - "Jan 19 13:56:08 shireesh-laptop dhclient: last message repeated 4 times", - "Jan 19 13:57:08 shireesh-laptop dhclient: last message repeated 3 times", - "Jan 19 13:58:08 shireesh-laptop dhclient: last message repeated 6 times", - "Jan 19 13:59:08 shireesh-laptop dhclient: last message repeated 4 times", - "Jan 19 13:59:40 shireesh-laptop dhclient: last message repeated 3 times", - "Jan 19 13:59:40 shireesh-laptop NetworkManager: DHCP: device eth1 state changed bound -> expire", - "Jan 19 13:59:40 shireesh-laptop dhclient: DHCPDISCOVER on eth1 to 255.255.255.255 port 67 interval 8", - "Jan 19 13:59:40 shireesh-laptop NetworkManager: DHCP: device eth1 state changed expire -> preinit", - "Jan 19 13:59:40 shireesh-laptop dhclient: DHCPOFFER of 192.168.1.174 from 192.168.1.1", - "Jan 19 13:59:40 shireesh-laptop dhclient: DHCPREQUEST of 192.168.1.174 on eth1 to 255.255.255.255 port 67", - "Jan 19 13:59:40 shireesh-laptop dhclient: DHCPACK of 192.168.1.174 from 192.168.1.1", - "Jan 19 13:59:40 shireesh-laptop dhclient: bound to 192.168.1.174 -- renewal in 3205 seconds.", - "Jan 19 13:59:40 shireesh-laptop NetworkManager: DHCP: device eth1 state changed preinit -> bound", - "Jan 19 13:59:40 shireesh-laptop NetworkManager: address 192.168.1.174", - "Jan 19 13:59:40 shireesh-laptop NetworkManager: prefix 24 (255.255.255.0)", - "Jan 19 13:59:40 shireesh-laptop NetworkManager: gateway 192.168.1.1", - "Jan 19 13:59:40 shireesh-laptop NetworkManager: nameserver '192.168.1.1'", - "Jan 19 13:59:40 shireesh-laptop NetworkManager: domain name 'in.gluster.com'", - "Jan 19 14:03:53 shireesh-laptop avahi-daemon[1098]: Invalid legacy unicast query packet.", - "Jan 19 14:03:53 shireesh-laptop avahi-daemon[1098]: Received response from host 192.168.1.155 with invalid source port 37219 on interface 'eth0.0'", - "Jan 19 14:03:54 shireesh-laptop avahi-daemon[1098]: Invalid legacy unicast query packet.", - "Jan 19 14:03:54 shireesh-laptop avahi-daemon[1098]: Invalid legacy unicast query packet.", - "Jan 19 14:03:54 shireesh-laptop avahi-daemon[1098]: Received response from host 192.168.1.155 with invalid source port 37219 on interface 'eth0.0'", - "Jan 19 14:05:09 shireesh-laptop avahi-daemon[1098]: last message repeated 8 times", - "Jan 19 14:12:48 shireesh-laptop NetworkManager: [1295426568.002642] periodic_update(): Roamed from BSSID E0:CB:4E:C0:0B:7F (glfs) to (none) ((none))", - "Jan 19 14:12:54 shireesh-laptop NetworkManager: [1295426574.002448] periodic_update(): Roamed from BSSID (none) ((none)) to E0:CB:4E:C0:0B:7F (glfs)", - "Jan 19 14:17:01 shireesh-laptop CRON[5321]: (root) CMD ( cd / && run-parts --report /etc/cron.hourly)" }; - - return logMessages; - } -} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/TabCreator.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/TabCreator.java deleted file mode 100644 index 1f5f8a15..00000000 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/TabCreator.java +++ /dev/null @@ -1,49 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * This file is part of Gluster Management Console. - * - * Gluster Management Console is free software; you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Gluster Management Console 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 Affero General Public License - * for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see - * . - *******************************************************************************/ -package com.gluster.storage.management.gui.views.details; - -import org.eclipse.swt.widgets.TabFolder; -import org.eclipse.ui.IWorkbenchSite; -import org.eclipse.ui.forms.widgets.FormToolkit; - -import com.gluster.storage.management.core.model.Entity; - -/** - * For every entity that can be selected from the navigation view (cluster tree), a set of tabs are created on the - * details view. Each entity has a corresponding tab creator that creates these tabs. These tab creators must implement - * this interface. - *

- * Important: Tab creators are cached for performance reasons. Hence they should not store any state information - * in class level variables. - */ -public interface TabCreator { - /** - * Creates tabs for the given entity - * - * @param entity - * Entity for which tabs are to be created - * @param tabFolder - * The tab folder in which the tabs are to be created - * @param toolkit - * The form toolkit that can be used for create components using Forms API - * @param site - * The workbench site that can be used to register as a selection provider - */ - public void createTabs(Entity entity, TabFolder tabFolder, FormToolkit toolkit, IWorkbenchSite site); -} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/TabCreatorFactory.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/TabCreatorFactory.java deleted file mode 100644 index f5098af5..00000000 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/TabCreatorFactory.java +++ /dev/null @@ -1,32 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * This file is part of Gluster Management Console. - * - * Gluster Management Console is free software; you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Gluster Management Console 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 Affero General Public License - * for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see - * . - *******************************************************************************/ -package com.gluster.storage.management.gui.views.details; - -import com.gluster.storage.management.core.model.Entity; - -/** - * Interface for tab creator factory. - */ -public interface TabCreatorFactory { - /** - * @param entity The entity for which tab creator factory is to be returned - * @return A tab creator factory for given entity - */ - public TabCreator getTabCreator(Entity entity); -} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/TabCreatorFactoryImpl.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/TabCreatorFactoryImpl.java deleted file mode 100644 index 28d3d4aa..00000000 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/TabCreatorFactoryImpl.java +++ /dev/null @@ -1,72 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * This file is part of Gluster Management Console. - * - * Gluster Management Console is free software; you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Gluster Management Console 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 Affero General Public License - * for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see - * . - *******************************************************************************/ -package com.gluster.storage.management.gui.views.details; - -import java.util.HashMap; -import java.util.Map; - -import com.gluster.storage.management.core.exceptions.GlusterRuntimeException; -import com.gluster.storage.management.core.model.Entity; -import com.gluster.storage.management.core.model.EntityGroup; - -public class TabCreatorFactoryImpl implements TabCreatorFactory { - - private Map tabCreatorCache = new HashMap(); - - /** - * Returns tab creator for given entity. The logic is as follows:
- * 1) Check if an tab creator is already created for the "class" of the entity. In case of {@link EntityGroup}, - * append the class name with entity type
- * 2) If the tab creator is found in the cache, return it
- * 3) If not found, create one by instantiating the class ".tabcreators.TabCreator". - * Again, "class name" includes "entity type" in case of {@link EntityGroup}
- * 4) Add the newly created tab creator to the cache and return it - */ - @SuppressWarnings("rawtypes") - @Override - public TabCreator getTabCreator(Entity entity) { - Class entityClass = entity.getClass(); - String key = entityClass.getSimpleName(); - if (entityClass == EntityGroup.class) { - // If it's an entity group, add the entity type to the key - key += ((EntityGroup) entity).getEntityType().getSimpleName(); - } - - TabCreator tabCreator = tabCreatorCache.get(key); - if (tabCreator == null) { - // Not created yet. Create one and add to the cache - String className = getClass().getPackage().getName() + ".tabcreators." + key + "TabCreator"; - try { - Class creatorFactoryClass = (Class) Class.forName(className); - tabCreator = creatorFactoryClass.newInstance(); - tabCreatorCache.put(key, tabCreator); - } catch (ClassNotFoundException e) { - throw new GlusterRuntimeException("Could not load creator factory class [" + className + "]", e); - } catch (InstantiationException e) { - throw new GlusterRuntimeException("Could not create instance of creator factory class [" + className - + "]", e); - } catch (IllegalAccessException e) { - throw new GlusterRuntimeException("Could not create instance of creator factory class [" + className - + "]", e); - } - } - - return tabCreator; - } -} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeLogsPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeLogsPage.java deleted file mode 100644 index 9eb7357e..00000000 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeLogsPage.java +++ /dev/null @@ -1,409 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * This file is part of Gluster Management Console. - * - * Gluster Management Console is free software; you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Gluster Management Console 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 Affero General Public License - * for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see - * . - *******************************************************************************/ -package com.gluster.storage.management.gui.views.details; - -import java.util.Calendar; -import java.util.Date; -import java.util.List; - -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.layout.TableColumnLayout; -import org.eclipse.jface.viewers.ArrayContentProvider; -import org.eclipse.jface.viewers.ColumnWeightData; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.DateTime; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.forms.widgets.FormToolkit; - -import com.gluster.storage.management.client.GlusterDataModelManager; -import com.gluster.storage.management.client.VolumesClient; -import com.gluster.storage.management.core.constants.CoreConstants; -import com.gluster.storage.management.core.constants.GlusterConstants; -import com.gluster.storage.management.core.constants.GlusterConstants.VOLUME_LOG_LEVELS; -import com.gluster.storage.management.core.model.VolumeLogMessage; -import com.gluster.storage.management.core.model.Status; -import com.gluster.storage.management.core.model.Volume; -import com.gluster.storage.management.core.response.LogMessageListResponse; -import com.gluster.storage.management.core.utils.GlusterCoreUtil; -import com.gluster.storage.management.gui.VolumeLogTableLabelProvider; -import com.gluster.storage.management.gui.utils.GUIHelper; - -public class VolumeLogsPage extends Composite { - - private final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); - private final GUIHelper guiHelper = GUIHelper.getInstance(); - private Text filterText; - private Text lineCountText; - private Volume volume; - - public enum LOG_TABLE_COLUMN_INDICES { - DATE, TIME, BRICK, SEVERITY, MESSAGE - }; - - private static final String[] LOG_TABLE_COLUMN_NAMES = new String[] { "Date", "Time", "Brick", "Severity", "Message" }; - private TableViewer tableViewer; - private Combo bricksCombo; - private Combo severityCombo; - private DateTime fromDate; - private DateTime fromTime; - private DateTime toDate; - private DateTime toTime; - private Button fromCheckbox; - private Button toCheckbox; - - /** - * Create the volume logs page - * - * @param parent - * @param style - * @param volume - * Volume for which the logs page is to be created - */ - public VolumeLogsPage(Composite parent, int style, Volume volume) { - super(parent, style); - this.volume = volume; - - addDisposeListener(new DisposeListener() { - public void widgetDisposed(DisposeEvent e) { - toolkit.dispose(); - } - }); - toolkit.adapt(this); - toolkit.paintBordersFor(this); - - configureLayout(); - - Composite composite = toolkit.createComposite(this, SWT.NONE); - toolkit.paintBordersFor(composite); - - createLineCountLabel(composite); - createLineCountText(composite); - - createBricksLabel(composite); - createBricksCombo(composite); - - createSeverityLabel(composite); - createSeverityCombo(composite); - - createFromDateLabel(composite); - createFromDateField(composite); - createFromTimeField(composite); - createFromCheckbox(composite); - - createToDateLabel(composite); - createToDateField(composite); - createToTimeField(composite); - createToCheckbox(composite); - - createSearchButton(composite); - - createSeparator(composite); - - createFilterLabel(composite); - createFilterText(composite); - - createLogTableViewer(); - } - - private void createLogTableViewer() { - Composite tableViewerComposite = createTableViewerComposite(); - - tableViewer = new TableViewer(tableViewerComposite, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI); - tableViewer.setLabelProvider(new VolumeLogTableLabelProvider()); - tableViewer.setContentProvider(new ArrayContentProvider()); - - setupLogsTable(tableViewerComposite, tableViewer.getTable()); - guiHelper.createFilter(tableViewer, filterText, false); - } - - private void createFilterText(Composite composite) { - filterText = guiHelper.createFilterText(toolkit, composite); - filterText.setBounds(90, 105, 250, 20); - } - - private void createFilterLabel(Composite composite) { - Label lblFilterString = toolkit.createLabel(composite, "Filter String", SWT.LEFT); - lblFilterString.setBounds(0, 105, 85, 20); - } - - private void createSeparator(Composite composite) { - Label separator = toolkit.createLabel(composite, "", SWT.SEPARATOR | SWT.HORIZONTAL | SWT.FILL); - separator.setBounds(0, 95, 680, 2); - } - - private void createSearchButton(Composite composite) { - Button btnGo = toolkit.createButton(composite, "&Go", SWT.NONE); - btnGo.setBounds(615, 55, 50, 30); - btnGo.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - VolumesClient client = new VolumesClient(); - - Date fromTimestamp = null; - Date toTimestamp = null; - - if (fromCheckbox.getSelection()) { - fromTimestamp = extractTimestamp(fromDate, fromTime); - } - - if (toCheckbox.getSelection()) { - toTimestamp = extractTimestamp(toDate, toTime); - } - - if (!validateTimeRange(fromTimestamp, toTimestamp)) { - return; - } - - LogMessageListResponse response = client.getLogs(volume.getName(), bricksCombo.getText(), - severityCombo.getText(), fromTimestamp, toTimestamp, Integer.parseInt(lineCountText.getText())); - Status status = response.getStatus(); - if (status.isSuccess()) { - List logMessages = response.getLogMessages(); - tableViewer.setInput(logMessages.toArray(new VolumeLogMessage[0])); - tableViewer.refresh(); - } else { - MessageDialog.openError(getShell(), "Volume Logs", "Error while fetching volume logs: [" + status - + "]"); - } - } - }); - } - - protected boolean validateTimeRange(Date fromTimestamp, Date toTimestamp) { - if (fromTimestamp == null && toTimestamp == null) { - // no time range selected. nothing to validate. - return true; - } - - Calendar calendar = Calendar.getInstance(); - Date now = calendar.getTime(); - if (fromTimestamp != null && fromTimestamp.after(now)) { - MessageDialog.openError(getShell(), "Volume Logs", "From time can't be greater than current time!"); - return false; - } - - if (toTimestamp != null) { - if (toTimestamp.after(now)) { - MessageDialog.openError(getShell(), "Volume Logs", "To time can't be greater than current time!"); - return false; - } - - if (fromTimestamp.after(toTimestamp)) { - MessageDialog.openError(getShell(), "Volume Logs", "From time can't be greater than To time!"); - return false; - } - } - - return true; - } - - private void createToCheckbox(Composite composite) { - toCheckbox = toolkit.createButton(composite, null, SWT.CHECK); - toCheckbox.setBounds(320, 60, 15, 20); - toCheckbox.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - if (toCheckbox.getSelection()) { - toDate.setEnabled(true); - toTime.setEnabled(true); - } else { - toDate.setEnabled(false); - toTime.setEnabled(false); - } - } - }); - } - - private void createToTimeField(Composite composite) { - toTime = new DateTime(composite, SWT.BORDER | SWT.TIME); - toTime.setBounds(490, 60, 120, 20); - toTime.setEnabled(false); - toolkit.adapt(toTime); - toolkit.paintBordersFor(toTime); - } - - private void createToDateField(Composite composite) { - toDate = new DateTime(composite, SWT.BORDER | SWT.DROP_DOWN); - toDate.setBounds(365, 60, 120, 20); - toDate.setEnabled(false); - toolkit.adapt(toDate); - toolkit.paintBordersFor(toDate); - } - - private void createToDateLabel(Composite composite) { - Label lblTo = toolkit.createLabel(composite, "To", SWT.NONE); - lblTo.setBounds(340, 60, 25, 20); - } - - private void createFromCheckbox(Composite composite) { - fromCheckbox = toolkit.createButton(composite, null, SWT.CHECK); - fromCheckbox.setBounds(0, 60, 15, 20); - fromCheckbox.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - if (fromCheckbox.getSelection()) { - fromDate.setEnabled(true); - fromTime.setEnabled(true); - } else { - fromDate.setEnabled(false); - fromTime.setEnabled(false); - } - } - }); - } - - private void createFromTimeField(Composite composite) { - fromTime = new DateTime(composite, SWT.BORDER | SWT.TIME); - fromTime.setBounds(190, 60, 120, 20); - fromTime.setEnabled(false); - toolkit.adapt(fromTime); - toolkit.paintBordersFor(fromTime); - } - - private void createFromDateField(Composite composite) { - fromDate = new DateTime(composite, SWT.BORDER | SWT.DROP_DOWN); - fromDate.setBounds(60, 60, 120, 20); - fromDate.setEnabled(false); - toolkit.adapt(fromDate); - toolkit.paintBordersFor(fromDate); - } - - private void createFromDateLabel(Composite composite) { - Label lblFrom = toolkit.createLabel(composite, "from", SWT.NONE); - lblFrom.setBounds(20, 60, 40, 20); - } - - private void createSeverityCombo(Composite composite) { - severityCombo = new Combo(composite, SWT.READ_ONLY); - severityCombo.setBounds(555, 15, 110, 20); - - severityCombo.setItems(GlusterConstants.VOLUME_LOG_LEVELS_ARR.toArray(new String[0])); - severityCombo.select(VOLUME_LOG_LEVELS.ERROR.ordinal()); - severityCombo.add(CoreConstants.ALL, 0); - - toolkit.adapt(severityCombo); - toolkit.paintBordersFor(severityCombo); - } - - private void createSeverityLabel(Composite composite) { - Label lblSeverity = toolkit.createLabel(composite, "Severity", SWT.NONE); - lblSeverity.setBounds(480, 15, 70, 20); - } - - private void createBricksCombo(Composite composite) { - bricksCombo = new Combo(composite, SWT.READ_ONLY); - bricksCombo.setBounds(365, 15, 100, 20); - bricksCombo.setItems( volume.getBrickDirectories().toArray(new String[0])); - bricksCombo.add(CoreConstants.ALL, 0); - toolkit.adapt(bricksCombo); - toolkit.paintBordersFor(bricksCombo); - bricksCombo.select(0); - } - - private void createBricksLabel(Composite composite) { - Label lblMessagesAndFilter = toolkit.createLabel(composite, "messages, and filter on bricks", SWT.NONE); - lblMessagesAndFilter.setBounds(160, 15, 200, 20); - } - - private void createLineCountText(Composite composite) { - lineCountText = toolkit.createText(composite, "100", SWT.NONE); - lineCountText.setBounds(85, 15, 60, 20); - } - - private void createLineCountLabel(Composite composite) { - Label lblScanLast = toolkit.createLabel(composite, "Scan last", SWT.NONE); - lblScanLast.setBounds(0, 15, 80, 20); - } - - private void configureLayout() { - setLayout(new GridLayout(1, false)); - GridData layoutData = new GridData(); - layoutData.grabExcessHorizontalSpace = true; - layoutData.grabExcessVerticalSpace = true; - // layoutData.verticalIndent = 10; - setLayoutData(layoutData); - } - - private Composite createTableViewerComposite() { - Composite tableViewerComposite = new Composite(this, SWT.NO); - tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); - GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true); - layoutData.verticalIndent = 10; - tableViewerComposite.setLayoutData(layoutData); - return tableViewerComposite; - } - - private void setupLogsTable(Composite parent, Table table) { - table.setHeaderVisible(true); - table.setLinesVisible(false); - - TableColumnLayout tableColumnLayout = guiHelper.createTableColumnLayout(table, LOG_TABLE_COLUMN_NAMES); - parent.setLayout(tableColumnLayout); - - setColumnProperties(table, LOG_TABLE_COLUMN_INDICES.DATE, SWT.CENTER, 50); - setColumnProperties(table, LOG_TABLE_COLUMN_INDICES.TIME, SWT.CENTER, 50); - setColumnProperties(table, LOG_TABLE_COLUMN_INDICES.BRICK, SWT.CENTER, 50); - setColumnProperties(table, LOG_TABLE_COLUMN_INDICES.SEVERITY, SWT.CENTER, 50); - setColumnProperties(table, LOG_TABLE_COLUMN_INDICES.MESSAGE, SWT.LEFT, 100); - } - - /** - * Sets properties for alignment and weight of given column of given table - * - * @param table - * @param columnIndex - * @param alignment - * @param weight - */ - private void setColumnProperties(Table table, LOG_TABLE_COLUMN_INDICES columnIndex, int alignment, int weight) { - TableColumn column = table.getColumn(columnIndex.ordinal()); - column.setAlignment(alignment); - - TableColumnLayout tableColumnLayout = (TableColumnLayout) table.getParent().getLayout(); - tableColumnLayout.setColumnData(column, new ColumnWeightData(weight)); - } - - private Date extractTimestamp(DateTime date, DateTime time) { - Calendar calendar = Calendar.getInstance(); - calendar.setLenient(false); - calendar.set(Calendar.DAY_OF_MONTH, date.getDay()); - // in Calendar class, month starts with zero i.e. Jan = 0 - calendar.set(Calendar.MONTH, date.getMonth()); - calendar.set(Calendar.YEAR, date.getYear()); - calendar.set(Calendar.HOUR_OF_DAY, time.getHours()); - calendar.set(Calendar.MINUTE, time.getMinutes()); - calendar.set(Calendar.SECOND, time.getSeconds()); - return calendar.getTime(); - } -} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeOptionsPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeOptionsPage.java deleted file mode 100644 index 22d38e50..00000000 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/details/VolumeOptionsPage.java +++ /dev/null @@ -1,359 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * This file is part of Gluster Management Console. - * - * Gluster Management Console is free software; you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Gluster Management Console 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 Affero General Public License - * for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see - * . - *******************************************************************************/ -package com.gluster.storage.management.gui.views.details; - -import java.util.List; -import java.util.Map.Entry; - -import org.apache.commons.lang.WordUtils; -import org.eclipse.jface.layout.TableColumnLayout; -import org.eclipse.jface.viewers.ArrayContentProvider; -import org.eclipse.jface.viewers.ColumnLabelProvider; -import org.eclipse.jface.viewers.ColumnLayoutData; -import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; -import org.eclipse.jface.viewers.ColumnWeightData; -import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.TableViewerColumn; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.PaintEvent; -import org.eclipse.swt.events.PaintListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.forms.widgets.FormToolkit; - -import com.gluster.storage.management.client.GlusterDataModelManager; -import com.gluster.storage.management.core.constants.CoreConstants; -import com.gluster.storage.management.core.model.DefaultClusterListener; -import com.gluster.storage.management.core.model.Event; -import com.gluster.storage.management.core.model.Event.EVENT_TYPE; -import com.gluster.storage.management.core.model.Volume; -import com.gluster.storage.management.core.model.VolumeOptionInfo; -import com.gluster.storage.management.gui.VolumeOptionsTableLabelProvider; -import com.gluster.storage.management.gui.utils.GUIHelper; - -public class VolumeOptionsPage extends Composite { - - private final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); - private TableViewer tableViewer; - private GUIHelper guiHelper = GUIHelper.getInstance(); - private Volume volume; - private DefaultClusterListener clusterListener; - private Text filterText; - private List defaultVolumeOptions = GlusterDataModelManager.getInstance() - .getVolumeOptionsDefaults(); - - public enum OPTIONS_TABLE_COLUMN_INDICES { - OPTION_KEY, OPTION_VALUE - }; - - private static final String[] OPTIONS_TABLE_COLUMN_NAMES = new String[] { "Option Key", "Option Value" }; - private Button addTopButton; - private Button addBottomButton; - private TableViewerColumn keyColumn; - private OptionKeyEditingSupport keyEditingSupport; - - public VolumeOptionsPage(final Composite parent, int style, Volume volume) { - super(parent, style); - - this.volume = volume; - - toolkit.adapt(this); - toolkit.paintBordersFor(this); - - setupPageLayout(); - filterText = guiHelper.createFilterText(toolkit, this); - - addTopButton = createAddButton(); - setupOptionsTableViewer(filterText); - - addBottomButton = createAddButton(); - - if (defaultVolumeOptions.size() == volume.getOptions().size()) { - setAddButtonsEnabled(false); - } - - tableViewer.setInput(volume.getOptions().entrySet()); - - parent.layout(); // Important - this actually paints the table - registerListeners(parent); - } - - private void setAddButtonsEnabled(boolean enable) { - addTopButton.setEnabled(enable); - addBottomButton.setEnabled(enable); - } - - private Button createAddButton() { - Button button = toolkit.createButton(this, "&Add", SWT.FLAT); - button.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - // add an empty option to be filled up by user - volume.setOption("", ""); - - tableViewer.refresh(); - tableViewer.setSelection(new StructuredSelection(getEntry(""))); - keyColumn.getViewer().editElement(getEntry(""), 0); // edit newly created entry - - // disable the add button AND search filter textbox till user fills up the new option - setAddButtonsEnabled(false); - filterText.setEnabled(false); - } - - private Entry getEntry(String key) { - for (Entry entry : volume.getOptions().entrySet()) { - if (entry.getKey().equals(key)) { - return entry; - } - } - return null; - } - }); - - // Make sure that add button is enabled only when search filter textbox is empty - filterText.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - if (filterText.getText().length() > 0) { - setAddButtonsEnabled(false); - } else { - if (defaultVolumeOptions.size() == volume.getOptions().size()) { - setAddButtonsEnabled(false); - } else { - setAddButtonsEnabled(true); - } - } - } - }); - return button; - } - - private void registerListeners(final Composite parent) { - addDisposeListener(new DisposeListener() { - public void widgetDisposed(DisposeEvent e) { - if (!(addTopButton.isEnabled() || addBottomButton.isEnabled())) { - // user has selected key, but not added value. Since this is not a valid entry, - // remove the last option (without value) from the volume - volume.getOptions().remove(keyEditingSupport.getEntryBeingAdded().getKey()); - } - - GlusterDataModelManager.getInstance().removeClusterListener(clusterListener); - toolkit.dispose(); - } - }); - - /** - * Ideally not required. However the table viewer is not getting laid out properly on performing - * "maximize + restore" So this is a hack to make sure that the table is laid out again on re-size of the window - */ - addPaintListener(new PaintListener() { - - @Override - public void paintControl(PaintEvent e) { - parent.layout(); - } - }); - - parent.addDisposeListener(new DisposeListener() { - - @Override - public void widgetDisposed(DisposeEvent e) { - if (!(addTopButton.isEnabled() || addBottomButton.isEnabled())) { - // user has selected key, but not added value. Since this is not a valid entry, - // remove the last option (without value) from the volume - Entry entryBeingAdded = keyEditingSupport.getEntryBeingAdded(); - volume.getOptions().remove(entryBeingAdded.getKey()); - } - } - }); - - clusterListener = new DefaultClusterListener() { - @SuppressWarnings("unchecked") - @Override - public void volumeChanged(Volume volume, Event event) { - super.volumeChanged(volume, event); - if (event.getEventType() == EVENT_TYPE.VOLUME_OPTIONS_RESET) { - if (!tableViewer.getControl().isDisposed()) { - tableViewer.refresh(); - setAddButtonsEnabled(true); - } - } - - if (event.getEventType() == EVENT_TYPE.VOLUME_OPTION_SET) { - Entry eventEntry = (Entry) event.getEventData(); - if (isNewOption(volume, eventEntry.getKey())) { - // option has been set successfully by the user. re-enable the add button and search filter - // textbox - setAddButtonsEnabled(true); - filterText.setEnabled(true); - } - - if (defaultVolumeOptions.size() == volume.getOptions().size()) { - setAddButtonsEnabled(false); - } - - if (tableViewer.getTable().getItemCount() < volume.getOptions().size()) { - // new volume set from outside this page. refresh the viewer. - tableViewer.refresh(); - } else { - // existing volume option value changed. update that element. - tableViewer.update(eventEntry, null); - } - } - } - - private boolean isNewOption(Volume volume, String optionKey) { - if (filterText.getText().length() > 0) { - // user has been filtering the contents. adding new option is allowed only when contents are NOT - // filtered. Thus it's impossible that this is a newly added option - return false; - } - - // if this is the last option in the volume options, it must be the new option - return optionKey.equals(volume.getOptions().keySet().toArray()[volume.getOptions().size() - 1]); - } - }; - GlusterDataModelManager.getInstance().addClusterListener(clusterListener); - } - - private void setupPageLayout() { - final GridLayout layout = new GridLayout(1, false); - layout.verticalSpacing = 10; - layout.marginTop = 10; - setLayout(layout); - } - - private void setupOptionsTable(Composite parent) { - Table table = tableViewer.getTable(); - table.setHeaderVisible(true); - table.setLinesVisible(false); - - TableColumnLayout tableColumnLayout = createTableColumnLayout(); - parent.setLayout(tableColumnLayout); - - setColumnProperties(table, OPTIONS_TABLE_COLUMN_INDICES.OPTION_KEY, SWT.CENTER, 100); - setColumnProperties(table, OPTIONS_TABLE_COLUMN_INDICES.OPTION_VALUE, SWT.CENTER, 100); - } - - private TableColumnLayout createTableColumnLayout() { - TableColumnLayout tableColumnLayout = new TableColumnLayout(); - ColumnLayoutData defaultColumnLayoutData = new ColumnWeightData(100); - - tableColumnLayout.setColumnData(createKeyColumn(), defaultColumnLayoutData); - tableColumnLayout.setColumnData(createValueColumn(), defaultColumnLayoutData); - - return tableColumnLayout; - } - - private TableColumn createValueColumn() { - TableViewerColumn valueColumn = new TableViewerColumn(tableViewer, SWT.NONE); - valueColumn.getColumn() - .setText(OPTIONS_TABLE_COLUMN_NAMES[OPTIONS_TABLE_COLUMN_INDICES.OPTION_VALUE.ordinal()]); - valueColumn.setLabelProvider(new ColumnLabelProvider() { - @SuppressWarnings("unchecked") - @Override - public String getText(Object element) { - return ((Entry) element).getValue(); - } - }); - - // User can edit value of a volume option - valueColumn.setEditingSupport(new OptionValueEditingSupport(valueColumn.getViewer(), volume)); - - return valueColumn.getColumn(); - } - - private TableColumn createKeyColumn() { - keyColumn = new TableViewerColumn(tableViewer, SWT.NONE); - keyColumn.getColumn().setText(OPTIONS_TABLE_COLUMN_NAMES[OPTIONS_TABLE_COLUMN_INDICES.OPTION_KEY.ordinal()]); - keyColumn.setLabelProvider(new ColumnLabelProvider() { - @SuppressWarnings("unchecked") - @Override - public String getText(Object element) { - return ((Entry) element).getKey(); - } - - @SuppressWarnings("unchecked") - @Override - public String getToolTipText(Object element) { - String key = ((Entry) element).getKey(); - if (key.isEmpty()) { - return "Click to select a volume option key"; - } - - VolumeOptionInfo optionInfo = GlusterDataModelManager.getInstance().getVolumeOptionInfo(key); - // Wrap the description before adding to tooltip so that long descriptions are displayed properly - return WordUtils.wrap(optionInfo.getDescription(), 60) + CoreConstants.NEWLINE + "Default value: " - + optionInfo.getDefaultValue(); - } - }); - - // Editing support required when adding new key - keyEditingSupport = new OptionKeyEditingSupport(keyColumn.getViewer(), volume); - keyColumn.setEditingSupport(keyEditingSupport); - - return keyColumn.getColumn(); - } - - private void createOptionsTableViewer(Composite parent) { - tableViewer = new TableViewer(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.SINGLE); - tableViewer.setLabelProvider(new VolumeOptionsTableLabelProvider()); - tableViewer.setContentProvider(new ArrayContentProvider()); - tableViewer.getTable().setLinesVisible(true); - - setupOptionsTable(parent); - } - - private Composite createTableViewerComposite() { - Composite tableViewerComposite = new Composite(this, SWT.NO); - tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); - tableViewerComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - return tableViewerComposite; - } - - private void setupOptionsTableViewer(final Text filterText) { - Composite tableViewerComposite = createTableViewerComposite(); - createOptionsTableViewer(tableViewerComposite); - ColumnViewerToolTipSupport.enableFor(tableViewer); - // Create a case insensitive filter for the table viewer using the filter text field - guiHelper.createFilter(tableViewer, filterText, false); - } - - private void setColumnProperties(Table table, OPTIONS_TABLE_COLUMN_INDICES columnIndex, int alignment, int weight) { - TableColumn column = table.getColumn(columnIndex.ordinal()); - column.setAlignment(alignment); - - TableColumnLayout tableColumnLayout = (TableColumnLayout) table.getParent().getLayout(); - tableColumnLayout.setColumnData(column, new ColumnWeightData(weight)); - } -} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/navigator/ClusterAdapterFactory.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/navigator/ClusterAdapterFactory.java deleted file mode 100644 index d7ef44ac..00000000 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/navigator/ClusterAdapterFactory.java +++ /dev/null @@ -1,101 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * This file is part of Gluster Management Console. - * - * Gluster Management Console is free software; you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Gluster Management Console 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 Affero General Public License - * for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see - * . - *******************************************************************************/ -package com.gluster.storage.management.gui.views.navigator; - -import org.eclipse.core.runtime.IAdapterFactory; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.ui.model.IWorkbenchAdapter; -import org.eclipse.ui.plugin.AbstractUIPlugin; - -import com.gluster.storage.management.core.model.Cluster; -import com.gluster.storage.management.core.model.Entity; -import com.gluster.storage.management.core.model.EntityGroup; -import com.gluster.storage.management.core.model.GlusterDataModel; -import com.gluster.storage.management.core.model.GlusterServer; -import com.gluster.storage.management.core.model.Server; -import com.gluster.storage.management.core.model.Volume; -import com.gluster.storage.management.gui.Application; -import com.gluster.storage.management.gui.IImageKeys; - -public class ClusterAdapterFactory implements IAdapterFactory { - private IWorkbenchAdapter entityAdapter = new IWorkbenchAdapter() { - - @Override - public Object getParent(Object o) { - return ((Entity) o).getParent(); - } - - @Override - public String getLabel(Object o) { - return ((Entity)o).getName(); - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Override - public ImageDescriptor getImageDescriptor(Object object) { - String iconPath = null; - - if(object instanceof GlusterDataModel || object instanceof Cluster) { - iconPath = IImageKeys.CLUSTER; - } - - if(object instanceof EntityGroup) { - Class entityType = ((EntityGroup) object).getEntityType(); - if(entityType == Volume.class) { - iconPath = IImageKeys.VOLUMES; - } else { - iconPath = IImageKeys.SERVERS; - } - } - - if(object instanceof Volume) { - iconPath = IImageKeys.VOLUME; - } - - if(object instanceof Server || object instanceof GlusterServer) { - iconPath = IImageKeys.SERVER; - } - - return AbstractUIPlugin.imageDescriptorFromPlugin( - Application.PLUGIN_ID, iconPath); - } - - @Override - public Object[] getChildren(Object o) { - return ((Entity)o).getChildren().toArray(); - } - }; - - @SuppressWarnings("rawtypes") - @Override - public Object getAdapter(Object adaptableObject, Class adapterType) { - if (adapterType == IWorkbenchAdapter.class) { - if (adaptableObject instanceof Entity) { - return entityAdapter; - } - } - return null; - } - - @SuppressWarnings("rawtypes") - @Override - public Class[] getAdapterList() { - return new Class[] { IWorkbenchAdapter.class }; - } -} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/navigator/NavigationTreeLabelDecorator.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/navigator/NavigationTreeLabelDecorator.java deleted file mode 100644 index 4cdc2e66..00000000 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/navigator/NavigationTreeLabelDecorator.java +++ /dev/null @@ -1,87 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * This file is part of Gluster Management Console. - * - * Gluster Management Console is free software; you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Gluster Management Console 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 Affero General Public License - * for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see - * . - *******************************************************************************/ -package com.gluster.storage.management.gui.views.navigator; - -import org.eclipse.jface.viewers.IDecoration; -import org.eclipse.jface.viewers.ILabelProviderListener; -import org.eclipse.jface.viewers.ILightweightLabelDecorator; -import org.eclipse.ui.plugin.AbstractUIPlugin; - -import com.gluster.storage.management.core.model.EntityGroup; -import com.gluster.storage.management.core.model.GlusterServer; -import com.gluster.storage.management.core.model.Server; -import com.gluster.storage.management.core.model.Volume; -import com.gluster.storage.management.gui.Application; -import com.gluster.storage.management.gui.IImageKeys; - -public class NavigationTreeLabelDecorator implements ILightweightLabelDecorator { - - @Override - public void addListener(ILabelProviderListener listener) { - } - - @Override - public void dispose() { - } - - @Override - public boolean isLabelProperty(Object element, String property) { - return false; - } - - @Override - public void removeListener(ILabelProviderListener listener) { - } - - @SuppressWarnings("rawtypes") - @Override - public void decorate(Object element, IDecoration decoration) { - if (element instanceof Volume) { - Volume volume = (Volume) element; - if (volume.getStatus() == Volume.VOLUME_STATUS.OFFLINE) { - decoration.addOverlay(AbstractUIPlugin.imageDescriptorFromPlugin(Application.PLUGIN_ID, - IImageKeys.OVERLAY_OFFLINE)); - } else { - decoration.addOverlay(AbstractUIPlugin.imageDescriptorFromPlugin(Application.PLUGIN_ID, - IImageKeys.OVERLAY_ONLINE)); - } - } - - if (element instanceof GlusterServer) { - GlusterServer server = (GlusterServer) element; - if (server.getStatus() == GlusterServer.SERVER_STATUS.OFFLINE) { - decoration.addOverlay(AbstractUIPlugin.imageDescriptorFromPlugin(Application.PLUGIN_ID, - IImageKeys.OVERLAY_OFFLINE)); - } else { - decoration.addOverlay(AbstractUIPlugin.imageDescriptorFromPlugin(Application.PLUGIN_ID, - IImageKeys.OVERLAY_ONLINE)); - } - } - - if (element instanceof Server) { - decoration.addOverlay(AbstractUIPlugin.imageDescriptorFromPlugin(Application.PLUGIN_ID, - IImageKeys.OVERLAY_STAR)); - } - - if(element instanceof EntityGroup && ((EntityGroup)element).getEntityType() == Server.class) { - decoration.addOverlay(AbstractUIPlugin.imageDescriptorFromPlugin(Application.PLUGIN_ID, - IImageKeys.OVERLAY_STAR)); - } - } -} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractBricksPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractBricksPage.java new file mode 100644 index 00000000..baa6cbe9 --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractBricksPage.java @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * This file is part of Gluster Management Console. + * + * Gluster Management Console is free software; you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Gluster Management Console 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 Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * . + *******************************************************************************/ +package com.gluster.storage.management.gui.views.pages; + +import java.util.List; + +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.CheckboxTableViewer; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.TableEditor; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +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.Display; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbenchSite; +import org.eclipse.ui.forms.events.HyperlinkAdapter; +import org.eclipse.ui.forms.events.HyperlinkEvent; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.ImageHyperlink; + +import com.gluster.storage.management.core.model.Brick; +import com.gluster.storage.management.core.model.Disk; +import com.gluster.storage.management.core.model.Disk.DISK_STATUS; +import com.gluster.storage.management.core.model.Entity; +import com.gluster.storage.management.gui.Application; +import com.gluster.storage.management.gui.IEntityListener; +import com.gluster.storage.management.gui.jobs.InitializeDiskJob; +import com.gluster.storage.management.gui.utils.GUIHelper; + +public abstract class AbstractBricksPage extends Composite implements IEntityListener { + protected final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); + protected CheckboxTableViewer tableViewer; + private IWorkbenchSite site; + protected static final GUIHelper guiHelper = GUIHelper.getInstance(); + + /** + * Setup properties of the table e.g. column headers, widths, etc. + * + * @param parent + * The parent composite. (TableColumnLayout has to be set on this) + * @param table + * The table to be set up + */ + protected abstract void setupDiskTable(Composite parent, Table table); + + /** + * @return The label provider to be used with the disk table viewer + */ + protected abstract ITableLabelProvider getTableLabelProvider(); + + /** + * @return Index of the "status" column in the table. Return -1 if status column is not displayed + */ + protected abstract int getStatusColumnIndex(); + + private void init(final Composite parent, IWorkbenchSite site, List bricks) { + addDisposeListener(new DisposeListener() { + public void widgetDisposed(DisposeEvent e) { + toolkit.dispose(); + } + }); + + this.site = site; + + setupPageLayout(); + Text filterText = guiHelper.createFilterText(toolkit, this); + setupBrickTableViewer(createTableViewerComposite(), filterText); + site.setSelectionProvider(tableViewer); + + tableViewer.setInput(bricks); + + site.setSelectionProvider(tableViewer); + Application.getApplication().addEntityListener(this); + + parent.layout(); // Important - this actually paints the table + + toolkit.adapt(this); + toolkit.paintBordersFor(this); + + /** + * Ideally not required. However the table viewer is not getting laid out properly on performing + * "maximize + restore" So this is a hack to make sure that the table is laid out again on re-size of the window + */ + addPaintListener(new PaintListener() { + @Override + public void paintControl(PaintEvent e) { + parent.layout(); + } + }); + } + + public AbstractBricksPage(final Composite parent, int style, IWorkbenchSite site, List bricks) { + super(parent, style); + init(parent, site, bricks); + } + + private void setupPageLayout() { + final GridLayout layout = new GridLayout(1, false); + layout.verticalSpacing = 10; + layout.marginTop = 10; + setLayout(layout); + } + + private Composite createTableViewerComposite() { + Composite tableViewerComposite = new Composite(this, SWT.NO); + tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + tableViewerComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + return tableViewerComposite; + } + + private CheckboxTableViewer createBrickTableViewer(Composite parent) { + tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI ); + + tableViewer.setLabelProvider(getTableLabelProvider()); + tableViewer.setContentProvider(new ArrayContentProvider()); + + setupDiskTable(parent, tableViewer.getTable()); + + // make sure that table selection is driven by checkbox selection + guiHelper.configureCheckboxTableViewer(tableViewer); + + return tableViewer; + } + + private void setupBrickTableViewer(Composite parent, final Text filterText) { + tableViewer = createBrickTableViewer(parent); + // Create a case insensitive filter for the table viewer using the filter text field + guiHelper.createFilter(tableViewer, filterText, false); + } +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractDisksPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractDisksPage.java new file mode 100644 index 00000000..55283c7a --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractDisksPage.java @@ -0,0 +1,309 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * This file is part of Gluster Management Console. + * + * Gluster Management Console is free software; you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Gluster Management Console 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 Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * . + *******************************************************************************/ +package com.gluster.storage.management.gui.views.pages; + +import java.util.List; + +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.CheckboxTableViewer; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.TableEditor; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +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.Display; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbenchSite; +import org.eclipse.ui.forms.events.HyperlinkAdapter; +import org.eclipse.ui.forms.events.HyperlinkEvent; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.ImageHyperlink; + +import com.gluster.storage.management.core.model.Disk; +import com.gluster.storage.management.core.model.Disk.DISK_STATUS; +import com.gluster.storage.management.core.model.Entity; +import com.gluster.storage.management.gui.Application; +import com.gluster.storage.management.gui.IEntityListener; +import com.gluster.storage.management.gui.jobs.InitializeDiskJob; +import com.gluster.storage.management.gui.utils.GUIHelper; + +public abstract class AbstractDisksPage extends Composite implements IEntityListener { + protected final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); + protected CheckboxTableViewer tableViewer; + private IWorkbenchSite site; + protected static final GUIHelper guiHelper = GUIHelper.getInstance(); + + /** + * Setup properties of the table e.g. column headers, widths, etc. + * + * @param parent + * The parent composite. (TableColumnLayout has to be set on this) + * @param table + * The table to be set up + */ + protected abstract void setupDiskTable(Composite parent, Table table); + + /** + * @return The label provider to be used with the disk table viewer + */ + protected abstract ITableLabelProvider getTableLabelProvider(); + + /** + * @return Index of the "status" column in the table. Return -1 if status column is not displayed + */ + protected abstract int getStatusColumnIndex(); + + private void init(final Composite parent, IWorkbenchSite site, List disks) { + addDisposeListener(new DisposeListener() { + public void widgetDisposed(DisposeEvent e) { + toolkit.dispose(); + } + }); + + this.site = site; + + setupPageLayout(); + Text filterText = guiHelper.createFilterText(toolkit, this); + setupDiskTableViewer(createTableViewerComposite(), filterText); + site.setSelectionProvider(tableViewer); + + tableViewer.setInput(disks); + setupStatusCellEditor(); // creates hyperlinks for "unitialized" disks + + site.setSelectionProvider(tableViewer); + Application.getApplication().addEntityListener(this); + + parent.layout(); // Important - this actually paints the table + + toolkit.adapt(this); + toolkit.paintBordersFor(this); + + /** + * Ideally not required. However the table viewer is not getting laid out properly on performing + * "maximize + restore" So this is a hack to make sure that the table is laid out again on re-size of the window + */ + addPaintListener(new PaintListener() { + + @Override + public void paintControl(PaintEvent e) { + parent.layout(); + } + }); + } + + public AbstractDisksPage(final Composite parent, int style, IWorkbenchSite site, List disks) { + super(parent, style); + init(parent, site, disks); + } + + private void setupPageLayout() { + final GridLayout layout = new GridLayout(1, false); + layout.verticalSpacing = 10; + layout.marginTop = 10; + setLayout(layout); + } + + private void createInitializeLink(final TableItem item, final int rowNum, final Disk disk) { + final Table table = tableViewer.getTable(); + final TableEditor editor = new TableEditor(table); + editor.grabHorizontal = true; + editor.horizontalAlignment = SWT.RIGHT; + + table.addPaintListener(new PaintListener() { + private TableItem myItem = item; + private int myRowNum = rowNum; + private ImageHyperlink myLink = null; + private TableEditor myEditor = null; + + private void createLinkFor(Disk disk1, TableItem item1, int rowNum1) { + myItem = item1; + myRowNum = rowNum1; + + myEditor = new TableEditor(table); + myEditor.grabHorizontal = true; + myEditor.horizontalAlignment = SWT.RIGHT; + + myLink = toolkit.createImageHyperlink(table, SWT.NONE); + // link.setImage(guiHelper.getImage(IImageKeys.DISK_UNINITIALIZED)); + myLink.setText("Initialize"); + myLink.addHyperlinkListener(new StatusLinkListener(myLink, myEditor, myItem, tableViewer, disk1, site)); + + myEditor.setEditor(myLink, item1, getStatusColumnIndex()); + + myItem.addDisposeListener(new DisposeListener() { + @Override + public void widgetDisposed(DisposeEvent e) { + myLink.dispose(); + myEditor.dispose(); + } + }); + } + + @Override + public void paintControl(PaintEvent e) { + int itemCount = table.getItemCount(); + + // Find the table item corresponding to our disk + Disk disk1 = null; + int rowNum1 = -1; + TableItem item1 = null; + for (int i = 0; i < itemCount; i++) { + item1 = table.getItem(i); + disk1 = (Disk) item1.getData(); + if (disk1 != null && disk1 == disk) { + rowNum1 = i; + break; + } + } + + if (rowNum1 == -1) { + // item disposed and disk not visible. nothing to do. + return; + } + + if (myEditor == null || myItem.isDisposed()) { + // item visible, and + // either editor never created, OR + // old item disposed. create the link for it + createLinkFor(disk1, item1, rowNum1); + } + + if (rowNum1 != myRowNum) { + // disk visible, but at a different row num. re-create the link + myLink.dispose(); + myEditor.dispose(); + createLinkFor(disk1, item1, rowNum1); + } + + myEditor.layout(); // IMPORTANT. Without this, the link location goes for a toss on maximize + restore + } + }); + } + + private void setupStatusCellEditor() { + final TableViewer viewer = tableViewer; + final Table table = viewer.getTable(); + for (int i = 0; i < table.getItemCount(); i++) { + final TableItem item = table.getItem(i); + if (item.isDisposed() || item.getData() == null) { + continue; + } + final Disk disk = (Disk) item.getData(); + if (disk.isUninitialized()) { + createInitializeLink(item, i, disk); + } + } + } + + private Composite createTableViewerComposite() { + Composite tableViewerComposite = new Composite(this, SWT.NO); + tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + tableViewerComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + return tableViewerComposite; + } + + private CheckboxTableViewer createDiskTableViewer(Composite parent) { + tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI ); + + tableViewer.setLabelProvider(getTableLabelProvider()); + tableViewer.setContentProvider(new ArrayContentProvider()); + + setupDiskTable(parent, tableViewer.getTable()); + + // make sure that table selection is driven by checkbox selection + guiHelper.configureCheckboxTableViewer(tableViewer); + + return tableViewer; + } + + private void setupDiskTableViewer(Composite parent, final Text filterText) { + tableViewer = createDiskTableViewer(parent); + // Create a case insensitive filter for the table viewer using the filter text field + guiHelper.createFilter(tableViewer, filterText, false); + } + + private final class StatusLinkListener extends HyperlinkAdapter { + private final Disk disk; + private final TableEditor myEditor; + private final ImageHyperlink myLink; + private final TableViewer viewer; + private final IWorkbenchSite site; + + private StatusLinkListener(ImageHyperlink link, TableEditor editor, TableItem item, TableViewer viewer, + Disk disk, IWorkbenchSite site) { + this.disk = disk; + this.viewer = viewer; + this.myEditor = editor; + this.myLink = link; + this.site = site; + } + + private void updateStatus(final DISK_STATUS status, final boolean disposeEditor) { + if (disposeEditor) { + myLink.dispose(); + myEditor.dispose(); + } + disk.setStatus(status); + viewer.update(disk, new String[] { "status" }); + Application.getApplication().entityChanged(disk, new String[] { "status" }); + } + + @Override + public void linkActivated(HyperlinkEvent e) { + updateStatus(DISK_STATUS.INITIALIZING, true); + guiHelper.showProgressView(); + + new InitializeDiskJob(disk).schedule(); + } + } + + @Override + public void entityChanged(final Entity entity, final String[] paremeters) { + if (!(entity instanceof Disk)) { + return; + } + final Disk disk = (Disk) entity; + + Display.getDefault().syncExec(new Runnable() { + public void run() { + tableViewer.update(disk, paremeters); + + if (disk.isUninitialized()) { + Table table = tableViewer.getTable(); + + for (int rowNum = 0; rowNum < table.getItemCount(); rowNum++) { + TableItem item = table.getItem(rowNum); + if (item.getData() == disk) { + createInitializeLink(item, rowNum, disk); + } + } + } + } + }); + } +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableViewerPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableViewerPage.java new file mode 100644 index 00000000..a8a98bbd --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableViewerPage.java @@ -0,0 +1,194 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * This file is part of Gluster Management Console. + * + * Gluster Management Console is free software; you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Gluster Management Console 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 Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * . + *******************************************************************************/ +package com.gluster.storage.management.gui.views.pages; + +import java.util.List; + +import org.eclipse.jface.layout.TableColumnLayout; +import org.eclipse.jface.viewers.CheckboxTableViewer; +import org.eclipse.jface.viewers.IBaseLabelProvider; +import org.eclipse.jface.viewers.IContentProvider; +import org.eclipse.jface.viewers.IDoubleClickListener; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +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.Display; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbenchSite; +import org.eclipse.ui.forms.events.HyperlinkAdapter; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.Hyperlink; + +import com.gluster.storage.management.client.GlusterDataModelManager; +import com.gluster.storage.management.core.model.ClusterListener; +import com.gluster.storage.management.gui.utils.GUIHelper; + +public abstract class AbstractTableViewerPage extends Composite { + + protected final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); + protected CheckboxTableViewer tableViewer; + protected GUIHelper guiHelper = GUIHelper.getInstance(); + private Hyperlink linkAll, linkNone; + protected Composite parent; + + public AbstractTableViewerPage(IWorkbenchSite site, final Composite parent, int style, Object model) { + super(parent, style); + this.parent = parent; + + toolkit.adapt(this); + toolkit.paintBordersFor(this); + + setupPageLayout(); + + createCheckboxSelectionLinks(); + + Text filterText = guiHelper.createFilterText(toolkit, this); + + setupServerTableViewer(site, filterText); + + tableViewer.setInput(model); + parent.layout(); // Important - this actually paints the table + + createListeners(parent); + } + + public void createCheckboxSelectionLinks() { + // create the "select all/none" links + toolkit.createLabel(this, "Select"); + linkAll = toolkit.createHyperlink(this, "all", SWT.NONE); + linkAll.addHyperlinkListener(new HyperlinkAdapter() { + @Override + public void linkActivated(org.eclipse.ui.forms.events.HyperlinkEvent e) { + tableViewer.setAllChecked(true); + tableViewer.setSelection(new StructuredSelection(getAllEntities())); + } + }); + + toolkit.createLabel(this, " / "); + + linkNone = toolkit.createHyperlink(this, "none", SWT.NONE); + linkNone.addHyperlinkListener(new HyperlinkAdapter() { + @Override + public void linkActivated(org.eclipse.ui.forms.events.HyperlinkEvent e) { + tableViewer.setAllChecked(false); + tableViewer.setSelection(null); + } + }); + } + + private void createListeners(final Composite parent) { + /** + * Ideally not required. However the table viewer is not getting laid out properly on performing + * "maximize + restore" So this is a hack to make sure that the table is laid out again on re-size of the window + */ + addPaintListener(new PaintListener() { + + @Override + public void paintControl(PaintEvent e) { + parent.layout(); + } + }); + + final ClusterListener clusterListener = createClusterListener(); + + final GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance(); + modelManager.addClusterListener(clusterListener); + + addDisposeListener(new DisposeListener() { + public void widgetDisposed(DisposeEvent e) { + toolkit.dispose(); + modelManager.removeClusterListener(clusterListener); + } + }); + } + + protected abstract ClusterListener createClusterListener(); + protected abstract String[] getColumnNames(); + protected abstract void setColumnProperties(Table table); + protected abstract IBaseLabelProvider getLabelProvider(); + protected abstract IContentProvider getContentProvider(); + protected abstract List getAllEntities(); + + public void addDoubleClickListener(IDoubleClickListener listener) { + tableViewer.addDoubleClickListener(listener); + } + + private void setupPageLayout() { + final GridLayout layout = new GridLayout(5, false); + layout.verticalSpacing = 10; + layout.marginTop = 10; + setLayout(layout); + } + + private void setupServerTable(Composite parent, Table table) { + table.setHeaderVisible(true); + table.setLinesVisible(false); + + TableColumnLayout tableColumnLayout = guiHelper.createTableColumnLayout(table, getColumnNames()); + parent.setLayout(tableColumnLayout); + + setColumnProperties(table); + } + + private CheckboxTableViewer createServerTableViewer(Composite parent) { + CheckboxTableViewer tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI); + + tableViewer.setLabelProvider(getLabelProvider()); + tableViewer.setContentProvider(getContentProvider()); + + setupServerTable(parent, tableViewer.getTable()); + + return tableViewer; + } + + private Composite createTableViewerComposite() { + Composite tableViewerComposite = new Composite(this, SWT.NO); + tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + tableViewerComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + GridData layoutData = new GridData(); + layoutData.horizontalSpan=5; + layoutData.grabExcessHorizontalSpace = true; + layoutData.horizontalAlignment = SWT.FILL; + layoutData.verticalAlignment = SWT.FILL; + tableViewerComposite.setLayoutData(layoutData); + + return tableViewerComposite; + } + + private void setupServerTableViewer(IWorkbenchSite site, final Text filterText) { + Composite tableViewerComposite = createTableViewerComposite(); + tableViewer = createServerTableViewer(tableViewerComposite); + site.setSelectionProvider(tableViewer); + + // make sure that table selection is driven by checkbox selection + guiHelper.configureCheckboxTableViewer(tableViewer); + + // Create a case insensitive filter for the table viewer using the filter text field + guiHelper.createFilter(tableViewer, filterText, false); + } +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/BricksPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/BricksPage.java new file mode 100644 index 00000000..a6bc6f94 --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/BricksPage.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * This file is part of Gluster Management Console. + * + * Gluster Management Console is free software; you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Gluster Management Console 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 Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * . + *******************************************************************************/ +package com.gluster.storage.management.gui.views.pages; + +import java.util.List; + +import org.eclipse.jface.layout.TableColumnLayout; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Table; +import org.eclipse.ui.IWorkbenchSite; + +import com.gluster.storage.management.client.GlusterDataModelManager; +import com.gluster.storage.management.core.model.Brick; +import com.gluster.storage.management.core.model.ClusterListener; +import com.gluster.storage.management.core.model.DefaultClusterListener; +import com.gluster.storage.management.core.model.Entity; +import com.gluster.storage.management.core.model.Event; +import com.gluster.storage.management.core.model.Volume; +import com.gluster.storage.management.core.model.Event.EVENT_TYPE; +import com.gluster.storage.management.gui.BrickTableLabelProvider; + +public class BricksPage extends AbstractBricksPage { + private Composite parent; + + public enum BRICK_TABLE_COLUMN_INDICES { + SERVER, BRICK, FREE_SPACE, TOTAL_SPACE, STATUS + }; + + private static final String[] DISK_TABLE_COLUMN_NAMES = new String[] { "Server", "Brick Directory", "Free Space (GB)", + "Total Space (GB)", "Status" }; + + public BricksPage(final Composite parent, int style, IWorkbenchSite site, final List bricks) { + super(parent, style, site, bricks); + createListeners(); + } + + private void createListeners() { + final ClusterListener clusterListener = new DefaultClusterListener() { + @Override + public void volumeChanged(Volume volume, Event event) { + if (event.getEventType() == EVENT_TYPE.BRICKS_ADDED || event.getEventType() == EVENT_TYPE.BRICKS_REMOVED) { + tableViewer.refresh(); + parent.update(); + } + + } + }; + GlusterDataModelManager.getInstance().addClusterListener(clusterListener); + addDisposeListener(new DisposeListener() { + + @Override + public void widgetDisposed(DisposeEvent e) { + GlusterDataModelManager.getInstance().removeClusterListener(clusterListener); + } + }); + } + + @Override + protected void setupDiskTable(Composite parent, Table table) { + this.parent = parent; + table.setHeaderVisible(true); + table.setLinesVisible(false); + + TableColumnLayout tableColumnLayout = guiHelper.createTableColumnLayout(table, DISK_TABLE_COLUMN_NAMES); + parent.setLayout(tableColumnLayout); + + guiHelper.setColumnProperties(table, BRICK_TABLE_COLUMN_INDICES.SERVER.ordinal(), SWT.CENTER, 100); + guiHelper.setColumnProperties(table, BRICK_TABLE_COLUMN_INDICES.BRICK.ordinal(), SWT.CENTER, 100); + guiHelper.setColumnProperties(table, BRICK_TABLE_COLUMN_INDICES.FREE_SPACE.ordinal(), SWT.CENTER, 90); + guiHelper.setColumnProperties(table, BRICK_TABLE_COLUMN_INDICES.TOTAL_SPACE.ordinal(), SWT.CENTER, 90); + + } + + @Override + protected ITableLabelProvider getTableLabelProvider() { + return new BrickTableLabelProvider(); + } + + @Override + protected int getStatusColumnIndex() { + return BRICK_TABLE_COLUMN_INDICES.STATUS.ordinal(); + } + + @Override + public void entityChanged(Entity entity, String[] paremeters) { + } +} \ No newline at end of file diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/DisksPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/DisksPage.java new file mode 100644 index 00000000..1df74481 --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/DisksPage.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * This file is part of Gluster Management Console. + * + * Gluster Management Console is free software; you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Gluster Management Console 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 Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * . + *******************************************************************************/ +package com.gluster.storage.management.gui.views.pages; + +import java.util.List; + +import org.eclipse.jface.layout.TableColumnLayout; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Table; +import org.eclipse.ui.IWorkbenchSite; + +import com.gluster.storage.management.core.model.Disk; +import com.gluster.storage.management.gui.DiskTableLabelProvider; + +public class DisksPage extends AbstractDisksPage { + + public enum DISK_TABLE_COLUMN_INDICES { + SERVER, DISK, FREE_SPACE, TOTAL_SPACE, STATUS + }; + + private static final String[] DISK_TABLE_COLUMN_NAMES = new String[] { "Server", "Disk", "Free Space (GB)", + "Total Space (GB)", "Status" }; + + public DisksPage(final Composite parent, int style, IWorkbenchSite site, List disks) { + super(parent, style, site, disks); + } + + @Override + protected void setupDiskTable(Composite parent, Table table) { + table.setHeaderVisible(true); + table.setLinesVisible(false); + + TableColumnLayout tableColumnLayout = guiHelper.createTableColumnLayout(table, DISK_TABLE_COLUMN_NAMES); + parent.setLayout(tableColumnLayout); + + guiHelper.setColumnProperties(table, DISK_TABLE_COLUMN_INDICES.SERVER.ordinal(), SWT.CENTER, 100); + guiHelper.setColumnProperties(table, DISK_TABLE_COLUMN_INDICES.DISK.ordinal(), SWT.CENTER, 100); + guiHelper.setColumnProperties(table, DISK_TABLE_COLUMN_INDICES.FREE_SPACE.ordinal(), SWT.CENTER, 90); + guiHelper.setColumnProperties(table, DISK_TABLE_COLUMN_INDICES.TOTAL_SPACE.ordinal(), SWT.CENTER, 90); + // guiHelper.setColumnProperties(table, DISK_TABLE_COLUMN_INDICES.SPACE_IN_USE.ordinal(), SWT.CENTER, 90); + } + + @Override + protected ITableLabelProvider getTableLabelProvider() { + return new DiskTableLabelProvider(); + } + + @Override + protected int getStatusColumnIndex() { + return DISK_TABLE_COLUMN_INDICES.STATUS.ordinal(); + } +} \ No newline at end of file diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/GlusterServersPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/GlusterServersPage.java new file mode 100644 index 00000000..efa2eaaa --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/GlusterServersPage.java @@ -0,0 +1,126 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * This file is part of Gluster Management Console. + * + * Gluster Management Console is free software; you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Gluster Management Console 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 Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * . + *******************************************************************************/ +package com.gluster.storage.management.gui.views.pages; + +import java.util.List; + +import org.eclipse.jface.layout.TableColumnLayout; +import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.jface.viewers.IBaseLabelProvider; +import org.eclipse.jface.viewers.IContentProvider; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.ui.IWorkbenchSite; + +import com.gluster.storage.management.core.model.ClusterListener; +import com.gluster.storage.management.core.model.DefaultClusterListener; +import com.gluster.storage.management.core.model.EntityGroup; +import com.gluster.storage.management.core.model.Event; +import com.gluster.storage.management.core.model.GlusterServer; +import com.gluster.storage.management.gui.EntityGroupContentProvider; +import com.gluster.storage.management.gui.GlusterServerTableLabelProvider; + +public class GlusterServersPage extends AbstractTableViewerPage { + private List glusterServers; + + public enum GLUSTER_SERVER_TABLE_COLUMN_INDICES { + NAME, IP_ADDRESSES, NUM_OF_CPUS, TOTAL_MEMORY, TOTAL_DISK_SPACE, AVAILABLE_DISK_SPACE, STATUS // Removed PREFERRED_NETWORK + }; + + private static final String[] GLUSTER_SERVER_TABLE_COLUMN_NAMES = new String[] { "Name", + "IP Address(es)", "Number\nof CPUs", "Total\nMemory (GB)", "Space (GB)", "Space\nAvailable (GB)", "Status" }; // Removed "Preferred\nNetwork", + + public GlusterServersPage(IWorkbenchSite site, final Composite parent, int style, final EntityGroup servers) { + super(site, parent, style, servers); + this.glusterServers = servers.getEntities(); + } + + @Override + protected ClusterListener createClusterListener() { + return new DefaultClusterListener() { + + @Override + public void serverAdded(GlusterServer server) { + tableViewer.refresh(); + } + + @Override + public void serverRemoved(GlusterServer server) { + tableViewer.refresh(); + } + + @Override + public void serverChanged(GlusterServer server, Event event) { + tableViewer.update(server, null); + } + }; + } + + @Override + protected void setColumnProperties(Table table) { + setColumnProperties(table, GLUSTER_SERVER_TABLE_COLUMN_INDICES.NAME, SWT.CENTER, 100); + setColumnProperties(table, GLUSTER_SERVER_TABLE_COLUMN_INDICES.STATUS, SWT.CENTER, 70); + // setColumnProperties(table, GLUSTER_SERVER_TABLE_COLUMN_INDICES.PREFERRED_NETWORK, SWT.CENTER, 90); + setColumnProperties(table, GLUSTER_SERVER_TABLE_COLUMN_INDICES.NUM_OF_CPUS, SWT.CENTER, 90); + //setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.CPU_USAGE, SWT.CENTER, 90); + setColumnProperties(table, GLUSTER_SERVER_TABLE_COLUMN_INDICES.TOTAL_MEMORY, SWT.CENTER, 90); + //setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.MEMORY_IN_USE, SWT.CENTER, 90); + setColumnProperties(table, GLUSTER_SERVER_TABLE_COLUMN_INDICES.TOTAL_DISK_SPACE, SWT.CENTER, 90); + setColumnProperties(table, GLUSTER_SERVER_TABLE_COLUMN_INDICES.AVAILABLE_DISK_SPACE, SWT.CENTER, 90); + //setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.DISK_SPACE_IN_USE, SWT.CENTER, 90); + } + + @Override + protected IBaseLabelProvider getLabelProvider() { + return new GlusterServerTableLabelProvider(); + } + + @Override + protected IContentProvider getContentProvider() { + return new EntityGroupContentProvider(); + } + + @Override + protected String[] getColumnNames() { + return GLUSTER_SERVER_TABLE_COLUMN_NAMES; + } + + @Override + protected List getAllEntities() { + return glusterServers; + } + + /** + * Sets properties for alignment and weight of given column of given table + * + * @param table + * @param columnIndex + * @param alignment + * @param weight + */ + public void setColumnProperties(Table table, GLUSTER_SERVER_TABLE_COLUMN_INDICES columnIndex, int alignment, int weight) { + TableColumn column = table.getColumn(columnIndex.ordinal()); + column.setAlignment(alignment); + + TableColumnLayout tableColumnLayout = (TableColumnLayout) table.getParent().getLayout(); + tableColumnLayout.setColumnData(column, new ColumnWeightData(weight)); + } +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/OptionKeyEditingSupport.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/OptionKeyEditingSupport.java new file mode 100644 index 00000000..87bd1154 --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/OptionKeyEditingSupport.java @@ -0,0 +1,125 @@ +/** + * + */ +package com.gluster.storage.management.gui.views.pages; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.eclipse.jface.viewers.CellEditor; +import org.eclipse.jface.viewers.ColumnViewer; +import org.eclipse.jface.viewers.ComboBoxCellEditor; +import org.eclipse.jface.viewers.EditingSupport; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; + +import com.gluster.storage.management.client.GlusterDataModelManager; +import com.gluster.storage.management.core.model.Volume; +import com.gluster.storage.management.core.model.VolumeOptionInfo; + +/** + * Editing support for the "value" column in volume options table viewer. + */ +public class OptionKeyEditingSupport extends EditingSupport { + private CellEditor cellEditor; + private Volume volume; + private List defaults = GlusterDataModelManager.getInstance().getVolumeOptionsDefaults(); + private String[] allowedKeys; + private ColumnViewer viewer; + + public OptionKeyEditingSupport(ColumnViewer viewer, Volume volume) { + super(viewer); + this.volume = volume; + this.viewer = viewer; + } + + /** + * @return array of option keys that are not already set on the volume + */ + private String[] getAllowedKeys() { + ArrayList keys = new ArrayList(); + Map volumeOptions = volume.getOptions(); + for(VolumeOptionInfo optionInfo : defaults) { + String optionName = optionInfo.getName(); + if(!volumeOptions.containsKey(optionName) || volumeOptions.get(optionName).isEmpty()) { + // key not set => available for setting + // value not set => this is the row being edited + keys.add(optionName); + } + } + return keys.toArray(new String[0]); + } + + @SuppressWarnings("unchecked") + @Override + protected void setValue(final Object element, final Object value) { + Entry oldEntry = (Entry)element; + Integer newValue = (Integer)value; + String newKey = allowedKeys[newValue]; + + if (((Entry)element).getKey().equals(newKey)) { + // selected value is same as old one. + return; + } + + // value has changed. set new value and refresh the viewer. + volume.getOptions().remove(oldEntry.getKey()); + volume.setOption(newKey, ""); + getViewer().refresh(); + } + + @Override + protected Object getValue(Object element) { + Entry entryBeingAdded = getEntryBeingAdded(); + if(entryBeingAdded == null) { + return cellEditor.getValue(); + } + + if(entryBeingAdded.getKey().isEmpty()) { + // editing just about to start. set first element as default. + return 0; + } + + return getIndexOfEntry(entryBeingAdded); + } + + @Override + protected CellEditor getCellEditor(Object element) { + allowedKeys = getAllowedKeys(); + cellEditor = new ComboBoxCellEditor((Composite) viewer.getControl(), allowedKeys, SWT.READ_ONLY); + return cellEditor; + } + + private int getIndexOfEntry(Entry entryBeingAdded) { + for(int index = 0; index < allowedKeys.length; index++) { + if(allowedKeys[index].equals(entryBeingAdded.getKey())) { + return index; + } + } + return -1; + } + + protected Entry getEntryBeingAdded() { + Entry entryBeingAdded = null; + Iterator> iter = volume.getOptions().entrySet().iterator(); + while(iter.hasNext()) { + Entry nextEntry = iter.next(); + if(!iter.hasNext() && nextEntry.getValue().isEmpty()) { + // it's the LAST entry, and it's value is empty. + // means this is a new row being added in the table viewer. + entryBeingAdded = nextEntry; + } + } + return entryBeingAdded; + } + + @SuppressWarnings("unchecked") + @Override + protected boolean canEdit(Object element) { + Entry entry = (Entry)element; + return (entry.getKey().isEmpty() || entry.getValue().isEmpty()); + } +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/OptionValueEditingSupport.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/OptionValueEditingSupport.java new file mode 100644 index 00000000..a5edd7cb --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/OptionValueEditingSupport.java @@ -0,0 +1,115 @@ +/** + * + */ +package com.gluster.storage.management.gui.views.pages; + +import java.util.List; +import java.util.Map.Entry; + +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.CellEditor; +import org.eclipse.jface.viewers.ColumnViewer; +import org.eclipse.jface.viewers.EditingSupport; +import org.eclipse.jface.viewers.TextCellEditor; +import org.eclipse.swt.custom.BusyIndicator; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; + +import com.gluster.storage.management.client.GlusterDataModelManager; +import com.gluster.storage.management.client.VolumesClient; +import com.gluster.storage.management.core.model.Status; +import com.gluster.storage.management.core.model.Volume; +import com.gluster.storage.management.core.model.VolumeOptionInfo; +import com.gluster.storage.management.gui.utils.GUIHelper; + +/** + * Editing support for the "value" column in volume options table viewer. + */ +public class OptionValueEditingSupport extends EditingSupport { + private CellEditor cellEditor; + private Volume volume; + private List defaults = GlusterDataModelManager.getInstance().getVolumeOptionsDefaults(); + private GUIHelper guiHelper = GUIHelper.getInstance(); + + public OptionValueEditingSupport(ColumnViewer viewer, Volume volume) { + super(viewer); + this.volume = volume; + this.cellEditor = new TextCellEditor((Composite) viewer.getControl()); + } + + @SuppressWarnings("unchecked") + @Override + protected void setValue(final Object element, final Object value) { + final Entry entry = (Entry) element; + final String optionKey = entry.getKey(); + final String optionValue = (String)value; + final String oldValue = entry.getValue(); + + // It is not allowed to change value to empty string + if(optionValue.isEmpty()) { + MessageDialog.openError(Display.getDefault().getActiveShell(), "Set Volume Option", + "Option value can't be empty! Please enter a valid value."); + cellEditor.setFocus(); + return; + } + + if (oldValue.equals(optionValue)) { + // value is same as that present in the model. return without doing anything. + return; + } + + // value has changed. set volume option at back-end and update model accordingly + guiHelper.setStatusMessage("Setting option [" + optionKey + " = " + optionValue + "]..."); + getViewer().getControl().update(); + + BusyIndicator.showWhile(Display.getDefault(), new Runnable() { + + @Override + public void run() { + VolumesClient client = new VolumesClient(); + Status status = client.setVolumeOption(volume.getName(), entry.getKey(), (String) value); + if (status.isSuccess()) { + entry.setValue((String)value); + GlusterDataModelManager.getInstance().setVolumeOption(volume, entry); + } else { + MessageDialog.openError(Display.getDefault().getActiveShell(), "Set Volume Option", + status.getMessage()); + } + getViewer().update(entry, null); + } + }); + + guiHelper.clearStatusMessage(); + getViewer().getControl().update(); + } + + /** + * @param key Key whose default value is to be fetched + * @return Default value of the volume option with given key + */ + private String getDefaultValue(String key) { + for(VolumeOptionInfo optionInfo : defaults) { + if(optionInfo.getName().equals(key)) { + return optionInfo.getDefaultValue(); + } + } + return ""; + } + + @SuppressWarnings("unchecked") + @Override + protected Object getValue(Object element) { + Entry entry = (Entry) element; + return entry.getValue().isEmpty() ? getDefaultValue(entry.getKey()) : entry.getValue(); + } + + @Override + protected CellEditor getCellEditor(Object element) { + return cellEditor; + } + + @Override + protected boolean canEdit(Object element) { + return true; + } +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServerDisksPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServerDisksPage.java new file mode 100644 index 00000000..3621afe1 --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServerDisksPage.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * This file is part of Gluster Management Console. + * + * Gluster Management Console is free software; you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Gluster Management Console 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 Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * . + *******************************************************************************/ +package com.gluster.storage.management.gui.views.pages; + +import java.util.List; + +import org.eclipse.jface.layout.TableColumnLayout; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Table; +import org.eclipse.ui.IWorkbenchSite; + +import com.gluster.storage.management.core.model.Disk; +import com.gluster.storage.management.gui.ServerDiskTableLabelProvider; +import com.gluster.storage.management.gui.TableLabelProviderAdapter; + +public class ServerDisksPage extends AbstractDisksPage { + public ServerDisksPage(Composite parent, int style, IWorkbenchSite site, List disks) { + super(parent, style, site, disks); + } + + public enum SERVER_DISK_TABLE_COLUMN_INDICES { + DISK, SPACE, SPACE_IN_USE, STATUS + }; + + private static final String[] SERVER_DISK_TABLE_COLUMN_NAMES = new String[] { "Disk", "Space (GB)", + "Space in Use (GB)", "Status" }; + + @Override + protected void setupDiskTable(Composite parent, Table table) { + table.setHeaderVisible(true); + table.setLinesVisible(false); + + TableColumnLayout tableColumnLayout = guiHelper.createTableColumnLayout(table, SERVER_DISK_TABLE_COLUMN_NAMES); + parent.setLayout(tableColumnLayout); + + guiHelper.setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.DISK.ordinal(), SWT.CENTER, 100); + guiHelper.setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.SPACE.ordinal(), SWT.CENTER, 90); + guiHelper.setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.SPACE_IN_USE.ordinal(), SWT.CENTER, 90); + guiHelper.setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.STATUS.ordinal(), SWT.LEFT, 90); + } + + @Override + protected int getStatusColumnIndex() { + return SERVER_DISK_TABLE_COLUMN_INDICES.STATUS.ordinal(); + } + + @Override + protected TableLabelProviderAdapter getTableLabelProvider() { + return new ServerDiskTableLabelProvider(); + } +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServerLogsPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServerLogsPage.java new file mode 100644 index 00000000..7cde38bb --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServerLogsPage.java @@ -0,0 +1,179 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * This file is part of Gluster Management Console. + * + * Gluster Management Console is free software; you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Gluster Management Console 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 Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * . + *******************************************************************************/ +package com.gluster.storage.management.gui.views.pages; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.ListViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.forms.widgets.FormToolkit; + +import com.gluster.storage.management.core.model.GlusterServer; +import com.gluster.storage.management.gui.utils.GUIHelper; + +public class ServerLogsPage extends Composite { + + private final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); + private final GUIHelper guiHelper = GUIHelper.getInstance(); + private Text text; + private Table table; + + public enum LOG_TABLE_COLUMN_INDICES { + DATE, TIME, DISK, SEVERITY, MESSAGE + }; + + private static final String[] LOG_TABLE_COLUMN_NAMES = new String[] { "Date", "Time", "Disk", "Severity", "Message" }; + + /** + * Create the composite. + * + * @param parent + * @param style + */ + public ServerLogsPage(Composite parent, int style, GlusterServer server) { + super(parent, style); + addDisposeListener(new DisposeListener() { + public void widgetDisposed(DisposeEvent e) { + toolkit.dispose(); + } + }); + toolkit.adapt(this); + toolkit.paintBordersFor(this); + + setLayout(new GridLayout(1, false)); + GridData layoutData = new GridData(); + layoutData.grabExcessHorizontalSpace = true; + layoutData.grabExcessVerticalSpace = true; + setLayoutData(layoutData); + + Composite composite = toolkit.createComposite(this, SWT.NONE); + toolkit.paintBordersFor(composite); + + Label lblScanLast = toolkit.createLabel(composite, "Scan last", SWT.NONE); + lblScanLast.setBounds(0, 15, 80, 20); + + text = toolkit.createText(composite, "100", SWT.NONE); + text.setBounds(85, 15, 60, 20); + + Label lblMessagesAndFilter = toolkit.createLabel(composite, " messages from ", SWT.CENTER); + lblMessagesAndFilter.setBounds(160, 15, 110, 20); + + Combo combo = new Combo(composite, SWT.CENTER); + combo.setBounds(295, 15, 100, 20); + combo.setItems(new String[] { "syslog", "dmesg" }); + toolkit.adapt(combo); + toolkit.paintBordersFor(combo); + combo.select(0); + + Button btngo = toolkit.createButton(composite, "&Go", SWT.NONE); + btngo.setBounds(410, 13, 50, 30); + + Label separator = toolkit.createLabel(composite, "", SWT.SEPARATOR | SWT.HORIZONTAL | SWT.FILL); + separator.setBounds(0, 50, 500, 2); + + Label lblFilterString = toolkit.createLabel(composite, "Filter String", SWT.LEFT); + lblFilterString.setBounds(0, 65, 100, 20); + + text = guiHelper.createFilterText(toolkit, composite); + text.setBounds(105, 65, 250, 20); + + Composite logContentsComposite = createLogContentsComposite(toolkit); + // Text logContentsText = toolkit.createText(logContentsComposite, "", SWT.MULTI | SWT.FLAT | SWT.BORDER); + // logContentsText.setEditable(false); + // populateDummyLogContent(logContentsText); + + ListViewer logViewer = new ListViewer(logContentsComposite, SWT.BORDER | SWT.V_SCROLL | SWT.NO); + logViewer.setContentProvider(new ArrayContentProvider()); + guiHelper.createFilter(logViewer, text, false); + logViewer.setInput(getDummyLogContents()); + + // TODO: Link the filter string with the contents text + } + + private Composite createLogContentsComposite(FormToolkit toolkit) { + Composite tableViewerComposite = toolkit.createComposite(this, SWT.NONE); + tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true); + layoutData.verticalIndent = 10; + tableViewerComposite.setLayoutData(layoutData); + return tableViewerComposite; + } + + private String[] getDummyLogContents() { + + String[] logMessages = { + "Jan 19 13:43:08 shireesh-laptop dhclient: last message repeated 6 times", + "Jan 19 13:44:08 shireesh-laptop dhclient: last message repeated 5 times", + "Jan 19 13:44:47 shireesh-laptop dhclient: last message repeated 2 times", + "Jan 19 13:44:47 shireesh-laptop dhclient: DHCPREQUEST of 192.168.1.174 on eth1 to 255.255.255.255 port 67", + "Jan 19 13:45:49 shireesh-laptop dhclient: last message repeated 6 times", + "Jan 19 13:46:59 shireesh-laptop dhclient: last message repeated 6 times", + "Jan 19 13:48:01 shireesh-laptop dhclient: last message repeated 4 times", + "Jan 19 13:49:02 shireesh-laptop dhclient: last message repeated 5 times", + "Jan 19 13:50:08 shireesh-laptop dhclient: last message repeated 4 times", + "Jan 19 13:51:08 shireesh-laptop dhclient: last message repeated 6 times", + "Jan 19 13:52:08 shireesh-laptop dhclient: last message repeated 4 times", + "Jan 19 13:53:08 shireesh-laptop dhclient: last message repeated 6 times", + "Jan 19 13:54:08 shireesh-laptop dhclient: last message repeated 5 times", + "Jan 19 13:55:08 shireesh-laptop dhclient: last message repeated 4 times", + "Jan 19 13:56:08 shireesh-laptop dhclient: last message repeated 4 times", + "Jan 19 13:57:08 shireesh-laptop dhclient: last message repeated 3 times", + "Jan 19 13:58:08 shireesh-laptop dhclient: last message repeated 6 times", + "Jan 19 13:59:08 shireesh-laptop dhclient: last message repeated 4 times", + "Jan 19 13:59:40 shireesh-laptop dhclient: last message repeated 3 times", + "Jan 19 13:59:40 shireesh-laptop NetworkManager: DHCP: device eth1 state changed bound -> expire", + "Jan 19 13:59:40 shireesh-laptop dhclient: DHCPDISCOVER on eth1 to 255.255.255.255 port 67 interval 8", + "Jan 19 13:59:40 shireesh-laptop NetworkManager: DHCP: device eth1 state changed expire -> preinit", + "Jan 19 13:59:40 shireesh-laptop dhclient: DHCPOFFER of 192.168.1.174 from 192.168.1.1", + "Jan 19 13:59:40 shireesh-laptop dhclient: DHCPREQUEST of 192.168.1.174 on eth1 to 255.255.255.255 port 67", + "Jan 19 13:59:40 shireesh-laptop dhclient: DHCPACK of 192.168.1.174 from 192.168.1.1", + "Jan 19 13:59:40 shireesh-laptop dhclient: bound to 192.168.1.174 -- renewal in 3205 seconds.", + "Jan 19 13:59:40 shireesh-laptop NetworkManager: DHCP: device eth1 state changed preinit -> bound", + "Jan 19 13:59:40 shireesh-laptop NetworkManager: address 192.168.1.174", + "Jan 19 13:59:40 shireesh-laptop NetworkManager: prefix 24 (255.255.255.0)", + "Jan 19 13:59:40 shireesh-laptop NetworkManager: gateway 192.168.1.1", + "Jan 19 13:59:40 shireesh-laptop NetworkManager: nameserver '192.168.1.1'", + "Jan 19 13:59:40 shireesh-laptop NetworkManager: domain name 'in.gluster.com'", + "Jan 19 14:03:53 shireesh-laptop avahi-daemon[1098]: Invalid legacy unicast query packet.", + "Jan 19 14:03:53 shireesh-laptop avahi-daemon[1098]: Received response from host 192.168.1.155 with invalid source port 37219 on interface 'eth0.0'", + "Jan 19 14:03:54 shireesh-laptop avahi-daemon[1098]: Invalid legacy unicast query packet.", + "Jan 19 14:03:54 shireesh-laptop avahi-daemon[1098]: Invalid legacy unicast query packet.", + "Jan 19 14:03:54 shireesh-laptop avahi-daemon[1098]: Received response from host 192.168.1.155 with invalid source port 37219 on interface 'eth0.0'", + "Jan 19 14:05:09 shireesh-laptop avahi-daemon[1098]: last message repeated 8 times", + "Jan 19 14:12:48 shireesh-laptop NetworkManager: [1295426568.002642] periodic_update(): Roamed from BSSID E0:CB:4E:C0:0B:7F (glfs) to (none) ((none))", + "Jan 19 14:12:54 shireesh-laptop NetworkManager: [1295426574.002448] periodic_update(): Roamed from BSSID (none) ((none)) to E0:CB:4E:C0:0B:7F (glfs)", + "Jan 19 14:17:01 shireesh-laptop CRON[5321]: (root) CMD ( cd / && run-parts --report /etc/cron.hourly)" }; + + return logMessages; + } +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServersPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServersPage.java index 20c3cbd4..48b8892c 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServersPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServersPage.java @@ -18,41 +18,28 @@ *******************************************************************************/ package com.gluster.storage.management.gui.views.pages; +import java.util.List; + import org.eclipse.jface.layout.TableColumnLayout; -import org.eclipse.jface.viewers.CheckboxTableViewer; import org.eclipse.jface.viewers.ColumnWeightData; -import org.eclipse.jface.viewers.IDoubleClickListener; +import org.eclipse.jface.viewers.IBaseLabelProvider; +import org.eclipse.jface.viewers.IContentProvider; import org.eclipse.swt.SWT; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.events.PaintEvent; -import org.eclipse.swt.events.PaintListener; -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.Display; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IWorkbenchSite; -import org.eclipse.ui.forms.widgets.FormToolkit; -import com.gluster.storage.management.client.GlusterDataModelManager; import com.gluster.storage.management.core.model.ClusterListener; import com.gluster.storage.management.core.model.DefaultClusterListener; import com.gluster.storage.management.core.model.EntityGroup; import com.gluster.storage.management.core.model.Server; import com.gluster.storage.management.gui.EntityGroupContentProvider; import com.gluster.storage.management.gui.ServerTableLabelProvider; -import com.gluster.storage.management.gui.utils.GUIHelper; - -public class ServersPage extends Composite { - - private final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); - private CheckboxTableViewer tableViewer; - private GUIHelper guiHelper = GUIHelper.getInstance(); +public class ServersPage extends AbstractTableViewerPage { + private List servers; + public enum SERVER_TABLE_COLUMN_INDICES { NAME, IP_ADDRESSES, NUM_OF_DISKS, TOTAL_DISK_SPACE }; @@ -67,39 +54,14 @@ public class ServersPage extends Composite { // "Number\nof CPUs", "CPU\nUsage (%)", "Total\nMemory (GB)", "Memory\nIn Use (GB)", // "Total Disk\n Space (GB)", "Disk Space\nin Use (GB)"}; - public ServersPage(final Composite parent, IWorkbenchSite site, EntityGroup servers) { - super(parent, SWT.NONE); - - addDisposeListener(new DisposeListener() { - public void widgetDisposed(DisposeEvent e) { - toolkit.dispose(); - } - }); - - toolkit.adapt(this); - toolkit.paintBordersFor(this); - - setupPageLayout(); - setupPage(site, servers); - parent.layout(); // Important - this actually paints the table - - createListeners(parent); + public ServersPage(final Composite parent, IWorkbenchSite site, EntityGroup serversGroup) { + super(site, parent, SWT.NONE, serversGroup); + this.servers = serversGroup.getEntities(); } - private void createListeners(final Composite parent) { - /** - * Ideally not required. However the table viewer is not getting laid out properly on performing - * "maximize + restore" So this is a hack to make sure that the table is laid out again on re-size of the window - */ - addPaintListener(new PaintListener() { - - @Override - public void paintControl(PaintEvent e) { - parent.layout(); - } - }); - - final ClusterListener clusterListener = new DefaultClusterListener() { + @Override + protected ClusterListener createClusterListener() { + return new DefaultClusterListener() { @Override public void discoveredServerRemoved(Server server) { refreshViewer(); @@ -115,16 +77,6 @@ public class ServersPage extends Composite { parent.update(); } }; - - final GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance(); - modelManager.addClusterListener(clusterListener); - addDisposeListener(new DisposeListener() { - @Override - public void widgetDisposed(DisposeEvent e) { - toolkit.dispose(); - modelManager.removeClusterListener(clusterListener); - } - }); } public void setInput(EntityGroup servers) { @@ -132,24 +84,8 @@ public class ServersPage extends Composite { tableViewer.refresh(); } - public void addDoubleClickListener(IDoubleClickListener listener) { - tableViewer.addDoubleClickListener(listener); - } - - private void setupPageLayout() { - final GridLayout layout = new GridLayout(1, false); - layout.verticalSpacing = 10; - layout.marginTop = 10; - setLayout(layout); - } - - private void setupServerTable(Composite parent, Table table) { - table.setHeaderVisible(true); - table.setLinesVisible(false); - - TableColumnLayout tableColumnLayout = guiHelper.createTableColumnLayout(table, SERVER_TABLE_COLUMN_NAMES); - parent.setLayout(tableColumnLayout); - + @Override + protected void setColumnProperties(Table table) { setColumnProperties(table, SERVER_TABLE_COLUMN_INDICES.NAME, SWT.CENTER, 70); setColumnProperties(table, SERVER_TABLE_COLUMN_INDICES.IP_ADDRESSES, SWT.CENTER, 100); setColumnProperties(table, SERVER_TABLE_COLUMN_INDICES.NUM_OF_DISKS, SWT.CENTER, 70); @@ -160,40 +96,26 @@ public class ServersPage extends Composite { // setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.MEMORY_IN_USE, SWT.CENTER, 90); // setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.DISK_SPACE_IN_USE, SWT.CENTER, 90); } - - private CheckboxTableViewer createServerTableViewer(Composite parent) { - final CheckboxTableViewer tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI); - // TableViewer tableViewer = new TableViewer(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI); - tableViewer.setLabelProvider(new ServerTableLabelProvider()); - tableViewer.setContentProvider(new EntityGroupContentProvider()); - - setupServerTable(parent, tableViewer.getTable()); - - // make sure that table selection is driven by checkbox selection - guiHelper.configureCheckboxTableViewer(tableViewer); - - return tableViewer; + + @Override + protected String[] getColumnNames() { + return SERVER_TABLE_COLUMN_NAMES; } - - private Composite createTableViewerComposite() { - Composite tableViewerComposite = new Composite(this, SWT.NONE); - tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); - tableViewerComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - return tableViewerComposite; + + @Override + protected IBaseLabelProvider getLabelProvider() { + return new ServerTableLabelProvider(); } - - private void setupPage(IWorkbenchSite site, EntityGroup servers) { - Text filterText = guiHelper.createFilterText(toolkit, this); - - Composite tableViewerComposite = createTableViewerComposite(); - tableViewer = createServerTableViewer(tableViewerComposite); - site.setSelectionProvider(tableViewer); - - // Create a case insensitive filter for the table viewer using the filter text field - guiHelper.createFilter(tableViewer, filterText, false); - - tableViewer.setInput(servers); + + @Override + protected IContentProvider getContentProvider() { + return new EntityGroupContentProvider(); } + + @Override + protected List getAllEntities() { + return servers; + } /** * Sets properties for alignment and weight of given column of given table @@ -209,5 +131,5 @@ public class ServersPage extends Composite { TableColumnLayout tableColumnLayout = (TableColumnLayout) table.getParent().getLayout(); tableColumnLayout.setColumnData(column, new ColumnWeightData(weight)); - } + } } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumeLogsPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumeLogsPage.java new file mode 100644 index 00000000..ab1b353d --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumeLogsPage.java @@ -0,0 +1,409 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * This file is part of Gluster Management Console. + * + * Gluster Management Console is free software; you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Gluster Management Console 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 Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * . + *******************************************************************************/ +package com.gluster.storage.management.gui.views.pages; + +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.layout.TableColumnLayout; +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.DateTime; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.forms.widgets.FormToolkit; + +import com.gluster.storage.management.client.GlusterDataModelManager; +import com.gluster.storage.management.client.VolumesClient; +import com.gluster.storage.management.core.constants.CoreConstants; +import com.gluster.storage.management.core.constants.GlusterConstants; +import com.gluster.storage.management.core.constants.GlusterConstants.VOLUME_LOG_LEVELS; +import com.gluster.storage.management.core.model.VolumeLogMessage; +import com.gluster.storage.management.core.model.Status; +import com.gluster.storage.management.core.model.Volume; +import com.gluster.storage.management.core.response.LogMessageListResponse; +import com.gluster.storage.management.core.utils.GlusterCoreUtil; +import com.gluster.storage.management.gui.VolumeLogTableLabelProvider; +import com.gluster.storage.management.gui.utils.GUIHelper; + +public class VolumeLogsPage extends Composite { + + private final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); + private final GUIHelper guiHelper = GUIHelper.getInstance(); + private Text filterText; + private Text lineCountText; + private Volume volume; + + public enum LOG_TABLE_COLUMN_INDICES { + DATE, TIME, BRICK, SEVERITY, MESSAGE + }; + + private static final String[] LOG_TABLE_COLUMN_NAMES = new String[] { "Date", "Time", "Brick", "Severity", "Message" }; + private TableViewer tableViewer; + private Combo bricksCombo; + private Combo severityCombo; + private DateTime fromDate; + private DateTime fromTime; + private DateTime toDate; + private DateTime toTime; + private Button fromCheckbox; + private Button toCheckbox; + + /** + * Create the volume logs page + * + * @param parent + * @param style + * @param volume + * Volume for which the logs page is to be created + */ + public VolumeLogsPage(Composite parent, int style, Volume volume) { + super(parent, style); + this.volume = volume; + + addDisposeListener(new DisposeListener() { + public void widgetDisposed(DisposeEvent e) { + toolkit.dispose(); + } + }); + toolkit.adapt(this); + toolkit.paintBordersFor(this); + + configureLayout(); + + Composite composite = toolkit.createComposite(this, SWT.NONE); + toolkit.paintBordersFor(composite); + + createLineCountLabel(composite); + createLineCountText(composite); + + createBricksLabel(composite); + createBricksCombo(composite); + + createSeverityLabel(composite); + createSeverityCombo(composite); + + createFromDateLabel(composite); + createFromDateField(composite); + createFromTimeField(composite); + createFromCheckbox(composite); + + createToDateLabel(composite); + createToDateField(composite); + createToTimeField(composite); + createToCheckbox(composite); + + createSearchButton(composite); + + createSeparator(composite); + + createFilterLabel(composite); + createFilterText(composite); + + createLogTableViewer(); + } + + private void createLogTableViewer() { + Composite tableViewerComposite = createTableViewerComposite(); + + tableViewer = new TableViewer(tableViewerComposite, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI); + tableViewer.setLabelProvider(new VolumeLogTableLabelProvider()); + tableViewer.setContentProvider(new ArrayContentProvider()); + + setupLogsTable(tableViewerComposite, tableViewer.getTable()); + guiHelper.createFilter(tableViewer, filterText, false); + } + + private void createFilterText(Composite composite) { + filterText = guiHelper.createFilterText(toolkit, composite); + filterText.setBounds(90, 105, 250, 20); + } + + private void createFilterLabel(Composite composite) { + Label lblFilterString = toolkit.createLabel(composite, "Filter String", SWT.LEFT); + lblFilterString.setBounds(0, 105, 85, 20); + } + + private void createSeparator(Composite composite) { + Label separator = toolkit.createLabel(composite, "", SWT.SEPARATOR | SWT.HORIZONTAL | SWT.FILL); + separator.setBounds(0, 95, 680, 2); + } + + private void createSearchButton(Composite composite) { + Button btnGo = toolkit.createButton(composite, "&Go", SWT.NONE); + btnGo.setBounds(615, 55, 50, 30); + btnGo.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + VolumesClient client = new VolumesClient(); + + Date fromTimestamp = null; + Date toTimestamp = null; + + if (fromCheckbox.getSelection()) { + fromTimestamp = extractTimestamp(fromDate, fromTime); + } + + if (toCheckbox.getSelection()) { + toTimestamp = extractTimestamp(toDate, toTime); + } + + if (!validateTimeRange(fromTimestamp, toTimestamp)) { + return; + } + + LogMessageListResponse response = client.getLogs(volume.getName(), bricksCombo.getText(), + severityCombo.getText(), fromTimestamp, toTimestamp, Integer.parseInt(lineCountText.getText())); + Status status = response.getStatus(); + if (status.isSuccess()) { + List logMessages = response.getLogMessages(); + tableViewer.setInput(logMessages.toArray(new VolumeLogMessage[0])); + tableViewer.refresh(); + } else { + MessageDialog.openError(getShell(), "Volume Logs", "Error while fetching volume logs: [" + status + + "]"); + } + } + }); + } + + protected boolean validateTimeRange(Date fromTimestamp, Date toTimestamp) { + if (fromTimestamp == null && toTimestamp == null) { + // no time range selected. nothing to validate. + return true; + } + + Calendar calendar = Calendar.getInstance(); + Date now = calendar.getTime(); + if (fromTimestamp != null && fromTimestamp.after(now)) { + MessageDialog.openError(getShell(), "Volume Logs", "From time can't be greater than current time!"); + return false; + } + + if (toTimestamp != null) { + if (toTimestamp.after(now)) { + MessageDialog.openError(getShell(), "Volume Logs", "To time can't be greater than current time!"); + return false; + } + + if (fromTimestamp.after(toTimestamp)) { + MessageDialog.openError(getShell(), "Volume Logs", "From time can't be greater than To time!"); + return false; + } + } + + return true; + } + + private void createToCheckbox(Composite composite) { + toCheckbox = toolkit.createButton(composite, null, SWT.CHECK); + toCheckbox.setBounds(320, 60, 15, 20); + toCheckbox.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + if (toCheckbox.getSelection()) { + toDate.setEnabled(true); + toTime.setEnabled(true); + } else { + toDate.setEnabled(false); + toTime.setEnabled(false); + } + } + }); + } + + private void createToTimeField(Composite composite) { + toTime = new DateTime(composite, SWT.BORDER | SWT.TIME); + toTime.setBounds(490, 60, 120, 20); + toTime.setEnabled(false); + toolkit.adapt(toTime); + toolkit.paintBordersFor(toTime); + } + + private void createToDateField(Composite composite) { + toDate = new DateTime(composite, SWT.BORDER | SWT.DROP_DOWN); + toDate.setBounds(365, 60, 120, 20); + toDate.setEnabled(false); + toolkit.adapt(toDate); + toolkit.paintBordersFor(toDate); + } + + private void createToDateLabel(Composite composite) { + Label lblTo = toolkit.createLabel(composite, "To", SWT.NONE); + lblTo.setBounds(340, 60, 25, 20); + } + + private void createFromCheckbox(Composite composite) { + fromCheckbox = toolkit.createButton(composite, null, SWT.CHECK); + fromCheckbox.setBounds(0, 60, 15, 20); + fromCheckbox.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + if (fromCheckbox.getSelection()) { + fromDate.setEnabled(true); + fromTime.setEnabled(true); + } else { + fromDate.setEnabled(false); + fromTime.setEnabled(false); + } + } + }); + } + + private void createFromTimeField(Composite composite) { + fromTime = new DateTime(composite, SWT.BORDER | SWT.TIME); + fromTime.setBounds(190, 60, 120, 20); + fromTime.setEnabled(false); + toolkit.adapt(fromTime); + toolkit.paintBordersFor(fromTime); + } + + private void createFromDateField(Composite composite) { + fromDate = new DateTime(composite, SWT.BORDER | SWT.DROP_DOWN); + fromDate.setBounds(60, 60, 120, 20); + fromDate.setEnabled(false); + toolkit.adapt(fromDate); + toolkit.paintBordersFor(fromDate); + } + + private void createFromDateLabel(Composite composite) { + Label lblFrom = toolkit.createLabel(composite, "from", SWT.NONE); + lblFrom.setBounds(20, 60, 40, 20); + } + + private void createSeverityCombo(Composite composite) { + severityCombo = new Combo(composite, SWT.READ_ONLY); + severityCombo.setBounds(555, 15, 110, 20); + + severityCombo.setItems(GlusterConstants.VOLUME_LOG_LEVELS_ARR.toArray(new String[0])); + severityCombo.select(VOLUME_LOG_LEVELS.ERROR.ordinal()); + severityCombo.add(CoreConstants.ALL, 0); + + toolkit.adapt(severityCombo); + toolkit.paintBordersFor(severityCombo); + } + + private void createSeverityLabel(Composite composite) { + Label lblSeverity = toolkit.createLabel(composite, "Severity", SWT.NONE); + lblSeverity.setBounds(480, 15, 70, 20); + } + + private void createBricksCombo(Composite composite) { + bricksCombo = new Combo(composite, SWT.READ_ONLY); + bricksCombo.setBounds(365, 15, 100, 20); + bricksCombo.setItems( volume.getBrickDirectories().toArray(new String[0])); + bricksCombo.add(CoreConstants.ALL, 0); + toolkit.adapt(bricksCombo); + toolkit.paintBordersFor(bricksCombo); + bricksCombo.select(0); + } + + private void createBricksLabel(Composite composite) { + Label lblMessagesAndFilter = toolkit.createLabel(composite, "messages, and filter on bricks", SWT.NONE); + lblMessagesAndFilter.setBounds(160, 15, 200, 20); + } + + private void createLineCountText(Composite composite) { + lineCountText = toolkit.createText(composite, "100", SWT.NONE); + lineCountText.setBounds(85, 15, 60, 20); + } + + private void createLineCountLabel(Composite composite) { + Label lblScanLast = toolkit.createLabel(composite, "Scan last", SWT.NONE); + lblScanLast.setBounds(0, 15, 80, 20); + } + + private void configureLayout() { + setLayout(new GridLayout(1, false)); + GridData layoutData = new GridData(); + layoutData.grabExcessHorizontalSpace = true; + layoutData.grabExcessVerticalSpace = true; + // layoutData.verticalIndent = 10; + setLayoutData(layoutData); + } + + private Composite createTableViewerComposite() { + Composite tableViewerComposite = new Composite(this, SWT.NO); + tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true); + layoutData.verticalIndent = 10; + tableViewerComposite.setLayoutData(layoutData); + return tableViewerComposite; + } + + private void setupLogsTable(Composite parent, Table table) { + table.setHeaderVisible(true); + table.setLinesVisible(false); + + TableColumnLayout tableColumnLayout = guiHelper.createTableColumnLayout(table, LOG_TABLE_COLUMN_NAMES); + parent.setLayout(tableColumnLayout); + + setColumnProperties(table, LOG_TABLE_COLUMN_INDICES.DATE, SWT.CENTER, 50); + setColumnProperties(table, LOG_TABLE_COLUMN_INDICES.TIME, SWT.CENTER, 50); + setColumnProperties(table, LOG_TABLE_COLUMN_INDICES.BRICK, SWT.CENTER, 50); + setColumnProperties(table, LOG_TABLE_COLUMN_INDICES.SEVERITY, SWT.CENTER, 50); + setColumnProperties(table, LOG_TABLE_COLUMN_INDICES.MESSAGE, SWT.LEFT, 100); + } + + /** + * Sets properties for alignment and weight of given column of given table + * + * @param table + * @param columnIndex + * @param alignment + * @param weight + */ + private void setColumnProperties(Table table, LOG_TABLE_COLUMN_INDICES columnIndex, int alignment, int weight) { + TableColumn column = table.getColumn(columnIndex.ordinal()); + column.setAlignment(alignment); + + TableColumnLayout tableColumnLayout = (TableColumnLayout) table.getParent().getLayout(); + tableColumnLayout.setColumnData(column, new ColumnWeightData(weight)); + } + + private Date extractTimestamp(DateTime date, DateTime time) { + Calendar calendar = Calendar.getInstance(); + calendar.setLenient(false); + calendar.set(Calendar.DAY_OF_MONTH, date.getDay()); + // in Calendar class, month starts with zero i.e. Jan = 0 + calendar.set(Calendar.MONTH, date.getMonth()); + calendar.set(Calendar.YEAR, date.getYear()); + calendar.set(Calendar.HOUR_OF_DAY, time.getHours()); + calendar.set(Calendar.MINUTE, time.getMinutes()); + calendar.set(Calendar.SECOND, time.getSeconds()); + return calendar.getTime(); + } +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumeOptionsPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumeOptionsPage.java new file mode 100644 index 00000000..bd003f3b --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumeOptionsPage.java @@ -0,0 +1,359 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * This file is part of Gluster Management Console. + * + * Gluster Management Console is free software; you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Gluster Management Console 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 Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * . + *******************************************************************************/ +package com.gluster.storage.management.gui.views.pages; + +import java.util.List; +import java.util.Map.Entry; + +import org.apache.commons.lang.WordUtils; +import org.eclipse.jface.layout.TableColumnLayout; +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.ColumnLayoutData; +import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; +import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.forms.widgets.FormToolkit; + +import com.gluster.storage.management.client.GlusterDataModelManager; +import com.gluster.storage.management.core.constants.CoreConstants; +import com.gluster.storage.management.core.model.DefaultClusterListener; +import com.gluster.storage.management.core.model.Event; +import com.gluster.storage.management.core.model.Event.EVENT_TYPE; +import com.gluster.storage.management.core.model.Volume; +import com.gluster.storage.management.core.model.VolumeOptionInfo; +import com.gluster.storage.management.gui.VolumeOptionsTableLabelProvider; +import com.gluster.storage.management.gui.utils.GUIHelper; + +public class VolumeOptionsPage extends Composite { + + private final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); + private TableViewer tableViewer; + private GUIHelper guiHelper = GUIHelper.getInstance(); + private Volume volume; + private DefaultClusterListener clusterListener; + private Text filterText; + private List defaultVolumeOptions = GlusterDataModelManager.getInstance() + .getVolumeOptionsDefaults(); + + public enum OPTIONS_TABLE_COLUMN_INDICES { + OPTION_KEY, OPTION_VALUE + }; + + private static final String[] OPTIONS_TABLE_COLUMN_NAMES = new String[] { "Option Key", "Option Value" }; + private Button addTopButton; + private Button addBottomButton; + private TableViewerColumn keyColumn; + private OptionKeyEditingSupport keyEditingSupport; + + public VolumeOptionsPage(final Composite parent, int style, Volume volume) { + super(parent, style); + + this.volume = volume; + + toolkit.adapt(this); + toolkit.paintBordersFor(this); + + setupPageLayout(); + filterText = guiHelper.createFilterText(toolkit, this); + + addTopButton = createAddButton(); + setupOptionsTableViewer(filterText); + + addBottomButton = createAddButton(); + + if (defaultVolumeOptions.size() == volume.getOptions().size()) { + setAddButtonsEnabled(false); + } + + tableViewer.setInput(volume.getOptions().entrySet()); + + parent.layout(); // Important - this actually paints the table + registerListeners(parent); + } + + private void setAddButtonsEnabled(boolean enable) { + addTopButton.setEnabled(enable); + addBottomButton.setEnabled(enable); + } + + private Button createAddButton() { + Button button = toolkit.createButton(this, "&Add", SWT.FLAT); + button.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + // add an empty option to be filled up by user + volume.setOption("", ""); + + tableViewer.refresh(); + tableViewer.setSelection(new StructuredSelection(getEntry(""))); + keyColumn.getViewer().editElement(getEntry(""), 0); // edit newly created entry + + // disable the add button AND search filter textbox till user fills up the new option + setAddButtonsEnabled(false); + filterText.setEnabled(false); + } + + private Entry getEntry(String key) { + for (Entry entry : volume.getOptions().entrySet()) { + if (entry.getKey().equals(key)) { + return entry; + } + } + return null; + } + }); + + // Make sure that add button is enabled only when search filter textbox is empty + filterText.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + if (filterText.getText().length() > 0) { + setAddButtonsEnabled(false); + } else { + if (defaultVolumeOptions.size() == volume.getOptions().size()) { + setAddButtonsEnabled(false); + } else { + setAddButtonsEnabled(true); + } + } + } + }); + return button; + } + + private void registerListeners(final Composite parent) { + addDisposeListener(new DisposeListener() { + public void widgetDisposed(DisposeEvent e) { + if (!(addTopButton.isEnabled() || addBottomButton.isEnabled())) { + // user has selected key, but not added value. Since this is not a valid entry, + // remove the last option (without value) from the volume + volume.getOptions().remove(keyEditingSupport.getEntryBeingAdded().getKey()); + } + + GlusterDataModelManager.getInstance().removeClusterListener(clusterListener); + toolkit.dispose(); + } + }); + + /** + * Ideally not required. However the table viewer is not getting laid out properly on performing + * "maximize + restore" So this is a hack to make sure that the table is laid out again on re-size of the window + */ + addPaintListener(new PaintListener() { + + @Override + public void paintControl(PaintEvent e) { + parent.layout(); + } + }); + + parent.addDisposeListener(new DisposeListener() { + + @Override + public void widgetDisposed(DisposeEvent e) { + if (!(addTopButton.isEnabled() || addBottomButton.isEnabled())) { + // user has selected key, but not added value. Since this is not a valid entry, + // remove the last option (without value) from the volume + Entry entryBeingAdded = keyEditingSupport.getEntryBeingAdded(); + volume.getOptions().remove(entryBeingAdded.getKey()); + } + } + }); + + clusterListener = new DefaultClusterListener() { + @SuppressWarnings("unchecked") + @Override + public void volumeChanged(Volume volume, Event event) { + super.volumeChanged(volume, event); + if (event.getEventType() == EVENT_TYPE.VOLUME_OPTIONS_RESET) { + if (!tableViewer.getControl().isDisposed()) { + tableViewer.refresh(); + setAddButtonsEnabled(true); + } + } + + if (event.getEventType() == EVENT_TYPE.VOLUME_OPTION_SET) { + Entry eventEntry = (Entry) event.getEventData(); + if (isNewOption(volume, eventEntry.getKey())) { + // option has been set successfully by the user. re-enable the add button and search filter + // textbox + setAddButtonsEnabled(true); + filterText.setEnabled(true); + } + + if (defaultVolumeOptions.size() == volume.getOptions().size()) { + setAddButtonsEnabled(false); + } + + if (tableViewer.getTable().getItemCount() < volume.getOptions().size()) { + // new volume set from outside this page. refresh the viewer. + tableViewer.refresh(); + } else { + // existing volume option value changed. update that element. + tableViewer.update(eventEntry, null); + } + } + } + + private boolean isNewOption(Volume volume, String optionKey) { + if (filterText.getText().length() > 0) { + // user has been filtering the contents. adding new option is allowed only when contents are NOT + // filtered. Thus it's impossible that this is a newly added option + return false; + } + + // if this is the last option in the volume options, it must be the new option + return optionKey.equals(volume.getOptions().keySet().toArray()[volume.getOptions().size() - 1]); + } + }; + GlusterDataModelManager.getInstance().addClusterListener(clusterListener); + } + + private void setupPageLayout() { + final GridLayout layout = new GridLayout(1, false); + layout.verticalSpacing = 10; + layout.marginTop = 10; + setLayout(layout); + } + + private void setupOptionsTable(Composite parent) { + Table table = tableViewer.getTable(); + table.setHeaderVisible(true); + table.setLinesVisible(false); + + TableColumnLayout tableColumnLayout = createTableColumnLayout(); + parent.setLayout(tableColumnLayout); + + setColumnProperties(table, OPTIONS_TABLE_COLUMN_INDICES.OPTION_KEY, SWT.CENTER, 100); + setColumnProperties(table, OPTIONS_TABLE_COLUMN_INDICES.OPTION_VALUE, SWT.CENTER, 100); + } + + private TableColumnLayout createTableColumnLayout() { + TableColumnLayout tableColumnLayout = new TableColumnLayout(); + ColumnLayoutData defaultColumnLayoutData = new ColumnWeightData(100); + + tableColumnLayout.setColumnData(createKeyColumn(), defaultColumnLayoutData); + tableColumnLayout.setColumnData(createValueColumn(), defaultColumnLayoutData); + + return tableColumnLayout; + } + + private TableColumn createValueColumn() { + TableViewerColumn valueColumn = new TableViewerColumn(tableViewer, SWT.NONE); + valueColumn.getColumn() + .setText(OPTIONS_TABLE_COLUMN_NAMES[OPTIONS_TABLE_COLUMN_INDICES.OPTION_VALUE.ordinal()]); + valueColumn.setLabelProvider(new ColumnLabelProvider() { + @SuppressWarnings("unchecked") + @Override + public String getText(Object element) { + return ((Entry) element).getValue(); + } + }); + + // User can edit value of a volume option + valueColumn.setEditingSupport(new OptionValueEditingSupport(valueColumn.getViewer(), volume)); + + return valueColumn.getColumn(); + } + + private TableColumn createKeyColumn() { + keyColumn = new TableViewerColumn(tableViewer, SWT.NONE); + keyColumn.getColumn().setText(OPTIONS_TABLE_COLUMN_NAMES[OPTIONS_TABLE_COLUMN_INDICES.OPTION_KEY.ordinal()]); + keyColumn.setLabelProvider(new ColumnLabelProvider() { + @SuppressWarnings("unchecked") + @Override + public String getText(Object element) { + return ((Entry) element).getKey(); + } + + @SuppressWarnings("unchecked") + @Override + public String getToolTipText(Object element) { + String key = ((Entry) element).getKey(); + if (key.isEmpty()) { + return "Click to select a volume option key"; + } + + VolumeOptionInfo optionInfo = GlusterDataModelManager.getInstance().getVolumeOptionInfo(key); + // Wrap the description before adding to tooltip so that long descriptions are displayed properly + return WordUtils.wrap(optionInfo.getDescription(), 60) + CoreConstants.NEWLINE + "Default value: " + + optionInfo.getDefaultValue(); + } + }); + + // Editing support required when adding new key + keyEditingSupport = new OptionKeyEditingSupport(keyColumn.getViewer(), volume); + keyColumn.setEditingSupport(keyEditingSupport); + + return keyColumn.getColumn(); + } + + private void createOptionsTableViewer(Composite parent) { + tableViewer = new TableViewer(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.SINGLE); + tableViewer.setLabelProvider(new VolumeOptionsTableLabelProvider()); + tableViewer.setContentProvider(new ArrayContentProvider()); + tableViewer.getTable().setLinesVisible(true); + + setupOptionsTable(parent); + } + + private Composite createTableViewerComposite() { + Composite tableViewerComposite = new Composite(this, SWT.NO); + tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + tableViewerComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + return tableViewerComposite; + } + + private void setupOptionsTableViewer(final Text filterText) { + Composite tableViewerComposite = createTableViewerComposite(); + createOptionsTableViewer(tableViewerComposite); + ColumnViewerToolTipSupport.enableFor(tableViewer); + // Create a case insensitive filter for the table viewer using the filter text field + guiHelper.createFilter(tableViewer, filterText, false); + } + + private void setColumnProperties(Table table, OPTIONS_TABLE_COLUMN_INDICES columnIndex, int alignment, int weight) { + TableColumn column = table.getColumn(columnIndex.ordinal()); + column.setAlignment(alignment); + + TableColumnLayout tableColumnLayout = (TableColumnLayout) table.getParent().getLayout(); + tableColumnLayout.setColumnData(column, new ColumnWeightData(weight)); + } +} diff --git a/src/com.gluster.storage.management.server/WebContent/scripts/Protocol.py b/src/com.gluster.storage.management.server/WebContent/scripts/Protocol.py new file mode 100644 index 00000000..ff073593 --- /dev/null +++ b/src/com.gluster.storage.management.server/WebContent/scripts/Protocol.py @@ -0,0 +1,438 @@ +# Copyright (C) 2009 Gluster, Inc. +# This file is part of Gluster Storage Platform. +# +# Gluster Storage Platform is free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 3 of +# the License, or (at your option) any later version. +# +# Gluster Storage Platform 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, see +# . + +import xml +import xml.parsers.expat +import xml.dom.minidom as MDOM +import os +import Globals +import copy +import Utils + +XML_STRING = 0 +XML_FILE = 1 + +class XDOM: + _domObj = None + + def __init__(self): + self._domObj = MDOM.Document() + return + + @classmethod + def getText(self, nodeList): + rc = "" + for node in nodeList: + if node.nodeType == node.TEXT_NODE: + rc = rc + node.data + return rc.strip() + + def parseString(self, requestString): + try: + self._domObj = MDOM.parseString(requestString) + except xml.parsers.expat.ExpatError, e: + Utils.log("XML string parse error: %s" % str(e)) + return False + return True + + def parseFile(self, fileName): + try: + self._domObj = MDOM.parse(fileName) + except IOError, e: + Utils.log("error reading file: %s" % str(e)) + return False + except xml.parsers.expat.ExpatError, e: + Utils.log("XML file %s parse error: %s" % (fileName, str(e))) + return False + return True + + def setDomObj(self, dom): + if dom and type(dom) != type([]): + self._domObj = dom + return True + return False + + def createTextNode(self, text): + if not self._domObj: + return False + if not text: + return False + return self._domObj.createTextNode(str(text)) + + def createTag(self, tag, text=None): + if not self._domObj: + return None + if tag == None: + return None + + tagE = self._domObj.createElement(str(tag)) + if text: + tagEText = self._domObj.createTextNode(str(text)) + tagE.appendChild(tagEText) + return tagE + + def addTag(self, tag): + if not self._domObj: + return False + if not tag: + return False + + self._domObj.appendChild(tag) + return True + + def createTagRoute(self, tagRoute, text=None): + if not tagRoute: + return False + + tagList = tagRoute.split(".") + tag = None + previousTag = None + for tagName in tagList[:-1]: + newTag = self.createTag(tagName, None) + if not tag: + tag = newTag + previousTag = newTag + continue + previousTag.appendChild(newTag) + previousTag = newTag + + if previousTag: + previousTag.appendChild(self.createTag(tagList[-1], text)) + else: + tag = self.createTag(tagList[-1], text) + return tag + + def appendTagRoute(self, tagRoute, value=None): + if not self._domObj: + return False + if not tagRoute: + return False + + parentTagE = self._domObj + + tagNameList = tagRoute.split(".") + newTagRoute = tagNameList.pop(-1) + + for i in range(len(tagNameList), 0, -1): + tagE = self.getElementsByTagRoute(".".join(tagNameList[:i])) + if tagE: + parentTagE = tagE[0] + break + newTagRoute = tagNameList[i-1] + "." + newTagRoute + + newTagE = self.createTagRoute(newTagRoute, value) + if not newTagE: + return False + try: + parentTagE.appendChild(newTagE) + except xml.dom.HierarchyRequestErr, e: + Utils.log("error occured. %s" + str(e)) + return False + return True + + def setTextByTagRoute(self, tagRoute, tagValue): + if not self._domObj: + return None + + if not tagRoute: + return None + + tagE = self.getElementsByTagRoute(tagRoute) + if not tagE: + return False + + parentTagE = self.getElementsByTagRoute(".".join(tagRoute.split(".")[:-1])) + if not parentTagE: + return False + + parentTagE[0].childNodes.remove(tagE[0]) + parentTagE[0].appendChild(self.createTag(tagRoute.split(".")[-1], tagValue)) + return True + + def getElementsByTagRoute(self, tagRoute): + if not self._domObj: + return None + + if not tagRoute: + return None + + x = None + for tag in tagRoute.split("."): + if x is None: + x = self._domObj.getElementsByTagName(tag) + continue + if x == []: + break + x = x[0].getElementsByTagName(tag) + return x + + def getTextByTagRoute(self, tagRoute): + if not self._domObj: + return None + + x = self.getElementsByTagRoute(tagRoute) + if x: + return self.getText(x[0].childNodes) + return None + + def getElementsByTagName(self, name): + if not self._domObj: + return None + return self._domObj.getElementsByTagName(name) + + def writexml(self, fileName, indent="", addindent="", newl=""): + if not self._domObj: + return None + try: + fp = open(fileName, "w") + self._domObj.writexml(fp, indent, addindent, newl) + fp.close() + return True + except IOError: + return False + + def toString(self, indent=" ", newl="\n", encoding = None): + if not self._domObj: + return None + return self._domObj.toprettyxml(indent, newl, encoding) + + def toxml(self, encoding = None): + if not self._domObj: + return None + return self._domObj.toxml(encoding) + + def toprettyxml(self, indent=" ", newl="\n", encoding = None): + return self.toString(indent, newl, encoding) + + def getAttribute(self, attributeName): + if not attributeName: + return None + try: + return self.getElementsByTagName("command")[0].getAttribute(attributeName) + except IndexError: + return False + + def setAttribute(self, attributeName, attributeValue): + if not (attributeName and attributeValue): + return None + try: + return self.getElementsByTagName("command")[0].setAttribute(attributeName, attributeValue) + except IndexError: + return False + + def getRequestCommand(self): + return self.getAttribute("request") + + def getResponseCommand(self): + return self.getAttribute("response") + + def getResponseCode(self): + return self.getAttribute("response-code") + + def getMessageId(self): + return self.getAttribute("id") + + def getVersion(self): + return self.getAttribute("version") + + def getRequestAction(self): + return self.getAttribute("action") + + def setVersion(self, value): + return self.setAttribute("version", value) + + def setRequestAction(self, value): + return self.setAttribute("action", value) + + def createCommandTag(self, command, responseCode, id, version=Globals.GLUSTER_PLATFORM_VERSION): + commandTag = self._domObj.createElement("command") + commandTag.setAttribute("response", command) + commandTag.setAttribute("response-code", responseCode) + commandTag.setAttribute("id", id) + commandTag.setAttribute("version", version) + return commandTag +##--end of XDOM + +class RequestXml(XDOM): + def __init__(self, requestString, type=None): + if None == requestString: + XDOM.__init__(self) + return + try: + if None == type: + if os.path.isfile(requestString): + self._domObj = MDOM.parse(requestString) + else: + self._domObj = MDOM.parseString(requestString) + elif XML_FILE == type: + self._domObj = MDOM.parse(requestString) + elif XML_STRING == type: + self._domObj = MDOM.parseString(requestString) + except IOError: + XDOM.__init__(self) + except xml.parsers.expat.ExpatError: + XDOM.__init__(self) + +##--end of RequestXML + +class ResponseXml(XDOM): + _commandTag = None + def __init__(self, command, responseCode, id, version=Globals.GLUSTER_PLATFORM_VERSION): + XDOM.__init__(self) + if command and responseCode and id: + self._commandTag = self.createCommandTag(command, responseCode, id, version) + self._domObj.appendChild(self._commandTag) + + def appendCommand(self, command, responseCode, id, version=Globals.GLUSTER_PLATFORM_VERSION): + if command and responseCode and id: + self._commandTag = self.createCommandTag(command, responseCode, id, version) + self._domObj.appendChild(self._commandTag) + return True + return False + + def append(self, tagName, tagValue=None): + if not self._commandTag: + return False + tag = self.createTag(tagName, tagValue) + if tag: + self._commandTag.appendChild(tag) + return True + return False + + def appendTag(self, tag): + if not tag: + return False + if not self._commandTag: + return False + self._commandTag.appendChild(tag) + return True + + def appendTagRoute(self, tagRoute, value=None): + if not self._commandTag: + return False + if not tagRoute: + return False + + parentTagE = self._commandTag + + tagNameList = tagRoute.split(".") + newTagRoute = tagNameList.pop(-1) + + for i in range(len(tagNameList), 0, -1): + tagE = self.getElementsByTagRoute(".".join(["command"] + tagNameList[:i])) + if tagE: + parentTagE = tagE[0] + break + newTagRoute = tagNameList[i-1] + "." + newTagRoute + + newTagE = self.createTagRoute(newTagRoute, value) + if not newTagE: + return False + try: + parentTagE.appendChild(newTagE) + except xml.dom.HierarchyRequestErr, e: + Utils.log("error occured. %s" + str(e)) + return False + return True + + def appendTagRouteOld(self, tagRoute, value=None): + if not tagRoute: + return False + if not self._commandTag: + return False + + tmpTagRoute = "" + previousTagE = self._commandTag + tagE = None + for tagName in tagRoute.split("."): + if not tmpTagRoute: + tagE = self.getElementsByTagRoute("command." + tagName) + else: + tagE = self.getElementsByTagRoute("command." + tmpTagRoute + "." + tagName) + if not tagE: + break + if len(tagE) != 1: + return False + previousTagE = tagE[0] + if not tmpTagRoute: + tmpTagRoute = tagName + else: + tmpTagRoute = tmpTagRoute + "." + tagName + + if tmpTagRoute == tagRoute: + return False + newTagRoute = tagRoute[len(tmpTagRoute):] + if newTagRoute[0] == '.': + newTagRoute = newTagRoute[1:] + + if previousTagE.childNodes and previousTagE.childNodes[0].nodeType == previousTagE.TEXT_NODE: + return False + previousTagE.appendChild(self.createTagRoute(newTagRoute, value)) + return True +##--end of ResponseXml + +def test(): + #volumes = RequestXml(VolumeFile, XML_FILE).getElementsByTagRoute("volume-list.volume") + requestStr = ''' + +movies1 +cluster mirror +512000 +zresearch +192.168.20.* +192.168.30.* + +no + + +no + + +no + + +''' + + requestXml = RequestXml(requestStr) + print requestXml.getAttribute("") + +def test1(): + rs = ResponseXml("create-volume", "OK", "xyz") + rs.appendTagRoute("volume.detail.name", "music") + print rs.toprettyxml() + rs.append("volume", "data") + print rs.toprettyxml() + rs.appendTagRoute("volume.detail.ipaddr", "192.168.10.1") + print rs.toprettyxml() + print rs.appendTagRoute("volume.detail.ipaddr.v6", "ff:ff::ff::") + print rs.toprettyxml() + + print rs.getTextByTagRoute("command.volume.detail") + +def test2(): + rs = ResponseXml("download-volume-logs", "OK", "xyz") + te = rs.createTag("interface", None) + te.appendChild(rs.createTag("device", "DEVICE1")) + te.appendChild(rs.createTag("description", "my device one")) + rs.appendTag(te) + + te = rs.createTag("interface", None) + te.appendChild(rs.createTag("device", "DEVICE2")) + te.appendChild(rs.createTag("description", "my device two")) + rs.appendTag(te) + print rs.toprettyxml() + diff --git a/src/com.gluster.storage.management.server/WebContent/scripts/Utils.py b/src/com.gluster.storage.management.server/WebContent/scripts/Utils.py new file mode 100644 index 00000000..f9b3254b --- /dev/null +++ b/src/com.gluster.storage.management.server/WebContent/scripts/Utils.py @@ -0,0 +1,705 @@ +# Copyright (c) 2010 Gluster, Inc. +# This file is part of Gluster Storage Platform. +# +# Gluster Storage Platform is free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 3 of +# the License, or (at your option) any later version. +# +# Gluster Storage Platform 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, see +# . + +import sys +import os +import re +import socket +import struct +import syslog +import subprocess +#import spwd +import time +#import uuid +import tempfile +import grp +import pwd +import inspect +from datetime import datetime +import urllib + +import Globals +import Protocol +from Common import * + +RUN_COMMAND_ERROR = -1024 +LOG_SYSLOG = 1 +SYSLOG_REQUIRED = False +LOG_FILE_NAME = None +LOG_FILE_OBJ = None + + +def _getLogCode(priority): + if syslog.LOG_EMERG == priority: + return "M" + elif syslog.LOG_ALERT == priority: + return "A" + elif syslog.LOG_CRIT == priority: + return "C" + elif syslog.LOG_ERR == priority: + return "E" + elif syslog.LOG_WARNING == priority: + return "W" + elif syslog.LOG_NOTICE == priority: + return "N" + elif syslog.LOG_INFO == priority: + return "I" + elif syslog.LOG_DEBUG == priority: + return "D" + else: # UNKNOWN + return "X" + + +def setLogFile(fileName): + global LOG_FILE_NAME + + if fileName: + LOG_FILE_NAME = fileName + return True + return False + + +def closeLog(): + global LOG_FILE_OBJ + global SYSLOG_REQUIRED + + if SYSLOG_REQUIRED: + syslog.closelog() + SYSLOG_REQUIRED = False + return True + + if LOG_FILE_OBJ: + try: + LOG_FILE_OBJ.close() + LOG_FILE_OBJ = None + except IOError, e: + sys.stderr.write("Failed to close file: %s\n" % e) + return False + return True + + +def openLog(fileName=None): + global LOG_FILE_NAME + global LOG_FILE_OBJ + global SYSLOG_REQUIRED + + if fileName == LOG_SYSLOG: + syslog.openlog(os.path.basename(sys.argv[0])) + SYSLOG_REQUIRED = True + return True + + if fileName: + LOG_FILE_NAME = fileName + + if not LOG_FILE_NAME: + return False + + closeLog() + + try: + LOG_FILE_OBJ = open(LOG_FILE_NAME, "a") + except IOError, e: + sys.stderr.write("Failed to open file %s: %s\n" % (LOG_FILE_NAME, e)) + return False + return True + +def record(priority, message=None): + global LOG_FILE_OBJ + global SYSLOG_REQUIRED + + stack = inspect.stack()[1] + if stack[3] == "": + prefix = "%s:%s:%s" % (stack[1], stack[2], stack[3]) + else: + prefix = "%s:%s:%s()" % (stack[1], stack[2], stack[3]) + + if type(priority) == type("") or type(priority) == type(u""): + logPriority = syslog.LOG_INFO + logMessage = priority + else: + logPriority = priority + logMessage = message + + if SYSLOG_REQUIRED: + syslog.syslog(logPriority, "[%s]: %s" % (prefix, logMessage)) + return + + fp = sys.stderr + if LOG_FILE_OBJ: + fp = LOG_FILE_OBJ + + fp.write("[%s] %s [%s]: %s" % (str(datetime.now()), _getLogCode(logPriority), prefix, logMessage)) + if logMessage[-1] != '\n': + fp.write("\n") + fp.flush() + return + + +def trace(message): + if message: + log(syslog.LOG_DEBUG, message) + + +def isString(value): + return (type(value) == type("") or type(value) == type(u"")) + + +def getTempFileName(): + filedesc, filename = tempfile.mkstemp(prefix="GSP_") + os.close(filedesc) + return filename + + +def runCommandBG(command, stdinFileObj=None, stdoutFileObj=None, stderrFileObj=None, + shell=False, root=None): + log("runCommandBG(): Trying to execute command [%s]" % command) + + if shell: + if not isString(command): + return None + else: + if isString(command): + command = command.split() + + if root == True: + if shell: + command = "sudo " + command + else: + command = ['sudo'] + command + elif isString(root): + if shell: + command = "sudo -u " + root + " " + command + else: + command = ['sudo', '-u', root] + command + + if not stdinFileObj: + stdinFileObj=subprocess.PIPE + if not stdoutFileObj: + stdoutFileObj=subprocess.PIPE + if not stderrFileObj: + stderrFileObj=subprocess.PIPE + + try: + process = subprocess.Popen(command, + bufsize=-1, + stdin=stdinFileObj, + stdout=stdoutFileObj, + stderr=stderrFileObj, + shell=shell) + return process + except OSError, e: + log("runCommandBG(): Failed to run command [%s]: %s" % (command, e)) + return None + + +def runCommand(command, + input='', output=False, + shell=False, root=None): + rv = {} + rv["Status"] = RUN_COMMAND_ERROR + rv["Stdout"] = None + rv["Stderr"] = None + + try: + stdinFileName = getTempFileName() + stdinFileObj = open(stdinFileName, "w") + stdinFileObj.write(input) + stdinFileObj.close() + stdinFileObj = open(stdinFileName, "r") + + stdoutFileName = getTempFileName() + stdoutFileObj = open(stdoutFileName, "w") + + stderrFileName = getTempFileName() + stderrFileObj = open(stderrFileName, "w") + except IOError, e: + log("Failed to create temporary file for executing command [%s]: %s" % (command, e)) + if output: + return rv + return rv["Status"] + + stdoutContent = None + stderrContent = None + + process = runCommandBG(command, + stdinFileObj=stdinFileObj, + stdoutFileObj=stdoutFileObj, + stderrFileObj=stderrFileObj, + shell=shell, root=root) + if process: + rv['Status'] = process.wait() + rv['Stdout'] = open(stdoutFileName).read() + rv['Stderr'] = open(stderrFileName).read() + + os.remove(stdinFileName) + os.remove(stdoutFileName) + os.remove(stderrFileName) + + log("runCommand(): execution status of command [%s] = [%s]" % (command, rv)) + + if output: + return rv + return rv["Status"] + + +def runCommandFG(command, stdout=False, stderr=False, + shell=False, root=None): + if stdout or stderr: + output = True + else: + output = False + return runCommand(command, output=output, shell=shell, root=root) + + +def IP2Number(ipString): + try: + return socket.htonl(struct.unpack("I", socket.inet_aton(ipString))[0]) + except socket.error: + return None + except TypeError: + return None + except struct.error: + return None + + +def Number2IP(number): + try: + return socket.inet_ntoa(struct.pack("I", socket.ntohl(number))) + except socket.error: + return None + except AttributeError: + return None + except ValueError: + return None + + +def computeHostName(hostName): + if not hostName: + return False + + hostPrefix = "" + for i in range(len(hostName), 0, -1): + pos = i - 1 + if hostName[pos].isdigit(): + continue + break + hostPrefix = hostName[:pos+1] + try: + hostIndex = int(hostName[pos+1:]) + except ValueError: + hostIndex = 0 + # TODO: Check the availablity of the (server) name + return "%s%s" % (hostPrefix, hostIndex + 1) + + +def daemonize(): + try: + pid = os.fork() + if pid > 0: + # exit first parent + sys.exit(0) + except OSError, e: + #sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) + return False + + # decouple from parent environment + os.chdir("/") + os.setsid() + os.umask(0) + + # do second fork + try: + pid = os.fork() + if pid > 0: + # exit from second parent + sys.exit(0) + except OSError, e: + #sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) + return False + + # redirect standard file descriptors + sys.stdout.flush() + sys.stderr.flush() + si = file("/dev/null", 'r') + so = file("/dev/null", 'a+') + se = file("/dev/null", 'a+', 0) + os.dup2(si.fileno(), sys.stdin.fileno()) + os.dup2(so.fileno(), sys.stdout.fileno()) + os.dup2(se.fileno(), sys.stderr.fileno()) + return True + + +def getDownloadStatus(fileName): + try: + lines = [line for line in open(fileName) + if "saved" in line or "%" in line] + except IOError: + return 0 + if not lines: + return 0 + if "saved" in lines[-1]: + return 100 + return lines[-1].split("%")[0].split()[-1] + + +def getMeminfo(): + """-> dict of data from meminfo (str:int). + Values are in kilobytes. + """ + import re + re_parser = re.compile(r'^(?P\S*):\s*(?P\d*)\s*kB' ) + result = {} + for line in open('/proc/meminfo'): + match = re_parser.match(line) + if not match: + continue # skip lines that don't parse + key, value = match.groups(['key', 'value']) + result[key] = int(value) + return result + + +def getCpuUsage(): + """-> dict of cpuid : (usertime, nicetime, systemtime, idletime) + cpuid "cpu" means the total for all CPUs. + cpuid "cpuN" means the value for CPU N. + """ + wanted_records = [line for line in open('/proc/stat') if + line.startswith('cpu')] + result = {} + for cpuline in wanted_records: + fields = cpuline.split()[:5] + data = map(int, fields[1:]) + result[fields[0]] = tuple(data) + return result + + +def getLoadavg(): + """-> 5-tuple containing the following numbers in order: + - 1-minute load average (float) + - 5-minute load average (float) + - 15-minute load average (float) + - Number of threads/processes currently executing (<= number of + CPUs) (int) + - Number of threads/processes that exist on the system (int) + - The PID of the most recently-created process on the system (int) + """ + loadavgstr = open('/proc/loadavg', 'r').readline().strip() + data = loadavgstr.split() + avg1, avg5, avg15 = map(float, data[:3]) + threads_and_procs_running, threads_and_procs_total = map(int, + data[3].split('/')) + most_recent_pid = int(data[4]) + ncpus = 1 + final_avg = "" + if hasattr(os, "sysconf"): + if os.sysconf_names.has_key("SC_NPROCESSORS_ONLN"): + # Linux + ncpus = os.sysconf("SC_NPROCESSORS_ONLN") + if isinstance(ncpus, int) and ncpus > 0: + final_avg = "%.2f" % (1.0 * avg1 / ncpus) + + # Future return everything when needed + # Commenting this for the time being + # avg5, avg15, threads_and_procs_running, threads_and_procs_total, most_recent_pid + return final_avg + + +def getInfinibandPortStatus(): + + """ Check for availability of infiniband port + and return which port is active in a key pair value + """ + + # Check for existence of infiniband ports + value = os.popen ("ls /sys/class/infiniband").readline().strip() + + if not value: + return None + + portlist = os.popen ("echo /sys/class/infiniband/*/ports/*").readline().split() + + portkeys = {} + + for port in portlist: + value = os.popen ("cat %s/state" % + port.strip()).readline().split(':')[1].strip() + portkeys[port.strip()] = value + + return portkeys + + +def getServerCount(): + try: + return int(open(Globals.SERVER_COUNT_FILE).read().strip()) + except IOError: + log("failed to read file %s" % Globals.SERVER_COUNT_FILE) + return 1 + except ValueError: + log("invalid number format in file %s" % Globals.SERVER_COUNT_FILE) + return 1 + + +def setServerCount(count): + try: + open(Globals.SERVER_COUNT_FILE, "w").write("%s\n" % count) + return True + except IOError: + log("failed to write file %s" % Globals.SERVER_COUNT_FILE) + return False + + +def getInstalledServerCount(): + try: + return int(open(Globals.INSTALLED_SERVER_COUNT_FILE).read().strip()) + except IOError: + log("failed to read file %s" % Globals.INSTALLED_SERVER_COUNT_FILE) + return 1 + except ValueError: + log("invalid number format in file %s" % Globals.INSTALLED_SERVER_COUNT_FILE) + return 1 + + +def setInstalledServerCount(count): + try: + open(Globals.INSTALLED_SERVER_COUNT_FILE, "w").write("%s\n" % count) + return True + except IOError: + log("failed to write file %s" % Globals.INSTALLED_SERVER_COUNT_FILE) + return False + + +def getLastInstalledServerIpList(): + ipList = {} + networkDom = Protocol.XDOM() + if not networkDom.parseFile(Globals.GLOBAL_NETWORK_FILE): + log("failed to parse file %s" % Globals.GLOBAL_NETWORK_FILE) + for tagE in networkDom.getElementsByTagRoute("server.interface"): + interfaceDom = Protocol.XDOM() + interfaceDom.setDomObj(tagE) + ipAddress = interfaceDom.getTextByTagRoute("ipaddr") + if ipAddress: + ipList[interfaceDom.getTextByTagRoute("device")] = ipAddress + return ipList + + +def getFreeIpAddress(device=None): + serverCount = getServerCount() + installedServerCount = getInstalledServerCount() + if serverCount == installedServerCount: + return None + + availableServerCount = serverCount - installedServerCount + ipList = getLastInstalledServerIpList() + + if not ipList: + return None + + if device: + if device not in ipList.keys(): + return None + deviceIpAddress = ipList[device] + else: + deviceIpAddress = ipList.values()[0] + ipNumber = IP2Number(deviceIpAddress) + + for i in range((ipNumber + availableServerCount), ipNumber, -1): + ipAddress = Number2IP(i) + if runCommandFG(["ping", "-qnc", "1", ipAddress]) != 0: + return ipAddress + return None + + +def getPasswordHash(userName): + try: + #return spwd.getspnam(userName).sp_pwd + return "Not implimented" + except KeyError: + return None + + +def getTransactionKey(): + try: + tokens = open(Globals.TRANSACTION_KEY_FILE).read().split(',') + except IOError: + return None, None + return tokens + + +def generateSignature(): + #return str(uuid.uuid4()) + ('--%f' % time.time()) + return ('--%f' % time.time()) + + +def getSignature(): + try: + return open(Globals.SIGNATURE_FILE).read().strip() + except IOError: + log(syslog.LOG_ERR, "unable to read signaure from %s file" % Globals.SIGNATURE_FILE) + return False + + +def storeSignature(signature, fileName=Globals.SIGNATURE_FILE): + try: + open(fileName, "w").write(signature + "\n") + except IOError: + log(syslog.LOG_ERR, "unable to write signature %s to %s file" % (signature, fileName)) + return False + return True + + +def isUserExist(userName): + try: + grp.getgrnam(userName).gr_gid + return True + except KeyError: + pass + try: + pwd.getpwnam(userName).pw_uid + return True + except KeyError: + pass + return False + + +def getGsnUserInfo(fileName=Globals.GSN_USER_INFO_FILE): + userInfo = {} + userInfo["UserId"] = None + userInfo["Password"] = None + try: + for line in open(fileName): + line = line.strip() + k = line[:line.index("=")] + v = line[line.index("=") + 1:] + if v[0] == "'" or v[0] == '"': + v = v[1:] + if v[-1] == "'" or v[-1] == '"': + v = v[:-1] + if k.upper() == "GSN_ID": + userInfo["UserId"] = v + if k.upper() == "GSN_PASSWORD": + userInfo["Password"] = v + except IOError, e: + log("Failed to read file %s: %s" % (fileName, e)) + return userInfo + + +def setGsnUserInfo(userInfo, fileName=Globals.GSN_USER_INFO_FILE): + try: + fp = open(fileName, "w") + fp.write("GSN_ID=%s\n" % userInfo["UserId"]) + fp.write("GSN_PASSWORD=%s\n" % userInfo["Password"]) + fp.close() + return True + except IOError, e: + log("Failed to write file %s: %s" % (fileName, e)) + return False + + +def getPlatformVersion(fileName=Globals.GLUSTER_VERSION_FILE): + versionInfo = {} + versionInfo["Version"] = None + versionInfo["Update"] = None + try: + lines = open(Globals.GLUSTER_VERSION_FILE).readlines() + for line in open(fileName): + line = line.strip() + k = line[:line.index("=")] + v = line[line.index("=") + 1:] + if v[0] == "'" or v[0] == '"': + v = v[1:] + if v[-1] == "'" or v[-1] == '"': + v = v[:-1] + if k.upper() == "VERSION": + versionInfo["Version"] = v + if k.upper() == "UPDATE": + versionInfo["Update"] = v + except IOError, e: + log("Failed to read file %s: %s" % (fileName, e)) + return versionInfo + + +def setPlatformVersion(versionInfo, fileName=Globals.GLUSTER_VERSION_FILE): + if isString(versionInfo): + tokens = versionInfo.strip().split(".") + if len(tokens) < 2: + log("Invalid version format %s. Expecting .." % versionInfo) + return False + version = ".".join(tokens[:2]) + update = ".".join(tokens[2:]) + if not update: + update = "0" + else: + version = versionInfo["Version"] + update = versionInfo["Update"] + try: + fp = open(fileName, "w") + fp.write("VERSION=%s\n" % version) + fp.write("UPDATE=%s\n" % update) + fp.close() + return True + except IOError, e: + log("Failed to write file %s: %s" % (fileName, e)) + return False + + +def getGlusterUpdateDom(serverVersion): + errorMessage = "" + updateInfoDom = None + try: + baseUrl = open(Globals.GLUSTER_UPDATE_SITE_FILE).read().strip() + except IOError, e: + log("Failed to read file %s: %s" % (Globals.GLUSTER_UPDATE_SITE_FILE, e)) + errorMessage = "Failed to read update site file" + return updateInfoDom, errorMessage + + try: + url = "%s/%s/%s" % (baseUrl, serverVersion, Globals.GLUSTER_UPDATES_FILE) + connection = urllib.urlopen(url) + if connection.getcode() != 200: + connection.close() + errorMessage = "Error received from server to open URL %s" % url + return updateInfoDom, errorMessage + updateInfoString = connection.read() + connection.close() + except IOError, e: + log("Failed to get update information from URL %s: %s" % (url, e)) + errorMessage = "Error getting update information" + return updateInfoDom, errorMessage + + updateInfoDom = Protocol.XDOM() + if not updateInfoDom.parseString(updateInfoString): + log("XML parse error on update information content [%s]" % updateInfoString) + errorMessage = "Parse error on update information" + updateInfoDom = None + return updateInfoDom, errorMessage + + +def removeFile(fileName, root=False): + if root: + if runCommand("rm %s" % fileName, root=True) == 0: + return True + return False + try: + os.remove(fileName) + return True + except OSError, e: + Utils.log("Failed to remove file %s: %s" % (fileName, e)) + return False + + +def isLiveMode(): + return os.path.exists(Globals.LIVE_MODE_FILE) diff --git a/src/com.gluster.storage.management.server/WebContent/scripts/XmlHandler.py b/src/com.gluster.storage.management.server/WebContent/scripts/XmlHandler.py new file mode 100644 index 00000000..72164ffb --- /dev/null +++ b/src/com.gluster.storage.management.server/WebContent/scripts/XmlHandler.py @@ -0,0 +1,346 @@ +# Copyright (C) 2009 Gluster, Inc. +# This file is part of Gluster Storage Platform. +# +# Gluster Storage Platform is free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 3 of +# the License, or (at your option) any later version. +# +# Gluster Storage Platform 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, see +# . + +import xml +import xml.parsers.expat +import xml.dom.minidom as MDOM +import os +import Globals +import copy +import Utils + +XML_STRING = 0 +XML_FILE = 1 + +class XDOM: + _domObj = None + + def __init__(self): + self._domObj = MDOM.Document() + return + + @classmethod + def getText(self, nodeList): + rc = "" + for node in nodeList: + if node.nodeType == node.TEXT_NODE: + rc = rc + node.data + return rc + + def parseString(self, requestString): + try: + self._domObj = MDOM.parseString(requestString) + except xml.parsers.expat.ExpatError, e: + Utils.log("XML string parse error: %s" % str(e)) + return False + return True + + def parseFile(self, fileName): + try: + self._domObj = MDOM.parse(fileName) + except IOError, e: + Utils.log("error reading file: %s" % str(e)) + return False + except xml.parsers.expat.ExpatError, e: + Utils.log("XML file %s parse error: %s" % (fileName, str(e))) + return False + return True + + def setDomObj(self, dom): + if dom and type(dom) != type([]): + self._domObj = dom + return True + return False + + def createTag(self, tag, text=None): + if not self._domObj: + return None + if tag == None: + return None + + tagE = self._domObj.createElement(str(tag)) + if text: + tagEText = self._domObj.createTextNode(str(text)) + tagE.appendChild(tagEText) + return tagE + + def addTag(self, tag): + if not self._domObj: + return False + if not tag: + return False + + self._domObj.appendChild(tag) + return True + + def createTagRoute(self, tagRoute, text=None): + if not tagRoute: + return False + + tagList = tagRoute.split(".") + tag = None + previousTag = None + for tagName in tagList[:-1]: + newTag = self.createTag(tagName, None) + if not tag: + tag = newTag + previousTag = newTag + continue + previousTag.appendChild(newTag) + previousTag = newTag + + if previousTag: + previousTag.appendChild(self.createTag(tagList[-1], text)) + else: + tag = self.createTag(tagList[-1], text) + return tag + + def appendTagRoute(self, tagRoute, value=None): + if not self._domObj: + return False + if not tagRoute: + return False + + parentTagE = self._domObj + + tagNameList = tagRoute.split(".") + newTagRoute = tagNameList.pop(-1) + + for i in range(len(tagNameList), 0, -1): + tagE = self.getElementsByTagRoute(".".join(tagNameList[:i])) + if tagE: + parentTagE = tagE[0] + break + newTagRoute = tagNameList[i-1] + "." + newTagRoute + + newTagE = self.createTagRoute(newTagRoute, value) + if not newTagE: + return False + try: + parentTagE.appendChild(newTagE) + except xml.dom.HierarchyRequestErr, e: + Utils.log("error occured. %s" + str(e)) + return False + return True + + def setTextByTagRoute(self, tagRoute, tagValue): + if not self._domObj: + return None + + if not tagRoute: + return None + + tagE = self.getElementsByTagRoute(tagRoute) + if not tagE: + return False + + parentTagE = self.getElementsByTagRoute(".".join(tagRoute.split(".")[:-1])) + if not parentTagE: + return False + + parentTagE[0].childNodes.remove(tagE[0]) + parentTagE[0].appendChild(self.createTag(tagRoute.split(".")[-1], tagValue)) + return True + + def getElementsByTagRoute(self, tagRoute): + if not self._domObj: + return None + + if not tagRoute: + return None + + x = None + for tag in tagRoute.split("."): + if x is None: + x = self._domObj.getElementsByTagName(tag) + continue + if x == []: + break + x = x[0].getElementsByTagName(tag) + return x + + def getTextByTagRoute(self, tagRoute): + if not self._domObj: + return None + + x = self.getElementsByTagRoute(tagRoute) + if x: + return self.getText(x[0].childNodes) + return None + + def getElementsByTagName(self, name): + if not self._domObj: + return None + return self._domObj.getElementsByTagName(name) + + def writexml(self, fileName, indent="", addindent="", newl=""): + if not self._domObj: + return None + try: + fp = open(fileName, "w") + self._domObj.writexml(fp, indent, addindent, newl) + fp.close() + return True + except IOError: + return False + + def toString(self, indent=" ", newl="\n", encoding = None): + if not self._domObj: + return None + return self._domObj.toprettyxml(indent, newl, encoding) + + def toxml(self, encoding = None): + if not self._domObj: + return None + return self._domObj.toxml(encoding) + + def toprettyxml(self, indent=" ", newl="\n", encoding = None): + return self.toString(indent, newl, encoding) + + def createResponseTag(self): + responseTag = self._domObj.createElement("response") + return responseTag +##--end of XDOM + +class RequestXml(XDOM): + def __init__(self, requestString, type=None): + if None == requestString: + XDOM.__init__(self) + return + try: + if None == type: + if os.path.isfile(requestString): + self._domObj = MDOM.parse(requestString) + else: + self._domObj = MDOM.parseString(requestString) + elif XML_FILE == type: + self._domObj = MDOM.parse(requestString) + elif XML_STRING == type: + self._domObj = MDOM.parseString(requestString) + except IOError: + XDOM.__init__(self) + except xml.parsers.expat.ExpatError: + XDOM.__init__(self) + +##--end of RequestXML + + +class ResponseXml(XDOM): + _responseTag = None + def __init__(self): + XDOM.__init__(self) + self._responseTag = self.createResponseTag() + self._domObj.appendChild(self._responseTag) + + @classmethod + def errorResponse(self, message): + if not self.responseTag: + return False + self.appendTagRoute("status.code", "-1"); + self.appendTagRoute("status.message", message) + + def append(self, tagName, tagValue=None): + if not self._responseTag: + return False + tag = self.createTag(tagName, tagValue) + if tag: + self._responseTag.appendChild(tag) + return True + return False + + def appendTag(self, tag): + if not tag: + return False + if not self._responseTag: + return False + self._responseTag.appendChild(tag) + return True + + def appendTagRoute(self, tagRoute, value=None): + if not self._responseTag: + return None + if not tagRoute: + return None + + parentTagE = self._responseTag + + tagNameList = tagRoute.split(".") + newTagRoute = tagNameList.pop(-1) + + for i in range(len(tagNameList), 0, -1): + tagE = self.getElementsByTagRoute(".".join(["response"] + tagNameList[:i])) + if tagE: + parentTagE = tagE[0] + break + newTagRoute = tagNameList[i-1] + "." + newTagRoute + + newTagE = self.createTagRoute(newTagRoute, value) + if not newTagE: + return None + try: + parentTagE.appendChild(newTagE) + except xml.dom.HierarchyRequestErr, e: + Utils.log("error occured. %s" + str(e)) + return None + return newTagE + + def appendTagRouteOld(self, tagRoute, value=None): + if not self._responseTag: + return False + if not tagRoute: + return False + + parentTagE = self._responseTag + + tagNameList = tagRoute.split(".") + newTagRoute = tagNameList.pop(-1) + + for i in range(len(tagNameList), 0, -1): + tagE = self.getElementsByTagRoute(".".join(["response"] + tagNameList[:i])) + if tagE: + parentTagE = tagE[0] + break + newTagRoute = tagNameList[i-1] + "." + newTagRoute + + newTagE = self.createTagRoute(newTagRoute, value) + if not newTagE: + return False + try: + parentTagE.appendChild(newTagE) + except xml.dom.HierarchyRequestErr, e: + Utils.log("error occured. %s" + str(e)) + return False + return True +##--end of ResponseXml + +def test(): + rs = ResponseXml() + rs.appendTagRoute("status.code", "0"); + rs.appendTagRoute("status.message", "SUCCESS") + serverTag = rs.appendTagRoute("server.name", "Server1") + networkInterfaces = rs.appendTagRoute("server.networkInterfaces", None) + networkTag = rs.createTag("networkInterface", None) + networkTag.appendChild(rs.createTag("name", "interface1")) + networkTag.appendChild(rs.createTag("ipaddress", "192.168.1.40")) + networkInterfaces.appendChild(networkTag) + networkTag = rs.createTag("networkInterface", None) + networkTag.appendChild(rs.createTag("name", "interface2")) + networkTag.appendChild(rs.createTag("ipaddress", "192.168.1.41")) + networkInterfaces.appendChild(networkTag) + print rs.toprettyxml() + +#test() -- cgit From a3d8ec755741893f2e2dfc6b348ead9ad2fc7ba2 Mon Sep 17 00:00:00 2001 From: Shireesh Anjal Date: Fri, 10 Jun 2011 21:05:44 +0530 Subject: Introduced select all/none links in disks, server disks, volumes and bricks views. --- .../gui/views/pages/AbstractBricksPage.java | 156 --------------------- .../gui/views/pages/AbstractDisksPage.java | 133 ++++-------------- .../gui/views/pages/AbstractTableViewerPage.java | 3 +- .../management/gui/views/pages/BricksPage.java | 62 ++++---- .../management/gui/views/pages/DisksPage.java | 20 ++- .../gui/views/pages/ServerDisksPage.java | 20 ++- .../management/gui/views/pages/VolumesPage.java | 133 +++++------------- 7 files changed, 107 insertions(+), 420 deletions(-) delete mode 100644 src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractBricksPage.java (limited to 'src') diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractBricksPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractBricksPage.java deleted file mode 100644 index baa6cbe9..00000000 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractBricksPage.java +++ /dev/null @@ -1,156 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * This file is part of Gluster Management Console. - * - * Gluster Management Console is free software; you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Gluster Management Console 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 Affero General Public License - * for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see - * . - *******************************************************************************/ -package com.gluster.storage.management.gui.views.pages; - -import java.util.List; - -import org.eclipse.jface.viewers.ArrayContentProvider; -import org.eclipse.jface.viewers.CheckboxTableViewer; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.custom.TableEditor; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.events.PaintEvent; -import org.eclipse.swt.events.PaintListener; -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.Display; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableItem; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.IWorkbenchSite; -import org.eclipse.ui.forms.events.HyperlinkAdapter; -import org.eclipse.ui.forms.events.HyperlinkEvent; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.ImageHyperlink; - -import com.gluster.storage.management.core.model.Brick; -import com.gluster.storage.management.core.model.Disk; -import com.gluster.storage.management.core.model.Disk.DISK_STATUS; -import com.gluster.storage.management.core.model.Entity; -import com.gluster.storage.management.gui.Application; -import com.gluster.storage.management.gui.IEntityListener; -import com.gluster.storage.management.gui.jobs.InitializeDiskJob; -import com.gluster.storage.management.gui.utils.GUIHelper; - -public abstract class AbstractBricksPage extends Composite implements IEntityListener { - protected final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); - protected CheckboxTableViewer tableViewer; - private IWorkbenchSite site; - protected static final GUIHelper guiHelper = GUIHelper.getInstance(); - - /** - * Setup properties of the table e.g. column headers, widths, etc. - * - * @param parent - * The parent composite. (TableColumnLayout has to be set on this) - * @param table - * The table to be set up - */ - protected abstract void setupDiskTable(Composite parent, Table table); - - /** - * @return The label provider to be used with the disk table viewer - */ - protected abstract ITableLabelProvider getTableLabelProvider(); - - /** - * @return Index of the "status" column in the table. Return -1 if status column is not displayed - */ - protected abstract int getStatusColumnIndex(); - - private void init(final Composite parent, IWorkbenchSite site, List bricks) { - addDisposeListener(new DisposeListener() { - public void widgetDisposed(DisposeEvent e) { - toolkit.dispose(); - } - }); - - this.site = site; - - setupPageLayout(); - Text filterText = guiHelper.createFilterText(toolkit, this); - setupBrickTableViewer(createTableViewerComposite(), filterText); - site.setSelectionProvider(tableViewer); - - tableViewer.setInput(bricks); - - site.setSelectionProvider(tableViewer); - Application.getApplication().addEntityListener(this); - - parent.layout(); // Important - this actually paints the table - - toolkit.adapt(this); - toolkit.paintBordersFor(this); - - /** - * Ideally not required. However the table viewer is not getting laid out properly on performing - * "maximize + restore" So this is a hack to make sure that the table is laid out again on re-size of the window - */ - addPaintListener(new PaintListener() { - @Override - public void paintControl(PaintEvent e) { - parent.layout(); - } - }); - } - - public AbstractBricksPage(final Composite parent, int style, IWorkbenchSite site, List bricks) { - super(parent, style); - init(parent, site, bricks); - } - - private void setupPageLayout() { - final GridLayout layout = new GridLayout(1, false); - layout.verticalSpacing = 10; - layout.marginTop = 10; - setLayout(layout); - } - - private Composite createTableViewerComposite() { - Composite tableViewerComposite = new Composite(this, SWT.NO); - tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); - tableViewerComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - return tableViewerComposite; - } - - private CheckboxTableViewer createBrickTableViewer(Composite parent) { - tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI ); - - tableViewer.setLabelProvider(getTableLabelProvider()); - tableViewer.setContentProvider(new ArrayContentProvider()); - - setupDiskTable(parent, tableViewer.getTable()); - - // make sure that table selection is driven by checkbox selection - guiHelper.configureCheckboxTableViewer(tableViewer); - - return tableViewer; - } - - private void setupBrickTableViewer(Composite parent, final Text filterText) { - tableViewer = createBrickTableViewer(parent); - // Create a case insensitive filter for the table viewer using the filter text field - guiHelper.createFilter(tableViewer, filterText, false); - } -} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractDisksPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractDisksPage.java index 55283c7a..133aed38 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractDisksPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractDisksPage.java @@ -21,8 +21,7 @@ package com.gluster.storage.management.gui.views.pages; import java.util.List; import org.eclipse.jface.viewers.ArrayContentProvider; -import org.eclipse.jface.viewers.CheckboxTableViewer; -import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.IContentProvider; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.TableEditor; @@ -30,102 +29,55 @@ import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; -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.Display; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableItem; -import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IWorkbenchSite; import org.eclipse.ui.forms.events.HyperlinkAdapter; import org.eclipse.ui.forms.events.HyperlinkEvent; -import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.ImageHyperlink; +import com.gluster.storage.management.core.model.ClusterListener; +import com.gluster.storage.management.core.model.DefaultClusterListener; import com.gluster.storage.management.core.model.Disk; import com.gluster.storage.management.core.model.Disk.DISK_STATUS; import com.gluster.storage.management.core.model.Entity; import com.gluster.storage.management.gui.Application; import com.gluster.storage.management.gui.IEntityListener; import com.gluster.storage.management.gui.jobs.InitializeDiskJob; -import com.gluster.storage.management.gui.utils.GUIHelper; - -public abstract class AbstractDisksPage extends Composite implements IEntityListener { - protected final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); - protected CheckboxTableViewer tableViewer; - private IWorkbenchSite site; - protected static final GUIHelper guiHelper = GUIHelper.getInstance(); - - /** - * Setup properties of the table e.g. column headers, widths, etc. - * - * @param parent - * The parent composite. (TableColumnLayout has to be set on this) - * @param table - * The table to be set up - */ - protected abstract void setupDiskTable(Composite parent, Table table); - - /** - * @return The label provider to be used with the disk table viewer - */ - protected abstract ITableLabelProvider getTableLabelProvider(); +public abstract class AbstractDisksPage extends AbstractTableViewerPage implements IEntityListener { + private List disks; + /** * @return Index of the "status" column in the table. Return -1 if status column is not displayed */ protected abstract int getStatusColumnIndex(); - private void init(final Composite parent, IWorkbenchSite site, List disks) { - addDisposeListener(new DisposeListener() { - public void widgetDisposed(DisposeEvent e) { - toolkit.dispose(); - } - }); - - this.site = site; - - setupPageLayout(); - Text filterText = guiHelper.createFilterText(toolkit, this); - setupDiskTableViewer(createTableViewerComposite(), filterText); - site.setSelectionProvider(tableViewer); - - tableViewer.setInput(disks); - setupStatusCellEditor(); // creates hyperlinks for "unitialized" disks - - site.setSelectionProvider(tableViewer); + public AbstractDisksPage(final Composite parent, int style, IWorkbenchSite site, List disks) { + super(site, parent, style, disks); + this.disks = disks; + + // creates hyperlinks for "unitialized" disks + setupStatusCellEditor(); + // Listen for disk status change events Application.getApplication().addEntityListener(this); - - parent.layout(); // Important - this actually paints the table - - toolkit.adapt(this); - toolkit.paintBordersFor(this); - - /** - * Ideally not required. However the table viewer is not getting laid out properly on performing - * "maximize + restore" So this is a hack to make sure that the table is laid out again on re-size of the window - */ - addPaintListener(new PaintListener() { - - @Override - public void paintControl(PaintEvent e) { - parent.layout(); - } - }); } - - public AbstractDisksPage(final Composite parent, int style, IWorkbenchSite site, List disks) { - super(parent, style); - init(parent, site, disks); + + @Override + protected IContentProvider getContentProvider() { + return new ArrayContentProvider(); } - - private void setupPageLayout() { - final GridLayout layout = new GridLayout(1, false); - layout.verticalSpacing = 10; - layout.marginTop = 10; - setLayout(layout); + + @Override + protected List getAllEntities() { + return disks; + } + + @Override + protected ClusterListener createClusterListener() { + return new DefaultClusterListener(); } private void createInitializeLink(final TableItem item, final int rowNum, final Disk disk) { @@ -151,7 +103,7 @@ public abstract class AbstractDisksPage extends Composite implements IEntityList myLink = toolkit.createImageHyperlink(table, SWT.NONE); // link.setImage(guiHelper.getImage(IImageKeys.DISK_UNINITIALIZED)); myLink.setText("Initialize"); - myLink.addHyperlinkListener(new StatusLinkListener(myLink, myEditor, myItem, tableViewer, disk1, site)); + myLink.addHyperlinkListener(new StatusLinkListener(myLink, myEditor, myItem, tableViewer, disk1)); myEditor.setEditor(myLink, item1, getStatusColumnIndex()); @@ -220,47 +172,18 @@ public abstract class AbstractDisksPage extends Composite implements IEntityList } } - private Composite createTableViewerComposite() { - Composite tableViewerComposite = new Composite(this, SWT.NO); - tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); - tableViewerComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - return tableViewerComposite; - } - - private CheckboxTableViewer createDiskTableViewer(Composite parent) { - tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI ); - - tableViewer.setLabelProvider(getTableLabelProvider()); - tableViewer.setContentProvider(new ArrayContentProvider()); - - setupDiskTable(parent, tableViewer.getTable()); - - // make sure that table selection is driven by checkbox selection - guiHelper.configureCheckboxTableViewer(tableViewer); - - return tableViewer; - } - - private void setupDiskTableViewer(Composite parent, final Text filterText) { - tableViewer = createDiskTableViewer(parent); - // Create a case insensitive filter for the table viewer using the filter text field - guiHelper.createFilter(tableViewer, filterText, false); - } - private final class StatusLinkListener extends HyperlinkAdapter { private final Disk disk; private final TableEditor myEditor; private final ImageHyperlink myLink; private final TableViewer viewer; - private final IWorkbenchSite site; private StatusLinkListener(ImageHyperlink link, TableEditor editor, TableItem item, TableViewer viewer, - Disk disk, IWorkbenchSite site) { + Disk disk) { this.disk = disk; this.viewer = viewer; this.myEditor = editor; this.myLink = link; - this.site = site; } private void updateStatus(final DISK_STATUS status, final boolean disposeEditor) { diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableViewerPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableViewerPage.java index a8a98bbd..b64e80d2 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableViewerPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableViewerPage.java @@ -52,8 +52,9 @@ public abstract class AbstractTableViewerPage extends Composite { protected final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); protected CheckboxTableViewer tableViewer; protected GUIHelper guiHelper = GUIHelper.getInstance(); - private Hyperlink linkAll, linkNone; protected Composite parent; + + private Hyperlink linkAll, linkNone; public AbstractTableViewerPage(IWorkbenchSite site, final Composite parent, int style, Object model) { super(parent, style); diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/BricksPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/BricksPage.java index a6bc6f94..b83914eb 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/BricksPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/BricksPage.java @@ -20,27 +20,24 @@ package com.gluster.storage.management.gui.views.pages; import java.util.List; -import org.eclipse.jface.layout.TableColumnLayout; +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.IContentProvider; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.swt.SWT; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Table; import org.eclipse.ui.IWorkbenchSite; -import com.gluster.storage.management.client.GlusterDataModelManager; import com.gluster.storage.management.core.model.Brick; import com.gluster.storage.management.core.model.ClusterListener; import com.gluster.storage.management.core.model.DefaultClusterListener; -import com.gluster.storage.management.core.model.Entity; import com.gluster.storage.management.core.model.Event; -import com.gluster.storage.management.core.model.Volume; import com.gluster.storage.management.core.model.Event.EVENT_TYPE; +import com.gluster.storage.management.core.model.Volume; import com.gluster.storage.management.gui.BrickTableLabelProvider; -public class BricksPage extends AbstractBricksPage { - private Composite parent; +public class BricksPage extends AbstractTableViewerPage { + private List bricks; public enum BRICK_TABLE_COLUMN_INDICES { SERVER, BRICK, FREE_SPACE, TOTAL_SPACE, STATUS @@ -49,13 +46,14 @@ public class BricksPage extends AbstractBricksPage { private static final String[] DISK_TABLE_COLUMN_NAMES = new String[] { "Server", "Brick Directory", "Free Space (GB)", "Total Space (GB)", "Status" }; - public BricksPage(final Composite parent, int style, IWorkbenchSite site, final List bricks) { - super(parent, style, site, bricks); - createListeners(); + public BricksPage(Composite parent, int style, IWorkbenchSite site, final List bricks) { + super(site, parent, style, bricks); + this.bricks = bricks; } - private void createListeners() { - final ClusterListener clusterListener = new DefaultClusterListener() { + @Override + protected ClusterListener createClusterListener() { + return new DefaultClusterListener() { @Override public void volumeChanged(Volume volume, Event event) { if (event.getEventType() == EVENT_TYPE.BRICKS_ADDED || event.getEventType() == EVENT_TYPE.BRICKS_REMOVED) { @@ -65,43 +63,33 @@ public class BricksPage extends AbstractBricksPage { } }; - GlusterDataModelManager.getInstance().addClusterListener(clusterListener); - addDisposeListener(new DisposeListener() { - - @Override - public void widgetDisposed(DisposeEvent e) { - GlusterDataModelManager.getInstance().removeClusterListener(clusterListener); - } - }); } @Override - protected void setupDiskTable(Composite parent, Table table) { - this.parent = parent; - table.setHeaderVisible(true); - table.setLinesVisible(false); - - TableColumnLayout tableColumnLayout = guiHelper.createTableColumnLayout(table, DISK_TABLE_COLUMN_NAMES); - parent.setLayout(tableColumnLayout); - + protected String[] getColumnNames() { + return DISK_TABLE_COLUMN_NAMES; + } + + @Override + protected void setColumnProperties(Table table) { guiHelper.setColumnProperties(table, BRICK_TABLE_COLUMN_INDICES.SERVER.ordinal(), SWT.CENTER, 100); guiHelper.setColumnProperties(table, BRICK_TABLE_COLUMN_INDICES.BRICK.ordinal(), SWT.CENTER, 100); guiHelper.setColumnProperties(table, BRICK_TABLE_COLUMN_INDICES.FREE_SPACE.ordinal(), SWT.CENTER, 90); guiHelper.setColumnProperties(table, BRICK_TABLE_COLUMN_INDICES.TOTAL_SPACE.ordinal(), SWT.CENTER, 90); - } - + @Override - protected ITableLabelProvider getTableLabelProvider() { + protected ITableLabelProvider getLabelProvider() { return new BrickTableLabelProvider(); } - + @Override - protected int getStatusColumnIndex() { - return BRICK_TABLE_COLUMN_INDICES.STATUS.ordinal(); + protected IContentProvider getContentProvider() { + return new ArrayContentProvider(); } - + @Override - public void entityChanged(Entity entity, String[] paremeters) { + protected List getAllEntities() { + return bricks; } } \ No newline at end of file diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/DisksPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/DisksPage.java index 1df74481..bd14607e 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/DisksPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/DisksPage.java @@ -20,8 +20,7 @@ package com.gluster.storage.management.gui.views.pages; import java.util.List; -import org.eclipse.jface.layout.TableColumnLayout; -import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.IBaseLabelProvider; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Table; @@ -44,25 +43,24 @@ public class DisksPage extends AbstractDisksPage { } @Override - protected void setupDiskTable(Composite parent, Table table) { - table.setHeaderVisible(true); - table.setLinesVisible(false); - - TableColumnLayout tableColumnLayout = guiHelper.createTableColumnLayout(table, DISK_TABLE_COLUMN_NAMES); - parent.setLayout(tableColumnLayout); + protected String[] getColumnNames() { + return DISK_TABLE_COLUMN_NAMES; + } + @Override + protected void setColumnProperties(Table table) { guiHelper.setColumnProperties(table, DISK_TABLE_COLUMN_INDICES.SERVER.ordinal(), SWT.CENTER, 100); guiHelper.setColumnProperties(table, DISK_TABLE_COLUMN_INDICES.DISK.ordinal(), SWT.CENTER, 100); guiHelper.setColumnProperties(table, DISK_TABLE_COLUMN_INDICES.FREE_SPACE.ordinal(), SWT.CENTER, 90); guiHelper.setColumnProperties(table, DISK_TABLE_COLUMN_INDICES.TOTAL_SPACE.ordinal(), SWT.CENTER, 90); // guiHelper.setColumnProperties(table, DISK_TABLE_COLUMN_INDICES.SPACE_IN_USE.ordinal(), SWT.CENTER, 90); } - + @Override - protected ITableLabelProvider getTableLabelProvider() { + protected IBaseLabelProvider getLabelProvider() { return new DiskTableLabelProvider(); } - + @Override protected int getStatusColumnIndex() { return DISK_TABLE_COLUMN_INDICES.STATUS.ordinal(); diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServerDisksPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServerDisksPage.java index 3621afe1..c2f76a43 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServerDisksPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/ServerDisksPage.java @@ -20,7 +20,7 @@ package com.gluster.storage.management.gui.views.pages; import java.util.List; -import org.eclipse.jface.layout.TableColumnLayout; +import org.eclipse.jface.viewers.IBaseLabelProvider; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Table; @@ -28,7 +28,6 @@ import org.eclipse.ui.IWorkbenchSite; import com.gluster.storage.management.core.model.Disk; import com.gluster.storage.management.gui.ServerDiskTableLabelProvider; -import com.gluster.storage.management.gui.TableLabelProviderAdapter; public class ServerDisksPage extends AbstractDisksPage { public ServerDisksPage(Composite parent, int style, IWorkbenchSite site, List disks) { @@ -43,26 +42,25 @@ public class ServerDisksPage extends AbstractDisksPage { "Space in Use (GB)", "Status" }; @Override - protected void setupDiskTable(Composite parent, Table table) { - table.setHeaderVisible(true); - table.setLinesVisible(false); - - TableColumnLayout tableColumnLayout = guiHelper.createTableColumnLayout(table, SERVER_DISK_TABLE_COLUMN_NAMES); - parent.setLayout(tableColumnLayout); - + protected String[] getColumnNames() { + return SERVER_DISK_TABLE_COLUMN_NAMES; + } + + @Override + protected void setColumnProperties(Table table) { guiHelper.setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.DISK.ordinal(), SWT.CENTER, 100); guiHelper.setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.SPACE.ordinal(), SWT.CENTER, 90); guiHelper.setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.SPACE_IN_USE.ordinal(), SWT.CENTER, 90); guiHelper.setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.STATUS.ordinal(), SWT.LEFT, 90); } - + @Override protected int getStatusColumnIndex() { return SERVER_DISK_TABLE_COLUMN_INDICES.STATUS.ordinal(); } @Override - protected TableLabelProviderAdapter getTableLabelProvider() { + protected IBaseLabelProvider getLabelProvider() { return new ServerDiskTableLabelProvider(); } } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumesPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumesPage.java index 38fa2d41..d0824888 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumesPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/VolumesPage.java @@ -18,39 +18,28 @@ *******************************************************************************/ package com.gluster.storage.management.gui.views.pages; +import java.util.List; + import org.eclipse.jface.layout.TableColumnLayout; -import org.eclipse.jface.viewers.CheckboxTableViewer; import org.eclipse.jface.viewers.ColumnWeightData; -import org.eclipse.jface.viewers.IDoubleClickListener; -import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.IBaseLabelProvider; +import org.eclipse.jface.viewers.IContentProvider; import org.eclipse.swt.SWT; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.events.PaintEvent; -import org.eclipse.swt.events.PaintListener; -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.Display; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IWorkbenchSite; -import org.eclipse.ui.forms.widgets.FormToolkit; +import com.gluster.storage.management.core.model.ClusterListener; +import com.gluster.storage.management.core.model.DefaultClusterListener; import com.gluster.storage.management.core.model.EntityGroup; import com.gluster.storage.management.core.model.Volume; import com.gluster.storage.management.gui.EntityGroupContentProvider; import com.gluster.storage.management.gui.VolumeTableLabelProvider; -import com.gluster.storage.management.gui.utils.GUIHelper; - -public class VolumesPage extends Composite { - - private final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); - private TableViewer tableViewer; - private GUIHelper guiHelper = GUIHelper.getInstance(); +public class VolumesPage extends AbstractTableViewerPage { + private List volumes; + public enum VOLUME_TABLE_COLUMN_INDICES { NAME, VOLUME_TYPE, NUM_OF_DISKS, TRANSPORT_TYPE, VOLUME_STATUS }; @@ -59,91 +48,37 @@ public class VolumesPage extends Composite { "Number of\nBricks", "Transport Type", "Status" }; public VolumesPage(final Composite parent, IWorkbenchSite site, EntityGroup volumes) { - super(parent, SWT.NONE); - - addDisposeListener(new DisposeListener() { - public void widgetDisposed(DisposeEvent e) { - toolkit.dispose(); - } - }); - - toolkit.adapt(this); - toolkit.paintBordersFor(this); - - setupPageLayout(); - setupVolumeTableViewer(site, volumes); - - parent.layout(); // Important - this actually paints the table - - /** - * Ideally not required. However the table viewer is not getting laid out properly on performing - * "maximize + restore" So this is a hack to make sure that the table is laid out again on re-size of the window - */ - addPaintListener(new PaintListener() { - - @Override - public void paintControl(PaintEvent e) { - parent.layout(); - } - }); + super(site, parent, SWT.NONE, volumes); } - public void addDoubleClickListener(IDoubleClickListener listener) { - tableViewer.addDoubleClickListener(listener); + @Override + protected String[] getColumnNames() { + return VOLUME_TABLE_COLUMN_NAMES; } - - private void setupPageLayout() { - final GridLayout layout = new GridLayout(1, false); - layout.verticalSpacing = 10; - layout.marginTop = 10; - setLayout(layout); - } - - private void setupVolumeTable(Composite parent, Table table) { - table.setHeaderVisible(true); - table.setLinesVisible(true); - - TableColumnLayout columnLayout = guiHelper.createTableColumnLayout(table, VOLUME_TABLE_COLUMN_NAMES); - parent.setLayout(columnLayout); - + + @Override + protected void setColumnProperties(Table table) { setColumnProperties(table, VOLUME_TABLE_COLUMN_INDICES.VOLUME_STATUS, SWT.CENTER, 50); setColumnProperties(table, VOLUME_TABLE_COLUMN_INDICES.NUM_OF_DISKS, SWT.CENTER, 50); setColumnProperties(table, VOLUME_TABLE_COLUMN_INDICES.TRANSPORT_TYPE, SWT.CENTER, 70); } - - private CheckboxTableViewer createVolumeTableViewer(Composite parent) { - CheckboxTableViewer tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.FLAT | SWT.FULL_SELECTION - | SWT.MULTI); - tableViewer.setLabelProvider(new VolumeTableLabelProvider()); - tableViewer.setContentProvider(new EntityGroupContentProvider()); - - setupVolumeTable(parent, tableViewer.getTable()); - - // make sure that table selection is driven by checkbox selection - guiHelper.configureCheckboxTableViewer(tableViewer); - - return tableViewer; + + @Override + protected IBaseLabelProvider getLabelProvider() { + return new VolumeTableLabelProvider(); } - - private Composite createTableViewerComposite() { - Composite tableViewerComposite = new Composite(this, SWT.NO); - tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); - tableViewerComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - return tableViewerComposite; + + @Override + protected IContentProvider getContentProvider() { + return new EntityGroupContentProvider(); } - - private void setupVolumeTableViewer(IWorkbenchSite site, EntityGroup volumes) { - Text filterText = guiHelper.createFilterText(toolkit, this); - - Composite tableViewerComposite = createTableViewerComposite(); - tableViewer = createVolumeTableViewer(tableViewerComposite); - site.setSelectionProvider(tableViewer); - - // Create a case insensitive filter for the table viewer using the filter text field - guiHelper.createFilter(tableViewer, filterText, false); - tableViewer.setInput(volumes); + + @Override + protected ClusterListener createClusterListener() { + // TODO: Override methods to handle volume related events + return new DefaultClusterListener(); } - + /** * Sets properties for alignment and weight of given column of given table * @@ -159,9 +94,9 @@ public class VolumesPage extends Composite { TableColumnLayout tableColumnLayout = (TableColumnLayout) table.getParent().getLayout(); tableColumnLayout.setColumnData(column, new ColumnWeightData(weight)); } - - public void setInput(EntityGroup volumes) { - tableViewer.setInput(volumes); - tableViewer.refresh(); + + @Override + protected List getAllEntities() { + return volumes; } } -- cgit From 971d745f48cdddbba3c3c1d18fc7338cf2cb7abf Mon Sep 17 00:00:00 2001 From: Shireesh Anjal Date: Fri, 10 Jun 2011 21:16:01 +0530 Subject: Introduced property to avoid bundling of sources with the exported plugins --- .../glustermc_build.properties | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/com.gluster.storage.management.releng/glustermc_build.properties b/src/com.gluster.storage.management.releng/glustermc_build.properties index b808ec9d..d50782d8 100644 --- a/src/com.gluster.storage.management.releng/glustermc_build.properties +++ b/src/com.gluster.storage.management.releng/glustermc_build.properties @@ -1,10 +1,14 @@ +# Buckminster build properties file for Gluster Management Console + # Where all the output should go -buckminster.output.root=/tmp/buckminster/glustermc +#buckminster.output.root=/tmp/buckminster/glustermc # Where the temp files should go -buckminster.temp.root=/tmp/buckminster +#buckminster.temp.root=/tmp/buckminster # How .qualifier in versions should be replaced qualifier.replacement.*=generator:lastRevision -target.os=linux -target.ws=gtk -target.arch=x86_64 +# Do not include source +cbi.include.source=false + +# Sets the Java compiler compliance level +org.eclipse.buckminster.core.jdt.compliancelevel=1.6 -- cgit From 496113c0d88dba8896fe137d5e05fca359cc61f3 Mon Sep 17 00:00:00 2001 From: Shireesh Anjal Date: Mon, 13 Jun 2011 15:47:33 +0530 Subject: Modified the download volume logs action to make it work even when the current focus is not on the volume node in navigation tree. --- .../storage/management/gui/actions/DownloadVolumeLogsAction.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/DownloadVolumeLogsAction.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/DownloadVolumeLogsAction.java index d7a63323..8de8aa2d 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/DownloadVolumeLogsAction.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/actions/DownloadVolumeLogsAction.java @@ -26,22 +26,21 @@ import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.FileDialog; -import com.gluster.storage.management.client.GlusterDataModelManager; import com.gluster.storage.management.client.VolumesClient; import com.gluster.storage.management.core.model.Volume; +import com.gluster.storage.management.gui.utils.GUIHelper; /** * */ public class DownloadVolumeLogsAction extends AbstractActionDelegate { + private GUIHelper guiHelper = GUIHelper.getInstance(); /* (non-Javadoc) * @see org.eclipse.ui.IWorkbenchWindowActionDelegate#dispose() */ @Override public void dispose() { - // TODO Auto-generated method stub - } /* (non-Javadoc) @@ -49,13 +48,14 @@ public class DownloadVolumeLogsAction extends AbstractActionDelegate { */ @Override protected void performAction(IAction action) { - final Volume volume = (Volume)selectedEntity; final VolumesClient client = new VolumesClient(); final Runnable downloadLogsThread = new Runnable() { @Override public void run() { + Volume volume = guiHelper.getSelectedEntity(getWindow(), Volume.class); + FileDialog dialog = new FileDialog(getShell(), SWT.SAVE); dialog.setFilterNames(new String[] {"GZipped Tar (*.tar.gz)"}); dialog.setFilterExtensions(new String[] {"*.tar.gz"}); -- cgit From db8e279f603d2e5e3541feec72466adf5b60f7bd Mon Sep 17 00:00:00 2001 From: Dhandapani Date: Mon, 13 Jun 2011 16:11:59 +0530 Subject: Bug 3018 - Adding spare bricks to a volume is not getting reflected immediately --- .../storage/management/gui/views/pages/AbstractTableViewerPage.java | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableViewerPage.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableViewerPage.java index b64e80d2..dfa06f85 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableViewerPage.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/pages/AbstractTableViewerPage.java @@ -176,6 +176,7 @@ public abstract class AbstractTableViewerPage extends Composite { layoutData.grabExcessHorizontalSpace = true; layoutData.horizontalAlignment = SWT.FILL; layoutData.verticalAlignment = SWT.FILL; + layoutData.grabExcessVerticalSpace = true; tableViewerComposite.setLayoutData(layoutData); return tableViewerComposite; -- cgit From 7635325e900e4f2198d72a4673c364bf06077e8c Mon Sep 17 00:00:00 2001 From: Shireesh Anjal Date: Mon, 13 Jun 2011 16:37:54 +0530 Subject: [Bug 3015] New: Not able to detach or attach the servers from servers list --- .../storage/management/gui/preferences/PreferenceConstants.java | 4 +--- .../src/com/gluster/storage/management/gui/views/NavigationView.java | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/preferences/PreferenceConstants.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/preferences/PreferenceConstants.java index 4c1bfcd5..a8826772 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/preferences/PreferenceConstants.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/preferences/PreferenceConstants.java @@ -23,12 +23,10 @@ package com.gluster.storage.management.gui.preferences; */ public class PreferenceConstants { + // TODO: Remove after proper preferences are added public static final String P_PATH = "pathPreference"; - public static final String P_BOOLEAN = "booleanPreference"; - public static final String P_CHOICE = "choicePreference"; - public static final String P_STRING = "stringPreference"; } diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/NavigationView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/NavigationView.java index f737ea9d..458dcf61 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/NavigationView.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/NavigationView.java @@ -60,7 +60,7 @@ public class NavigationView extends ViewPart implements ISelectionListener { viewsManager = new GlusterViewsManager(getSite().getPage()); // listen to selection events to update views/toolbar accordingly - getSite().getPage().addPostSelectionListener(this); + getSite().getPage().addSelectionListener(this); } private void createNavigationTree(Composite parent) { -- cgit