/**
* Copyright (C) 2015 Valkyrie RCP
*
* Licensed 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.valkyriercp.application.docking;
import com.vldocking.swing.docking.DockKey;
import com.vldocking.swing.docking.Dockable;
import com.vldocking.swing.docking.DockableResolver;
import com.vldocking.swing.docking.DockableState;
import com.vldocking.swing.docking.DockingContext;
import com.vldocking.swing.docking.DockingDesktop;
import com.vldocking.swing.docking.event.DockableSelectionEvent;
import com.vldocking.swing.docking.event.DockableSelectionListener;
import com.vldocking.swing.docking.event.DockableStateChangeEvent;
import com.vldocking.swing.docking.event.DockableStateChangeListener;
import com.vldocking.swing.docking.event.DockableStateWillChangeEvent;
import com.vldocking.swing.docking.event.DockableStateWillChangeListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.valkyriercp.application.ApplicationWindow;
import org.valkyriercp.application.PageComponent;
import org.valkyriercp.application.PageDescriptor;
import org.valkyriercp.application.PageLayoutBuilder;
import org.valkyriercp.application.ViewDescriptor;
import org.valkyriercp.application.support.AbstractApplicationPage;
import org.xml.sax.SAXException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.swing.*;
import javax.xml.parsers.ParserConfigurationException;
/**
* @author Rogan Dawes
*/
public class VLDockingApplicationPage extends AbstractApplicationPage implements PageLayoutBuilder {
private Logger logger = LoggerFactory.getLogger(getClass());
private DockingDesktop desktop;
private DockingContext dockingContext;
private VLDockingLayoutManager layoutManager = null;
private boolean resolving = false;
private Resource initialLayout = null;
public VLDockingApplicationPage(ApplicationWindow window, PageDescriptor pageDescriptor) {
super(window, pageDescriptor);
if (pageDescriptor instanceof VLDockingPageDescriptor) {
VLDockingPageDescriptor descriptor = (VLDockingPageDescriptor) pageDescriptor;
setLayoutManager(descriptor.getLayoutManager());
setInitialLayout(descriptor.getInitialLayout());
}
}
protected PageComponent getPageComponent(Dockable dockable) {
if (dockable instanceof ViewDescriptorDockable)
return ((ViewDescriptorDockable) dockable).getPageComponent();
return null;
}
protected Dockable getDockable(PageComponent pageComponent) {
DockableState[] states = desktop.getDockables();
for (int i = 0; i < states.length; i++) {
Dockable dockable = states[i].getDockable();
PageComponent pc = getPageComponent(dockable);
if (pc == pageComponent)
return dockable;
}
return null;
}
protected boolean giveFocusTo(PageComponent pageComponent) {
Dockable dockable = getDockable(pageComponent);
if (dockable == null) {
return false;
}
// Don't request focus here, the DockingDesktop already shifts focus. If requesting focus at this point,
// the DockingDesktop catches this event and fires another focus event. This might cause loops when
// maximizing/minimizing/restoring because at that point a remove of the component is done which shifts
// focus and after setting the correct docking state, a focus request is done.
// see RCP-558
return true;
}
public void addView(String viewDescriptorId) {
showView(viewDescriptorId);
}
protected void doAddPageComponent(PageComponent pageComponent) {
if (resolving)
return;
pageComponent.getControl();
Dockable dockable = getDockable(pageComponent);
if (dockable != null)
return;
dockable = createDockable(pageComponent);
getLayoutManager().addDockable(desktop, dockable);
}
protected Dockable createDockable(PageComponent pageComponent) {
return createDockable(getViewDescriptor(pageComponent.getId()), pageComponent);
}
protected Dockable createDockable(ViewDescriptor descriptor, PageComponent pageComponent) {
return new ViewDescriptorDockable(descriptor, pageComponent);
}
protected void doRemovePageComponent(PageComponent pageComponent) {
Dockable dockable = getDockable(pageComponent);
if (dockable != null) {
getLayoutManager().removeDockable(desktop, dockable);
}
}
protected JComponent createControl() {
String name = getPageDescriptor().getId();
desktop = new DockingDesktop(name, getDockingContext());
desktop.setName(name);
DockableListener listener = new DockableListener();
desktop.addDockableStateChangeListener(listener);
desktop.addDockableStateWillChangeListener(listener);
desktop.addDockableSelectionListener(listener);
if (initialLayout != null) {
try {
InputStream in = initialLayout.getInputStream();
desktop.getContext().readXML(in);
in.close();
} catch (IOException ioe) {
logger.warn("Error reading workspace layout " + initialLayout + ", using defaults", ioe);
getPageDescriptor().buildInitialLayout(this);
} catch (SAXException saxe) {
logger.warn("Error parsing workspace layout " + initialLayout + ", using defaults", saxe);
getPageDescriptor().buildInitialLayout(this);
} catch (ParserConfigurationException pce) {
logger.warn("Error parsing workspace layout " + initialLayout + ", using defaults", pce);
getPageDescriptor().buildInitialLayout(this);
}
if (desktop.getDockables().length == 0) {
getPageDescriptor().buildInitialLayout(this);
}
} else {
getPageDescriptor().buildInitialLayout(this);
}
return desktop;
}
protected void updatePageComponentProperties(PageComponent pageComponent) {
Dockable dockable = getDockable(pageComponent);
DockKey dockKey = dockable.getDockKey();
if (pageComponent.getIcon() != null) {
dockKey.setIcon(pageComponent.getIcon());
}
dockKey.setName(pageComponent.getDisplayName());
dockKey.setTooltip(pageComponent.getCaption());
}
/**
* @return the dockingContext
*/
public DockingContext getDockingContext() {
if (this.dockingContext == null) {
this.dockingContext = new DockingContext();
this.dockingContext.setDockableResolver(new ViewDescriptorResolver());
}
return this.dockingContext;
}
/**
* @return the layoutManager
*/
private VLDockingLayoutManager getLayoutManager() {
if (this.layoutManager == null) {
layoutManager = new DefaultLayoutManager();
}
return this.layoutManager;
}
/**
* @param layoutManager
* the layoutManager to set
*/
public void setLayoutManager(VLDockingLayoutManager layoutManager) {
this.layoutManager = layoutManager;
}
/**
* @param initialLayout
* the initialLayout to set
*/
public void setInitialLayout(Resource initialLayout) {
this.initialLayout = initialLayout;
}
public boolean close() {
// try to save the layout if it came from a file we can write to
if (initialLayout != null) {
File file = null;
try {
file = initialLayout.getFile();
if (file.canWrite()) {
try {
OutputStream out = new FileOutputStream(file);
desktop.getContext().writeXML(out);
out.close();
} catch (IOException ioe) {
logger.warn("Error saving desktop layout to " + file, ioe);
}
}
} catch (IOException ioe) {
}
}
return super.close();
}
private class DockableListener implements DockableStateChangeListener, DockableStateWillChangeListener,
DockableSelectionListener {
/*
* (non-Javadoc)
*
* @see com.vlsolutions.swing.docking.event.DockableStateWillChangeListener#dockableStateWillChange(com.vlsolutions.swing.docking.event.DockableStateWillChangeEvent)
*/
public void dockableStateWillChange(DockableStateWillChangeEvent event) {
DockableState futureState = event.getFutureState();
if (futureState.isClosed()) {
Dockable dockable = futureState.getDockable();
if (dockable instanceof ViewDescriptorDockable) {
ViewDescriptorDockable vdd = (ViewDescriptorDockable) dockable;
PageComponent pc = vdd.getPageComponent();
if (!pc.canClose())
event.cancel();
}
}
}
/*
* (non-Javadoc)
*
* @see com.vlsolutions.swing.docking.event.DockableStateChangeListener#dockableStateChanged(com.vlsolutions.swing.docking.event.DockableStateChangeEvent)
*/
public void dockableStateChanged(DockableStateChangeEvent event) {
DockableState previousState = event.getPreviousState();
DockableState newState = event.getNewState();
Dockable dockable = newState.getDockable();
PageComponent pc = getPageComponent(dockable);
if (pc == null)
return;
if (previousState != null && !previousState.isClosed() && newState.isClosed()) {
pc.getContext().getPage().close(pc);
}
}
/*
* (non-Javadoc)
*
* @see com.vlsolutions.swing.docking.event.DockableSelectionListener#selectionChanged(com.vlsolutions.swing.docking.event.DockableSelectionEvent)
*/
public void selectionChanged(DockableSelectionEvent e) {
Dockable dockable = e.getSelectedDockable();
if (dockable != null) {
PageComponent pc = getPageComponent(dockable);
if (pc != null)
setActiveComponent(pc);
}
}
}
private class ViewDescriptorResolver implements DockableResolver {
public Dockable resolveDockable(String keyName) {
ViewDescriptor descriptor = getViewDescriptor(keyName);
if (descriptor == null)
return null;
PageComponent pageComponent = createPageComponent(descriptor);
resolving = true;
addPageComponent(pageComponent);
resolving = false;
Dockable dockable = createDockable(descriptor, pageComponent);
return dockable;
}
}
private class DefaultLayoutManager implements VLDockingLayoutManager {
/*
* (non-Javadoc)
*
* @see org.springframework.richclient.application.vldocking.VLDockingLayoutManager#addDockable(com.vlsolutions.swing.docking.DockingDesktop,
* com.vlsolutions.swing.docking.Dockable)
*/
public void addDockable(DockingDesktop desktop, Dockable dockable) {
desktop.addDockable(dockable);
}
/*
* (non-Javadoc)
*
* @see org.springframework.richclient.application.vldocking.VLDockingLayoutManager#removeDockable(com.vlsolutions.swing.docking.DockingDesktop,
* com.vlsolutions.swing.docking.Dockable)
*/
public void removeDockable(DockingDesktop desktop, Dockable dockable) {
desktop.remove(dockable);
}
}
}