blob: e4c5cff25b737051cc1274ea5dafce339b3455b4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.chemistry.opencmis.workbench;
import static org.apache.chemistry.opencmis.commons.impl.CollectionsHelper.isNotEmpty;
import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JToolBar;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeSelectionModel;
import org.apache.chemistry.opencmis.client.api.ObjectType;
import org.apache.chemistry.opencmis.client.api.Tree;
import org.apache.chemistry.opencmis.client.util.TypeUtils;
import org.apache.chemistry.opencmis.client.util.TypeUtils.ValidationError;
import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
import org.apache.chemistry.opencmis.commons.enums.CmisVersion;
import org.apache.chemistry.opencmis.workbench.model.ClientModel;
public class TypesFrame extends JFrame {
private static final long serialVersionUID = 1L;
private static final String WINDOW_TITLE = "CMIS Types";
private static final int BUTTON_SAVE = 0;
private static final int BUTTON_UPDATE = 1;
private static final int BUTTON_DELETE = 2;
private static final int BUTTON_CREATE = 3;
private final ClientModel model;
private RepositoryInfo repInfo;
private ObjectType currentType;
private JToolBar toolBar;
private JButton[] toolbarButton;
private JTree typesTree;
private TypeSplitPane typePanel;
public TypesFrame(ClientModel model) {
super();
this.model = model;
repInfo = model.getRepositoryInfo();
createGUI();
loadData();
}
private void createGUI() {
setTitle(WINDOW_TITLE + " - " + model.getRepositoryName());
ImageIcon icon = ClientHelper.getIcon("icon.png");
if (icon != null) {
setIconImage(icon.getImage());
}
setPreferredSize(new Dimension(1000, 700));
setMinimumSize(new Dimension(200, 60));
setLayout(new BorderLayout());
toolBar = new JToolBar("CMIS Types Toolbar", JToolBar.HORIZONTAL);
toolbarButton = new JButton[4];
JMenuItem menuItem;
// -- save ---
final JPopupMenu savePopup = new JPopupMenu();
menuItem = new JMenuItem("Save Type Definition to XML");
savePopup.add(menuItem);
menuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
JFileChooser fileChooser = createXmlFileChooser();
fileChooser.setSelectedFile(new File(getFilename() + ".xml"));
int chooseResult = fileChooser.showDialog(getRootPane(), "Save XML");
if (chooseResult == JFileChooser.APPROVE_OPTION) {
try {
OutputStream out = new BufferedOutputStream(new FileOutputStream(fileChooser.getSelectedFile()));
TypeUtils.writeToXML(currentType, out);
out.flush();
out.close();
} catch (Exception e) {
ClientHelper.showError(getRootPane(), e);
}
}
}
});
menuItem = new JMenuItem("Save Type Definition to JSON");
savePopup.add(menuItem);
menuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
JFileChooser fileChooser = createJsonFileChooser();
fileChooser.setSelectedFile(new File(getFilename() + ".json"));
int chooseResult = fileChooser.showDialog(getRootPane(), "Save JSON");
if (chooseResult == JFileChooser.APPROVE_OPTION) {
try {
OutputStream out = new BufferedOutputStream(new FileOutputStream(fileChooser.getSelectedFile()));
TypeUtils.writeToJSON(currentType, out);
out.flush();
out.close();
} catch (Exception e) {
ClientHelper.showError(getRootPane(), e);
}
}
}
});
toolbarButton[BUTTON_SAVE] = new JButton("Save Type Definition", ClientHelper.getIcon("savetype.png"));
toolbarButton[BUTTON_SAVE].addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
savePopup.show(toolbarButton[BUTTON_SAVE], 0, toolbarButton[BUTTON_SAVE].getHeight());
}
});
toolBar.add(toolbarButton[BUTTON_SAVE]);
toolBar.addSeparator();
// -- update --
final JPopupMenu updatePopup = new JPopupMenu();
menuItem = new JMenuItem("Load Type Definition from XML");
updatePopup.add(menuItem);
menuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
JFileChooser fileChooser = createXmlFileChooser();
int chooseResult = fileChooser.showDialog(getRootPane(), "Load XML");
if (chooseResult == JFileChooser.APPROVE_OPTION) {
try {
InputStream in = new BufferedInputStream(new FileInputStream(fileChooser.getSelectedFile()),
64 * 1024);
TypeDefinition type = TypeUtils.readFromXML(in);
in.close();
if (checkTypeDefinition(type)) {
model.getClientSession().getSession().updateType(type);
}
loadData();
} catch (Exception e) {
ClientHelper.showError(getRootPane(), e);
}
}
}
});
menuItem = new JMenuItem("Load Type Definition from JSON");
updatePopup.add(menuItem);
menuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
JFileChooser fileChooser = createJsonFileChooser();
int chooseResult = fileChooser.showDialog(getRootPane(), "Load JSON");
if (chooseResult == JFileChooser.APPROVE_OPTION) {
try {
InputStream in = new BufferedInputStream(new FileInputStream(fileChooser.getSelectedFile()),
64 * 1024);
TypeDefinition type = TypeUtils.readFromJSON(in);
in.close();
if (checkTypeDefinition(type)) {
model.getClientSession().getSession().updateType(type);
}
loadData();
} catch (Exception e) {
ClientHelper.showError(getRootPane(), e);
}
}
}
});
toolbarButton[BUTTON_UPDATE] = new JButton("Update Type", ClientHelper.getIcon("updatetype.png"));
toolbarButton[BUTTON_UPDATE].setEnabled(repInfo.getCmisVersion() != CmisVersion.CMIS_1_0);
toolbarButton[BUTTON_UPDATE].addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
updatePopup.show(toolbarButton[BUTTON_UPDATE], 0, toolbarButton[BUTTON_UPDATE].getHeight());
}
});
toolBar.add(toolbarButton[BUTTON_UPDATE]);
// -- delete --
toolbarButton[BUTTON_DELETE] = new JButton("Delete Type", ClientHelper.getIcon("deletetype.png"));
toolbarButton[BUTTON_DELETE].setEnabled(repInfo.getCmisVersion() != CmisVersion.CMIS_1_0);
toolbarButton[BUTTON_DELETE].addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
int answer = JOptionPane.showConfirmDialog(getOwner(), "Do you really want to delete the type "
+ currentType.getId() + "?", "Delete Type", JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE);
if (answer == JOptionPane.YES_OPTION) {
try {
model.getClientSession().getSession().deleteType(currentType.getId());
} catch (Exception e) {
ClientHelper.showError(getRootPane(), e);
}
loadData();
}
}
});
toolBar.add(toolbarButton[BUTTON_DELETE]);
toolBar.addSeparator();
// -- create --
final JPopupMenu createPopup = new JPopupMenu();
menuItem = new JMenuItem("Load Type Definition from XML");
createPopup.add(menuItem);
menuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
JFileChooser fileChooser = createXmlFileChooser();
int chooseResult = fileChooser.showDialog(getRootPane(), "Load XML");
if (chooseResult == JFileChooser.APPROVE_OPTION) {
try {
InputStream in = new BufferedInputStream(new FileInputStream(fileChooser.getSelectedFile()),
64 * 1024);
TypeDefinition type = TypeUtils.readFromXML(in);
in.close();
if (checkTypeDefinition(type)) {
model.getClientSession().getSession().createType(type);
}
loadData();
} catch (Exception e) {
ClientHelper.showError(getRootPane(), e);
}
}
}
});
menuItem = new JMenuItem("Load Type Definition from JSON");
createPopup.add(menuItem);
menuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
JFileChooser fileChooser = createJsonFileChooser();
int chooseResult = fileChooser.showDialog(getRootPane(), "Load JSON");
if (chooseResult == JFileChooser.APPROVE_OPTION) {
try {
InputStream in = new BufferedInputStream(new FileInputStream(fileChooser.getSelectedFile()),
64 * 1024);
TypeDefinition type = TypeUtils.readFromJSON(in);
in.close();
if (checkTypeDefinition(type)) {
model.getClientSession().getSession().createType(type);
}
loadData();
} catch (Exception e) {
ClientHelper.showError(getRootPane(), e);
}
}
}
});
toolbarButton[BUTTON_CREATE] = new JButton("Create Type", ClientHelper.getIcon("newtype.png"));
toolbarButton[BUTTON_CREATE].setEnabled(repInfo.getCmisVersion() != CmisVersion.CMIS_1_0);
toolbarButton[BUTTON_CREATE].addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
createPopup.show(toolbarButton[BUTTON_CREATE], 0, toolbarButton[BUTTON_CREATE].getHeight());
}
});
toolBar.add(toolbarButton[BUTTON_CREATE]);
add(toolBar, BorderLayout.PAGE_START);
typesTree = new JTree();
typesTree.setRootVisible(false);
typesTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
typesTree.addTreeSelectionListener(new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) ((JTree) e.getSource())
.getLastSelectedPathComponent();
if (node == null) {
return;
}
currentType = ((TypeNode) node.getUserObject()).getType();
if (repInfo.getCmisVersion() != CmisVersion.CMIS_1_0) {
toolbarButton[BUTTON_UPDATE].setEnabled(currentType.getTypeMutability() != null
&& Boolean.TRUE.equals(currentType.getTypeMutability().canUpdate()));
toolbarButton[BUTTON_DELETE].setEnabled(currentType.getTypeMutability() != null
&& Boolean.TRUE.equals(currentType.getTypeMutability().canDelete()));
}
typePanel.setType(currentType);
}
});
typePanel = new TypeSplitPane(model);
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new JScrollPane(typesTree), typePanel);
splitPane.setDividerLocation(300);
add(splitPane, BorderLayout.CENTER);
ClientHelper.installEscapeBinding(this, getRootPane(), true);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
private JFileChooser createXmlFileChooser() {
JFileChooser fileChooser = new JFileChooser();
fileChooser.addChoosableFileFilter(new FileFilter() {
@Override
public String getDescription() {
return "XML CMIS Type Definition File";
}
@Override
public boolean accept(File f) {
return f.isDirectory() || f.getName().endsWith(".xml");
}
});
return fileChooser;
}
private JFileChooser createJsonFileChooser() {
JFileChooser fileChooser = new JFileChooser();
fileChooser.addChoosableFileFilter(new FileFilter() {
@Override
public String getDescription() {
return "JSON CMIS Type Definition File";
}
@Override
public boolean accept(File f) {
return f.isDirectory() || f.getName().endsWith(".json");
}
});
return fileChooser;
}
private String getFilename() {
if (currentType != null) {
String filename = currentType.getId();
filename = filename.replace(':', '_');
filename = filename.replace('/', '_');
filename = filename.replace('\\', '_');
return filename;
}
return "type";
}
private boolean checkTypeDefinition(TypeDefinition type) {
StringBuilder sb = new StringBuilder();
List<ValidationError> typeResult = TypeUtils.validateTypeDefinition(type);
if (isNotEmpty(typeResult)) {
sb.append("\nType Definition:\n");
for (ValidationError error : typeResult) {
sb.append("- ");
sb.append(error.toString());
sb.append('\n');
}
}
if (type.getPropertyDefinitions() != null) {
for (PropertyDefinition<?> propDef : type.getPropertyDefinitions().values()) {
List<ValidationError> propResult = TypeUtils.validatePropertyDefinition(propDef);
if (isNotEmpty(propResult)) {
sb.append("\nProperty Definition '" + propDef.getId() + "':\n");
for (ValidationError error : propResult) {
sb.append("- ");
sb.append(error.toString());
sb.append('\n');
}
}
}
}
if (sb.length() == 0) {
return true;
}
int answer = JOptionPane
.showConfirmDialog(this, "The type defintion has the following issues.\n" + sb.toString()
+ "\n\nDo you want to proceed anyway?", "Type Definition Validation",
JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
return answer == JOptionPane.YES_OPTION;
}
private void loadData() {
try {
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode();
List<Tree<ObjectType>> types = model.getTypeDescendants();
for (Tree<ObjectType> tt : types) {
addLevel(rootNode, tt);
}
DefaultTreeModel treeModel = new DefaultTreeModel(rootNode);
typesTree.setModel(treeModel);
typesTree.setSelectionRow(0);
} catch (Exception ex) {
ClientHelper.showError(null, ex);
return;
} finally {
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
private void addLevel(DefaultMutableTreeNode parent, Tree<ObjectType> tree) {
DefaultMutableTreeNode node = new DefaultMutableTreeNode(new TypeNode(tree.getItem()));
parent.add(node);
if (tree.getChildren() != null) {
for (Tree<ObjectType> tt : tree.getChildren()) {
addLevel(node, tt);
}
}
}
static class TypeNode {
private final ObjectType type;
public TypeNode(ObjectType type) {
this.type = type;
}
public ObjectType getType() {
return type;
}
@Override
public String toString() {
return type.getDisplayName() + " (" + type.getId() + ")";
}
}
}