/* * Rapid Beans Framework: DocumentView.java * * Copyright (C) 2009 Martin Bluemel * * Creation Date: 02/14/2006 * * This program is free software; you can redistribute it and/or modify it under the terms of the * GNU Lesser General Public License as published by the Free Software Foundation; * either version 3 of the License, or (at your option) any later version. * This program 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 Lesser General Public License for more details. * You should have received a copies of the GNU Lesser General Public License and the * GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses/>. */ package org.rapidbeans.presentation; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.MissingResourceException; import org.rapidbeans.core.basic.PropertyCollection; import org.rapidbeans.core.basic.RapidBean; import org.rapidbeans.core.common.RapidBeansLocale; import org.rapidbeans.core.exception.RapidBeansRuntimeException; import org.rapidbeans.datasource.Document; import org.rapidbeans.datasource.Filter; import org.rapidbeans.datasource.event.AddedEvent; import org.rapidbeans.datasource.event.ChangedEvent; import org.rapidbeans.datasource.event.DocumentChangeListener; import org.rapidbeans.datasource.event.RemovedEvent; import org.rapidbeans.presentation.config.ConfigApplication; import org.rapidbeans.presentation.config.ConfigDocument; import org.rapidbeans.presentation.config.ConfigPropPersistencestrategy; import org.rapidbeans.presentation.config.ConfigView; import org.rapidbeans.presentation.swing.DocumentViewSwing; /** * A view for a bean document. * * @author Martin Bluemel */ public abstract class DocumentView implements View, DocumentTreeViewListener, EditorBeanListener, DocumentChangeListener { /** * @return the divider location */ public int getDividerLocation() { return -1; } /** * @param the * divider location */ public void setDividerLocation(final int loc) { } /** * the client. */ private Application client = null; protected MainWindow getMainwindow() { if (this.client == null) { return null; } return this.client.getMainwindow(); } /** * @return the view's title. */ public String getTitle() { String idstring = null; final RapidBeansLocale locale = this.getClient().getCurrentLocale(); final RapidBean bean = this.document.getRoot(); // gui.properties: view.<document config type name>.<config type // name>.title if (this.getConfigDocument() != null && this.getConfiguration() != null) { try { final String key = "view." + this.getConfigDocument().getName() + "." + this.getConfiguration().getName() + ".title"; final String pattern = locale.getStringGui(key); idstring = bean.expandPropertyValues(pattern, locale); } catch (MissingResourceException e) { idstring = null; } } // gui.properties: document.<document config type name>.title if (idstring == null && this.getConfigDocument() != null) { try { final String key = "document." + this.getConfigDocument().getName() + ".title"; final String pattern = locale.getStringGui(key); idstring = bean.expandPropertyValues(pattern, locale); } catch (MissingResourceException e) { idstring = null; } } // gui.properties: document.<bean classname>.title if (idstring == null) { try { final String key = "document." + bean.getClass().getName().toLowerCase() + ".title"; final String pattern = locale.getStringGui(key); idstring = bean.expandPropertyValues(pattern, locale); } catch (MissingResourceException e) { idstring = null; } } // gui.properties: bean.<bean classname> if (idstring == null) { try { final String key = "bean." + bean.getType().getName().toLowerCase(); final String pattern = locale.getStringGui(key); idstring = bean.expandPropertyValues(pattern, locale); } catch (MissingResourceException e) { idstring = null; } } if (idstring == null) { idstring = bean.toStringGui(locale); } return idstring; } /** * @return the client */ public Application getClient() { return this.client; } /** * the tree view. */ private DocumentTreeView treeView = null; /** * @return the tree view */ public DocumentTreeView getTreeView() { return this.treeView; } /** * the document viewed. */ private Document document = null; /** * @return the document viewed */ public Document getDocument() { return this.document; } /** * the view's name. */ private String name = null; /** * the document view's name is the document's name. * * @return the document view's name */ public String getName() { return this.name; } /** * @return the configured persistence strategy if any or 'ondemand' per * default */ public ConfigPropPersistencestrategy getPersistencestrategy() { return this.getConfiguration().getPersistencestrategy(); } /** * the editors. */ private HashMap<String, EditorBean> editors = new HashMap<String, EditorBean>(); /** * the tree paths. */ private HashMap<String, Object> treePaths = new HashMap<String, Object>(); /** * get an editor by a bean's ID. * * @param bean * the edited bean * @param newMode * if the editor to get is in new mode * * @return the bean editor for that key */ public EditorBean getEditor(final RapidBean bean, final boolean newMode) { final String key = this.getEditorKey(newMode, bean); return this.editors.get(key); } /** * get all bean editors. * * @return all bean editors in the order first opened first */ public Collection<EditorBean> getEditors() { return this.editors.values(); } /** * @return the number of all open editors. */ public int getOpenEditorsNumber() { return this.editors.values().size(); } /** * get a tree path by a bean's ID. * * @param bean * the edited bean * * @return the tree path for that key */ protected Object getTreePath(final RapidBean bean) { final String key = bean.getType().getName() + "::" + bean.getIdString(); return this.treePaths.get(key); } /** * the view's document configuration. */ private ConfigDocument configDocument = null; /** * @return the view's document configuration */ public ConfigDocument getConfigDocument() { return this.configDocument; } /** * the view's configuration. */ private ConfigView configuration = null; /** * @return the view's configuration */ public ConfigView getConfiguration() { return this.configuration; } /** * constructor. * * @param clnt * the client * @param doc * the document * @param docconfname * the view's document config name * @param viewconfname * the view's config name * @param filter * the filter to apply */ protected DocumentView(final Application clnt, final Document doc, final String docconfname, final String viewconfname, final Filter filter) { this.client = clnt; this.document = doc; if (filter != null) { this.beanFilter = filter; this.beanFilter.setDocument(doc); } if (clnt.getConfiguration() != null) { this.configDocument = clnt.getConfiguration().getConfigDocument(docconfname); } if (this.configDocument == null) { this.configDocument = new ConfigDocument(); this.configDocument.setName(docconfname); } if (clnt.getConfiguration() != null) { this.configuration = clnt.getConfiguration() .getConfigView(this.getConfigDocument().getName(), viewconfname); } if (this.configuration == null) { this.configuration = new ConfigView(); } this.name = doc.getName() + "." + viewconfname; this.treeView = DocumentTreeView.createInstance(this.client, doc, filter); this.document.addDocumentChangeListener(this); this.treeView.setTreeViewListener(this); } /** * edit a bean. * * @param bean * the bean to edit * * @return the editor opened */ public EditorBean editBean(final RapidBean bean) { Object[] keys = { this.treeView.getTreeKey(bean) }; Object[] selObjs = { bean }; return this.treeView.editBeans(keys, selObjs); } /** * handler for selected beans. * * @param bean * the selected bean * @param newBeanParent * a new Bean's parent collection property. Is not null if a new * Bean is to be created Is null if an existing bean is simply * edited * @param treePath * the tree path * @param newMode * if the editor is opened in new mode or not * * @return the editor created. */ protected EditorBean addBeanEditor(final RapidBean bean, final PropertyCollection newBeanParent, final Object treePath, final boolean newMode) { final EditorBean editor = EditorBean.createInstance(this.client, this, bean, newBeanParent); if (newMode) { final Application app = ApplicationManager.getApplication(); if (app != null) { final CreateNewBeansEditorApplyBehaviour mode = app.getSettings().getBasic().getGui() .getCreateNewBeansEditorApplyBehaviour(); editor.setCreateApplyMode(mode); } } final String key = this.getEditorKey(newMode, bean); this.editors.put(key, editor); this.treePaths.put(key, treePath); editor.addEditorListener(this); return editor; } /** * @return the key of the selected editor. */ protected abstract String getSelectedEditorKey(); /** * Update the document view's title. */ protected abstract void updateTitle(); /** * handler for closed bean editors. * * @param editor * the editor to close */ public void closeBeanEditor(final EditorBean editor) { String key = this.getEditorKey(editor.isInNewMode(), editor.getBean()); this.editors.remove(key); selectCurrentlySelectedEditorInTreeView(); } /** * @param isInNewMode * if the editor is in new modeor not * @param bean * the bean to be edited * @return the editor key */ private String getEditorKey(final boolean isInNewMode, final RapidBean bean) { String key; if (isInNewMode) { key = bean.getType().getName() + "::@@new@@"; } else { key = bean.getType().getName() + "::" + bean.getIdString(); } return key; } /** * select the currently selected editor in the tree view. */ public void selectCurrentlySelectedEditorInTreeView() { this.treeView.setSelectedBean(this.treePaths.get(this.getSelectedEditorKey())); } /** * select the currently selected editor in the tree view. */ public void selectBeanInTreeView(final RapidBean bean) { this.treeView.setSelectedBean(this.treePaths.get(bean)); } /** * constructor argument types. */ private static final Class<?>[] CONSTR_PARTYPES = { Application.class, Document.class, String.class, String.class, Filter.class }; /** * create a DocumentView of a special type. * * @param client * the parent client * @param document * the document to show * @param docconfname * the view's document configuration name * @param viewconfname * the view's configuration name * @param filter * the filter * * @return the instance */ public static DocumentView createInstance(final Application client, final Document document, final ConfigDocument docconf, final ConfigView viewconf, final Filter filter) { String docconfname = null; if (docconf != null) { docconfname = docconf.getName(); } String viewconfname = null; if (viewconf != null) { viewconfname = viewconf.getName(); } return createInstance(client, document, docconfname, viewconfname, filter); } /** * the BiBeanFilter applied to this view. */ private Filter beanFilter = null; /** * create a DocumentView of a special type. * * @param client * the parent client * @param document * the document to show * @param docconfname * the view's document configuration name * @param viewconfname * the view's configuration name * @param filter * the filter * * @return the instance */ public static DocumentView createInstance(final Application client, final Document document, final String doccfgname, final String viewcfgname, final Filter filter) { String docconfname = null; if (doccfgname == null) { docconfname = ConfigDocument.NAME_NO_CONFIG; } else { docconfname = doccfgname; } document.setConfigName(docconfname); String viewconfname = null; if (viewcfgname == null) { viewconfname = ConfigView.NAME_NO_CONFIG; } else { viewconfname = viewcfgname; } DocumentView documentView = null; final ConfigApplication clientCfg = client.getConfiguration(); if (clientCfg != null) { final ConfigView viewconf = clientCfg.getConfigView(docconfname, viewconfname); if (viewconf != null && viewconf.getViewclass() != null) { Class<?> viewclass = null; try { viewclass = Class.forName(viewconf.getViewclass()); } catch (ClassNotFoundException e) { viewclass = null; } if (viewclass != null) { try { Constructor<?> constr = viewclass.getConstructor(CONSTR_PARTYPES); Object[] oa = { client, document, docconfname, viewconfname, filter }; documentView = (DocumentView) constr.newInstance(oa); } catch (SecurityException e) { throw new RapidBeansRuntimeException(e); } catch (NoSuchMethodException e) { throw new RapidBeansRuntimeException(e); } catch (InstantiationException e) { throw new RapidBeansRuntimeException(e); } catch (IllegalAccessException e) { throw new RapidBeansRuntimeException(e); } catch (InvocationTargetException e) { throw new RapidBeansRuntimeException(e); } } } } if (documentView == null) { switch (client.getConfiguration().getGuitype()) { case swing: documentView = new DocumentViewSwing(client, document, docconfname, viewconfname, filter); break; case eclipsercp: // mainWindow = new BBMainWindowEclispercp(); break; default: throw new RapidBeansRuntimeException("Unknown GUI type \"" + client.getConfiguration().getGuitype().name() + "\""); } } return documentView; } /** * event handler for bean pre add event. * * @param e * the added event */ public void beanAddPre(final AddedEvent e) { if (ThreadLocalEventLock.get()) { return; } this.treeView.beanAddPre(e); for (EditorBean bbEditor : this.editors.values()) { bbEditor.beanAddPre(e); } } /** * event handler for bean added event. * * @param e * the added event */ public void beanAdded(final AddedEvent e) { if (ThreadLocalEventLock.get()) { return; } this.treeView.beanAdded(e); for (EditorBean bbEditor : this.editors.values()) { bbEditor.beanAdded(e); } markAsChanged(true); } /** * event handler for bean changed event. * * @param e * the changed event */ public void beanChangePre(final ChangedEvent e) { this.treeView.beanChangePre(e); for (EditorBean bbEditor : this.editors.values()) { bbEditor.beanChangePre(e); } } /** * event handler for bean changed event. * * @param e * the changed event */ public void beanChanged(final ChangedEvent e) { markAsChanged(true); this.treeView.beanChanged(e); if (e.getBean() == this.document.getRoot()) { this.updateTitle(); } for (EditorBean bbEditor : this.editors.values()) { bbEditor.beanChanged(e); } } /** * event handler for bean pre remove event. * * @param e * the removed event */ public void beanRemovePre(final RemovedEvent e) { if (ThreadLocalEventLock.get()) { return; } this.treeView.beanRemovePre(e); for (EditorBean bbEditor : this.editors.values()) { bbEditor.beanRemovePre(e); } } /** * event handler for bean removed event. * * @param event * the removed event */ public void beanRemoved(final RemovedEvent event) { if (ThreadLocalEventLock.get()) { return; } this.treeView.beanRemoved(event); ArrayList<EditorBean> bbEditors = new ArrayList<EditorBean>(); for (EditorBean bbEditor : this.editors.values()) { bbEditors.add(bbEditor); } for (EditorBean bbEditor : bbEditors) { bbEditor.beanRemoved(event); } markAsChanged(true); } /** * reset the document change mark. */ public void documentSaved() { markAsChanged(false); } /** * close a document view. * * @return if cancelling is desired */ public boolean close() { boolean cancel = false; ArrayList<EditorBean> clonedEditors = new ArrayList<EditorBean>(); for (EditorBean editor : this.editors.values()) { clonedEditors.add(editor); } for (EditorBean editor : clonedEditors) { cancel = editor.close(); if (cancel) { break; } } final Application app = ApplicationManager.getApplication(); if (!cancel) { switch (this.getPersistencestrategy()) { case onclosedocumentview: case oncloseeditor: if (this.document.getChanged()) { if (app != null) { app.save(this.document); } else { this.document.save(); } } break; default: break; } } if ((!cancel) && this.document.getChanged() && this.client.isLastOpenDocumentView(this) && (app == null || (!app.getTestMode()))) { final RapidBeansLocale locale = this.client.getCurrentLocale(); final String msg = locale.getStringMessage("messagedialog.documentview.close", this.getTitle()); MessageDialogResponse response = this.client.messageYesNoCancel(msg, locale.getStringMessage("messagedialog.documentview.close.title")); switch (response) { case yes: if (this.document.getUrl() == null) { DocumentController.saveAs(this.document); } if (this.document.getUrl() != null) { if (app != null) { app.save(this.document); } else { this.document.save(); } } else { cancel = true; } break; case no: break; default: cancel = true; break; } } if (!cancel) { this.document.removeDocumentChangeListener(this); if (this.client.getView(this.name) != null) { this.client.removeView(this); } if (this.client.getDocument(this.document.getName()) != null) { this.client.removeDocument(this.document); } } return cancel; } /** * mark / unmark the document as changed. * * @param changed * if changed or unchanged */ public abstract void markAsChanged(final boolean changed); /** * @return the beanFilter */ protected Filter getBeanFilter() { return beanFilter; } }