001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.image;
043:
044: import java.beans.PropertyVetoException;
045: import java.util.Enumeration;
046: import javax.swing.SwingUtilities;
047: import org.openide.cookies.CloseCookie;
048: import org.openide.cookies.OpenCookie;
049: import org.openide.filesystems.FileChangeListener;
050: import org.openide.filesystems.FileChangeAdapter;
051: import org.openide.filesystems.FileEvent;
052: import org.openide.loaders.DataObject;
053: import org.openide.loaders.MultiDataObject;
054: import org.openide.loaders.OpenSupport;
055: import org.openide.NotifyDescriptor;
056: import org.openide.DialogDisplayer;
057: import org.openide.windows.CloneableOpenSupport;
058: import org.openide.windows.CloneableTopComponent;
059: import org.openide.util.NbBundle;
060: import org.openide.util.RequestProcessor;
061: import org.openide.util.RequestProcessor.Task;
062:
063: /**
064: * OpenSupport flavored with some <code>CloneableEditorSupport</code> features like
065: * listening on changes of image file and renames on dataobject,
066: * so it can work appropriate in Editor window.
067: *
068: * @author Peter Zavadsky
069: * @author Marian Petras
070: */
071: public class ImageOpenSupport extends OpenSupport implements
072: OpenCookie, CloseCookie {
073:
074: /** Saves last modified time. */
075: private long lastSaveTime;
076:
077: /** Listens for changes on file. */
078: private FileChangeListener fileChangeL;
079:
080: /** Reloading task. */
081: private Task reloadTask;
082:
083: /** Constructs ImageOpenSupportObject on given MultiDataObject.Entry. */
084: public ImageOpenSupport(MultiDataObject.Entry entry) {
085: super (entry, new Environment(entry.getDataObject())); // TEMP
086: }
087:
088: /** Creates the CloenableTOPComponent viewer of image. */
089: public CloneableTopComponent createCloneableTopComponent() {
090: prepareViewer();
091: return new ImageViewer((ImageDataObject) entry.getDataObject());
092: }
093:
094: /** Set listener for changes on image file. */
095: void prepareViewer() {
096: // listen for changes on the image file
097: if (fileChangeL == null) {
098: fileChangeL = new FileChangeAdapter() {
099: public void fileChanged(final FileEvent evt) {
100: if (allEditors.isEmpty()) {
101: return;
102: }
103:
104: if (evt.getFile().isVirtual()) {
105: entry.getFile().removeFileChangeListener(this );
106: // File doesn't exist on disk - simulate env
107: // invalidation.
108: ((Environment) ImageOpenSupport.this .env)
109: .fileRemoved();
110: entry.getFile().addFileChangeListener(this );
111: return;
112: }
113:
114: if (evt.getTime() > lastSaveTime) {
115: lastSaveTime = System.currentTimeMillis();
116:
117: // Post in new task.
118: if (reloadTask == null
119: || reloadTask.isFinished()) {
120:
121: reloadTask = RequestProcessor.getDefault()
122: .post(new Runnable() {
123: public void run() {
124: reload(evt);
125: }
126: });
127: }
128: }
129: }
130: };
131: }
132: entry.getFile().addFileChangeListener(fileChangeL);
133: lastSaveTime = System.currentTimeMillis();
134: }
135:
136: /** Ask and reload/close image views. */
137: private void reload(FileEvent evt) {
138: // ask if reload?
139: // XXX the following is a resource path in NB 3.x and a URL after build system
140: // merge; better to produce something nicer (e.g. FileUtil.toFile):
141: String msg = NbBundle.getMessage(ImageOpenSupport.class,
142: "MSG_ExternalChange", entry.getFile());
143: NotifyDescriptor nd = new NotifyDescriptor.Confirmation(msg,
144: NotifyDescriptor.YES_NO_OPTION);
145: Object ret = DialogDisplayer.getDefault().notify(nd);
146:
147: if (NotifyDescriptor.YES_OPTION.equals(ret)) {
148: // due to compiler 1.2 bug only
149: final ImageDataObject imageObj = (ImageDataObject) entry
150: .getDataObject();
151: final CloneableTopComponent.Ref editors = allEditors;
152:
153: Enumeration e = editors.getComponents();
154: while (e.hasMoreElements()) {
155: final Object pane = e.nextElement();
156: SwingUtilities.invokeLater(new Runnable() {
157: public void run() {
158: ((ImageViewer) pane).updateView(imageObj);
159: }
160: });
161: }
162: }
163: }
164:
165: /** Environment for image open support. */
166: private static class Environment extends OpenSupport.Env {
167: /** generated Serialized Version UID */
168: static final long serialVersionUID = -1934890789745432254L;
169:
170: /** Constructor. */
171: public Environment(DataObject dataObject) {
172: super (dataObject);
173: }
174:
175: /** Overrides superclass method. Gets from OpenCookie. */
176: public CloneableOpenSupport findCloneableOpenSupport() {
177: return (CloneableOpenSupport) getDataObject().getCookie(
178: OpenCookie.class);
179: }
180:
181: /** Called from enclosing support.
182: * The components are going to be closed anyway and in case of
183: * modified document its asked before if to save the change. */
184: private void fileRemoved() {
185: try {
186: fireVetoableChange(PROP_VALID, Boolean.TRUE,
187: Boolean.FALSE);
188: } catch (PropertyVetoException pve) {
189: // Ignore.
190: }
191:
192: firePropertyChange(PROP_VALID, Boolean.TRUE, Boolean.FALSE);
193: }
194: } // End of nested Environment class.
195: }
|