/*
* This file is part of the TimeFinder project.
* Visit http://www.timefinder.de for more information.
* Copyright 2008 the original author or authors.
*
* 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 de.timefinder.core.ui.mydoggy;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import javolution.util.FastMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import org.noos.xing.mydoggy.AggregationPosition;
import org.noos.xing.mydoggy.Content;
import org.noos.xing.mydoggy.ContentManager;
import org.noos.xing.mydoggy.ContentManagerUIListener;
import org.noos.xing.mydoggy.MultiSplitConstraint;
import org.noos.xing.mydoggy.MultiSplitContentManagerUI;
import org.noos.xing.mydoggy.PersistenceDelegate.MergePolicy;
import org.noos.xing.mydoggy.PersistenceDelegateCallback;
import org.noos.xing.mydoggy.TabbedContentManagerUI;
import org.noos.xing.mydoggy.ToolWindowManager;
import org.noos.xing.mydoggy.event.ContentManagerUIEvent;
import org.noos.xing.mydoggy.plaf.MyDoggyToolWindowManager;
import org.noos.xing.mydoggy.plaf.ui.cmp.ExtendedTableLayout;
import org.noos.xing.mydoggy.plaf.ui.content.MyDoggyMultiSplitContentManagerUI;
import org.springframework.richclient.application.ApplicationWindow;
import org.springframework.richclient.application.PageComponent;
import org.springframework.richclient.application.PageDescriptor;
import org.springframework.richclient.application.PageLayoutBuilder;
import org.springframework.richclient.application.support.AbstractApplicationPage;
import org.springframework.richclient.util.Assert;
/**
* This page represents one page for the spring rich client with
* the mydoggy framework. In pure Swing apps one would use a JFrame instead.
*
* @author Peter Karich, peat_hal ‘at’ users ‘dot’ sourceforge ‘dot’ net
*/
public class MyDoggyApplicationPage extends AbstractApplicationPage implements PageLayoutBuilder {
private JPanel rootComponent;
private MyDoggyToolWindowManager toolWindowManager;
private ContentManager contentManager;
private MultiSplitContentManagerUI contentManagerUI;
private Map<String, Entry<Content, PageComponent>> contentAndPageComponentById;
MyDoggyApplicationPage(ApplicationWindow window, PageDescriptor pageDescriptor) {
super(window, pageDescriptor);
contentAndPageComponentById = new FastMap<String, Entry<Content, PageComponent>>();
toolWindowManager = new MyDoggyToolWindowManager();
contentManager = toolWindowManager.getContentManager();
contentManagerUI = new MyDoggyMultiSplitContentManagerUI();
contentManager.setContentManagerUI(contentManagerUI);
assert SwingUtilities.isEventDispatchThread();
contentManagerUI.setTabPlacement(TabbedContentManagerUI.TabPlacement.TOP);
contentManagerUI.setShowAlwaysTab(true);
contentManagerUI.setCloseable(true);
contentManagerUI.setDetachable(true);
contentManagerUI.setMinimizable(true);
contentManagerUI.addContentManagerUIListener(new MyDoggyContentListener());
}
@Override
protected void doAddPageComponent(PageComponent pageComponent) {
Assert.notNull(pageComponent);
// If we have at least one content, then dock into that one!
MultiSplitConstraint constraint;
if (contentAndPageComponentById.values().iterator().hasNext()) {
constraint = new MultiSplitConstraint(contentAndPageComponentById.values().iterator().next().getKey());
} else {
constraint = new MultiSplitConstraint(AggregationPosition.DEFAULT);
}
// Create and register a new content to the mydoggy layout manager
Content c = contentManager.addContent(
pageComponent.getId(),
pageComponent.getDisplayName(), // tabName
pageComponent.getIcon(),
pageComponent.getControl(),
pageComponent.getDisplayName(), // toolTip
constraint);
Assert.notNull(c);
Assert.isTrue(c.getId().equals(pageComponent.getId()));
contentAndPageComponentById.put(pageComponent.getId(),
new DoggyEntry<Content, PageComponent>(c, pageComponent));
// trigger the createControl method of the PageComponent, so if a
// PageComponentListener is added
// in the createControl method, the componentOpened event is received.
pageComponent.getControl();
}
@Override
protected void doRemovePageComponent(PageComponent pageComponent) {
Entry<Content, PageComponent> e = contentAndPageComponentById.remove(pageComponent.getId());
Assert.notNull(e);
boolean ret = contentManager.removeContent(e.getKey());
Assert.isTrue(ret);
}
@Override
protected boolean giveFocusTo(PageComponent pageComponent) {
return pageComponent.getControl().requestFocusInWindow();
}
@Override
public void setActiveComponent(PageComponent pageComponent) {
if (pageComponent != null) {
// really necessary?
Content c = getContent(pageComponent.getId());
if (c != null) {
c.ensureVisible();
}
setActive(pageComponent.getId());
}
super.setActiveComponent(pageComponent);
}
@Override
protected JComponent createControl() {
// At startup create the main component and set the mydoggy specific
// layout manager.
Assert.isNull(rootComponent, "Should not being initialized twice.");
rootComponent = new JPanel();
rootComponent.setLayout(new ExtendedTableLayout(new double[][]{{0, -1, 0}, {0, -1, 0}}));
rootComponent.add(toolWindowManager, "1,1,");
return rootComponent;
}
@Override
public void addView(String viewDescriptorId) {
// called from pageDescriptor.buildInitialLayout (then pageBuilder.addView)
showView(viewDescriptorId);
}
/* Now some helper methods and classes */
private Content getContent(String id) {
return contentManager.getContent(id);
}
private PageComponent getPageComponent(String id) {
Entry<Content, PageComponent> entry =
contentAndPageComponentById.get(id);
if (entry == null) {
return null;
}
return entry.getValue();
}
void buildInitialLayout() {
// add all the specified views (List of views)
getPageDescriptor().buildInitialLayout(this);
}
/**
* This method displays the component with specified key
* @return true if it was successful.
*/
private boolean setActive(final String id) {
Assert.isTrue(SwingUtilities.isEventDispatchThread());
Content c = getContent(id);
if (c != null) {
c.setSelected(true);
return true;
}
return false;
}
@Override
public boolean close() {
try {
saveLayout();
} catch (IOException ex) {
logger.warn("IO Error while saving layout!", ex);
}
return super.close();
}
boolean loadLayout() throws IOException {
File file = getLayoutFile();
if (file != null && file.canRead()) {
Assert.isTrue(SwingUtilities.isEventDispatchThread());
Assert.isTrue(rootComponent.isVisible());
FileInputStream inputStream = new FileInputStream(file);
// load layout, but add the requested content before (via callback)!
toolWindowManager.getPersistenceDelegate().merge(
inputStream, MergePolicy.UNION,
new PersistenceDelegateCallback() {
// @Override
// public ToolWindow toolwindowNotFound(ToolWindowManager toolWindowManager, String toolWindowId, PersistenceNode node) {
// //logger.info("'toolwindow not found' Not supported yet.");
// return null;
// }
//
// @Override
// public Content contentNotFound(ToolWindowManager toolWindowManager, String contentId, PersistenceNode node) {
// addView(contentId);
// return contentAndPageComponentById.get(contentId).getKey();
// }
//
// @Override
// public String validate(PersistenceNode node, String attribute, String attributeValue, Object attributeDefaultValue) {
// return attributeValue;
// }
@Override
public Content contentNotFound(ToolWindowManager toolWindowManager, String contentId) {
addView(contentId);
return contentAndPageComponentById.get(contentId).getKey();
}
});
inputStream.close();
logger.info("Loaded " + contentManager.getContentCount() + " view(s).");
return true;
}
return false;
}
void saveLayout() throws IOException {
File file = getLayoutFile();
if (file != null) {
if (!file.exists()) {
if (!file.createNewFile()) {
return;
}
}
if (file.canWrite()) {
FileOutputStream output = new FileOutputStream(file);
toolWindowManager.getPersistenceDelegate().save(output);
output.close();
//logger.info("Successfully saved layout.");
logger.info("Saved " + contentManager.getContentCount() + " view(s).");
}
}
}
private File getLayoutFile() throws IOException {
PageDescriptor pageDescriptor = getPageDescriptor();
if (pageDescriptor instanceof MyDoggyPageDescriptor) {
return ((MyDoggyPageDescriptor) pageDescriptor).getApplicationSettings().getLayoutFile();
} else {
throw new IOException("Couldn't return the layout file. Wrong PageDescriptorType:" + pageDescriptor.getClass());
}
}
/**
* SpringRC should be informed of a MyDoggy closing event.
*/
private class MyDoggyContentListener implements ContentManagerUIListener {
@Override
public boolean contentUIRemoving(ContentManagerUIEvent cmEvent) {
Content content = cmEvent.getContentUI().getContent();
Assert.notNull(content);
PageComponent pc = getPageComponent(content.getId());
Assert.notNull(pc);
close(pc);
// let mydoggy remove the page ! (don't no for sure if this is the reason of the NPE in mydoggy if we return close(pc))
return false;
}
@Override
public void contentUIDetached(ContentManagerUIEvent cmEvent) {
}
}
private static class DoggyEntry<K, V> implements Map.Entry<K, V> {
private K key;
private V innerValue;
DoggyEntry(K key, V value) {
this.key = key;
this.innerValue = value;
}
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return innerValue;
}
@Override
public V setValue(V value) {
V old = this.innerValue;
this.innerValue = value;
return old;
}
}
}