/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.tools.workbench.scplugin.ui.project; import java.io.File; import java.util.Iterator; import java.util.List; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import org.eclipse.persistence.tools.workbench.framework.action.FrameworkAction; import org.eclipse.persistence.tools.workbench.framework.app.AbstractApplicationNode; import org.eclipse.persistence.tools.workbench.framework.app.ApplicationNode; import org.eclipse.persistence.tools.workbench.framework.app.GroupContainerDescription; import org.eclipse.persistence.tools.workbench.framework.app.MenuDescription; import org.eclipse.persistence.tools.workbench.framework.app.MenuGroupDescription; import org.eclipse.persistence.tools.workbench.framework.app.RootMenuDescription; import org.eclipse.persistence.tools.workbench.framework.app.ToolBarButtonGroupDescription; import org.eclipse.persistence.tools.workbench.framework.app.ToolBarDescription; import org.eclipse.persistence.tools.workbench.framework.context.ApplicationContext; import org.eclipse.persistence.tools.workbench.framework.context.WorkbenchContext; import org.eclipse.persistence.tools.workbench.framework.ui.view.AbstractPropertiesPage; import org.eclipse.persistence.tools.workbench.scplugin.SCPlugin; import org.eclipse.persistence.tools.workbench.scplugin.model.adapter.SessionAdapter; import org.eclipse.persistence.tools.workbench.scplugin.model.adapter.SessionBrokerAdapter; import org.eclipse.persistence.tools.workbench.scplugin.model.adapter.TopLinkSessionsAdapter; import org.eclipse.persistence.tools.workbench.scplugin.model.meta.SCSessionsPropertiesManager; import org.eclipse.persistence.tools.workbench.scplugin.ui.broker.SessionBrokerNode; import org.eclipse.persistence.tools.workbench.uitools.LabelArea; import org.eclipse.persistence.tools.workbench.uitools.app.CollectionAspectAdapter; import org.eclipse.persistence.tools.workbench.uitools.app.CollectionValueModel; import org.eclipse.persistence.tools.workbench.uitools.app.TreeNodeValueModel; import org.eclipse.persistence.tools.workbench.uitools.swing.EmptyIcon; import org.eclipse.persistence.tools.workbench.utility.io.FileTools; import org.eclipse.persistence.tools.workbench.utility.string.StringTools; /** * Main SC Node that holds all the session nodes in a SC project. */ public final class ProjectNode extends SessionsNode { private boolean firstTimeReadOnlyFlagWasDetected; // ********** constructors/initialization ********** public ProjectNode( TopLinkSessionsAdapter topLinkSessions, TreeNodeValueModel parent, SCPlugin plugin, ApplicationContext context) { super( topLinkSessions, parent, plugin, context); this.firstTimeReadOnlyFlagWasDetected = topLinkSessions.getPath().canWrite(); } // **************** factory methods **************************************** protected AbstractApplicationNode buildChildNode( SessionAdapter session) { AbstractApplicationNode node = null; try { node = super.buildChildNode( session); } catch( IllegalArgumentException e) { if( session instanceof SessionBrokerAdapter) node = new SessionBrokerNode(( SessionBrokerAdapter)session, this, ( SCPlugin)this.getPlugin(), this.getApplicationContext()); else throw new IllegalArgumentException( "Invalid Session"); } return node; } protected CollectionValueModel buildSessionsAspectAdapter() { return new CollectionAspectAdapter( this, TopLinkSessionsAdapter.SESSIONS_COLLECTION) { protected Iterator getValueFromSubject() { return (( TopLinkSessionsAdapter)subject).sessions(); } protected int sizeFromSubject() { return (( TopLinkSessionsAdapter)subject).sessionsSize(); } }; } protected AbstractPropertiesPage buildPropertiesPage(WorkbenchContext context) { return new ProjectPropertiesPage(context); } protected Object propertiesPageKey() { return ProjectPropertiesPage.class; } protected String buildIconKey() { return "SESSIONS_CONFIGURATION"; } protected FrameworkAction buildRenameNodeAction(WorkbenchContext workbenchContext) { // No rename supported for now use SaveAs return null; } protected String buildDisplayString() { String displayString = super.buildDisplayString(); File path = this.topLinkSessions().getPath(); if (path.exists() && !path.canWrite()) { displayString = resourceRepository().getString("PROJECT_NODE_DISPLAY_STRING_READ_ONLY", displayString); } return displayString; } protected List buildDisplayStringPropertyNamesList() { List displayStrings = super.buildDisplayStringPropertyNamesList(); displayStrings.add( TopLinkSessionsAdapter.NAME_PROPERTY ); return displayStrings; } private FrameworkAction getAddSessionAction(WorkbenchContext workbenchContext) { return new AddNewSessionAction(workbenchContext); } private FrameworkAction getAddBrokerAction(WorkbenchContext workbenchContext) { return new AddNewBrokerAction(workbenchContext); } public GroupContainerDescription buildMenuDescription(WorkbenchContext workbenchContext) { WorkbenchContext wrappedContext = buildLocalWorkbenchContext(workbenchContext); RootMenuDescription desc = new RootMenuDescription(); MenuGroupDescription newGroup = new MenuGroupDescription(); newGroup.add(getAddSessionAction(wrappedContext)); newGroup.add(getAddBrokerAction(wrappedContext)); MenuDescription newMenu = new MenuDescription(resourceRepository().getString("NEW_MENU"), resourceRepository().getString("NEW_MENU"),resourceRepository().getMnemonic("NEW_MENU"), EMPTY_ICON); newMenu.add(newGroup); MenuGroupDescription newItemGroup = new MenuGroupDescription(); newItemGroup.add(newMenu); desc.add(newItemGroup); MenuGroupDescription closeGroup = new MenuGroupDescription(); closeGroup.add(getCloseAction(workbenchContext)); desc.add(closeGroup); MenuGroupDescription saveGroup = new MenuGroupDescription(); saveGroup.add(getSaveAction(workbenchContext)); saveGroup.add(getSaveAsAction(workbenchContext)); desc.add(saveGroup); desc.add(buildHelpMenuGroup(wrappedContext)); return desc; } public GroupContainerDescription buildToolBarDescription(WorkbenchContext workbenchContext) { WorkbenchContext wrappedContext = buildLocalWorkbenchContext(workbenchContext); ToolBarDescription desc = new ToolBarDescription(); ToolBarButtonGroupDescription addGroup = new ToolBarButtonGroupDescription(); addGroup.add(getAddSessionAction(wrappedContext)); addGroup.add(getAddBrokerAction(wrappedContext)); desc.add(addGroup); return desc; } protected FrameworkAction getCloseAction(WorkbenchContext workbenchContext) { return workbenchContext.getActionRepository().getCloseAction(); } protected FrameworkAction buildDeleteNodeAction(WorkbenchContext workbenchContext) { return null; // Always null } protected FrameworkAction getSaveAction(WorkbenchContext workbenchContext) { return workbenchContext.getActionRepository().getSaveAction(); } protected FrameworkAction getSaveAsAction(WorkbenchContext workbenchContext) { return workbenchContext.getActionRepository().getSaveAsAction(); } TopLinkSessionsAdapter topLinkSessions() { return ( TopLinkSessionsAdapter)this.getValue(); } public String helpTopicID() { return "navigator.scproject"; } // **************** Initialization **************************************** public boolean save(File mostRecentSaveDirectory, WorkbenchContext workbenchContext) { TopLinkSessionsAdapter sessions = this.topLinkSessions(); File path = sessions.getPath(); boolean saved = false; // - There is no directory before the file name and it starts with Sessions, // we assume this is an untitled sessions.xml // - The location might have been marked read only, always do a Save As if( path.getPath().startsWith( SCSessionsPropertiesManager.UNTITLED_FILE_NAME)) { saved = saveAs(mostRecentSaveDirectory, workbenchContext); } else { // The Read-Only flag was changed after the file was opened if (!path.canWrite()) { // Show an error message and ask if we should try again if (firstTimeReadOnlyFlagWasDetected) { showErrorReadOnlyMessage(workbenchContext); firstTimeReadOnlyFlagWasDetected = false; // We can try to save again, use Save As path if (canRetryToSave(workbenchContext)) { saved = saveAs(mostRecentSaveDirectory, workbenchContext); if (saved) { displayStringChanged(); } } } // - A Read-Only file was opened and needs to be saved // - The save is invoked again on a Read-Only file, right away use the Save As path else { saved = saveAs(mostRecentSaveDirectory, workbenchContext); } } // The file is not an untitled file, the file is not marked as Read-Only // then attempt to save it else { saved = saveImp(path, workbenchContext); firstTimeReadOnlyFlagWasDetected = false; if (saved) { displayStringChanged(); } } } return saved; } private boolean canRetryToSave(WorkbenchContext workbenchContext) { return JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog( workbenchContext.getCurrentWindow(), resourceRepository().getString("SAVE_RETRY_TO_SAVE_MESSAGE"), workbenchContext.getApplicationContext().getApplication().getShortProductName(), JOptionPane.YES_NO_OPTION ); } private boolean saveImp( File savePath, WorkbenchContext workbenchContext) { TopLinkSessionsAdapter sessions = this.topLinkSessions(); try { sessions.getProperties().saveAs( preferences(), savePath); // Need to be done before sessions.save() sessions.save( savePath); return true; } catch( Throwable e) { showErrorMessage( e, workbenchContext); return false; } } public boolean saveAs(File mostRecentSaveDirectory, WorkbenchContext workbenchContext) { File path = topLinkSessions().getPath(); File directory = path.getParentFile(); if (directory == null) directory = mostRecentSaveDirectory; JFileChooser chooser = new FileChooserDialog(workbenchContext); chooser.setDialogTitle(resourceRepository().getString( "SAVE_AS_DIALOG_TITLE")); chooser.setCurrentDirectory( directory); chooser.setSelectedFile( path); chooser.setMultiSelectionEnabled( false); int result = chooser.showSaveDialog( workbenchContext.getCurrentWindow()); if( result != JFileChooser.APPROVE_OPTION) return false; workbenchContext.getNavigatorSelectionModel().pushExpansionState(); boolean saved = saveImp(chooser.getSelectedFile(), workbenchContext); workbenchContext.getNavigatorSelectionModel().popAndRestoreExpansionState(); return saved; } public File saveFile() { //The framework expects null if the project has never been saved before File saveLocation = this.topLinkSessions().getPath(); return saveLocation.exists() ? saveLocation : null; } private void showErrorReadOnlyMessage(WorkbenchContext workbenchContext) { String fileName = FileTools.canonicalFile(topLinkSessions().getPath()).getPath(); String message = resourceRepository().getString ( "SAVE_READ_ONLY_ERROR_MESSAGE", workbenchContext.getApplicationContext().getApplication().getShortProductName(), fileName, StringTools.CR ); LabelArea label = new LabelArea(message); JOptionPane.showMessageDialog ( workbenchContext.getCurrentWindow(), label, workbenchContext.getApplicationContext().getApplication().getShortProductName(), JOptionPane.WARNING_MESSAGE ); } private void showErrorMessage(Throwable exception, WorkbenchContext workbenchContext) { ((SCPlugin) getPlugin()).showWarning( workbenchContext, resourceRepository().getString("SAVE_ERROR_MESSAGE", topLinkSessions().getPath().getPath()), exception ); } /** * This extension over the <code>JFileChooser</code> makes sure the selected * file is valid, ie is not Read-Only, is not currently opened. If it's a * different file, then prompt the user to make sure it is ok to overwrite it. */ private class FileChooserDialog extends JFileChooser { private WorkbenchContext workbenchContext; private FileChooserDialog(WorkbenchContext workbenchContext) { super(); this.workbenchContext = workbenchContext; } /** * Determines whether the selected file can be used as the new location to * persist the document. */ public void approveSelection() { int result = canReplaceExistingFile(); if (result == JOptionPane.YES_OPTION) super.approveSelection(); else if (result == JOptionPane.CANCEL_OPTION) cancelSelection(); } /** * Verifies if the file (which is currently selected) can be replaced with * the document to be saved. * * @return <code>JOptionPane.YES_OPTION</code> if the file is not * Read-Only, not opened or can be replaced, <code>JOptionPane.NO_OPTION</code> * if the document can't be saved because the selected file is Read-Only * or the user said no to replace it, or <code><code>JOptionPane.NO_OPTION</code></code> * if the user does not want to replace the file and canceled the confirm * dialog */ private int canReplaceExistingFile() { File file = getSelectedFile(); String applicationName = workbenchContext.getApplicationContext().getApplication().getShortProductName(); // The file is actually opened if (isDocumentOpened(file)) { String message = resourceRepository().getString("SAVE_AS_DIALOG_ALREADY_OPENED", applicationName, file, StringTools.CR); LabelArea label = new LabelArea(message); label.setPreferredWidth(800); JOptionPane.showMessageDialog ( workbenchContext.getCurrentWindow(), label, applicationName, JOptionPane.WARNING_MESSAGE ); return JOptionPane.NO_OPTION; } // The file exist but is marked as Read-Only, show we can't save it if (file.exists() && !file.canWrite()) { String message = resourceRepository().getString("SAVE_AS_DIALOG_CANT_SAVE", file); LabelArea label = new LabelArea(message); label.setPreferredWidth(800); JOptionPane.showMessageDialog ( workbenchContext.getCurrentWindow(), label, applicationName, JOptionPane.WARNING_MESSAGE ); return JOptionPane.NO_OPTION; } // The file exist and is not the file to save, ask to replace it if (file.exists() && !topLinkSessions().getPath().equals(file)) { String message = resourceRepository().getString("SAVE_AS_DIALOG_REPLACE", getSelectedFile().getPath()); LabelArea label = new LabelArea(message); label.setPreferredWidth(800); return JOptionPane.showConfirmDialog ( workbenchContext.getCurrentWindow(), label, applicationName, JOptionPane.YES_NO_CANCEL_OPTION ); } return JOptionPane.YES_OPTION; } /** * Determines whether a file with the given path is already opened. The * location of this document is not considered during the check. * * @param file The file choosen to save this document * @return <code>true</code> if the document at the given location is * already opened; <code>false</code> otherwise */ private boolean isDocumentOpened(File file) { ApplicationNode[] appNodes = nodeManager().projectNodesFor(getPlugin()); for (int i = 0; i < appNodes.length; i++) { ProjectNode node = (ProjectNode) appNodes[i]; // This is this node, continue if (node == ProjectNode.this) continue; File anotherOpenedFile = node.topLinkSessions().getPath(); if (file.equals(anotherOpenedFile)) return true; } return false; } } }