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.core.windows.view;
043:
044: import java.awt.*;
045: import java.awt.datatransfer.DataFlavor;
046: import java.awt.dnd.*;
047: import java.util.Arrays;
048: import java.util.logging.Level;
049: import java.util.logging.Logger;
050: import javax.swing.*;
051: import javax.swing.border.Border;
052: import org.netbeans.core.windows.*;
053: import org.netbeans.core.windows.view.dnd.*;
054: import org.openide.util.*;
055: import org.openide.windows.*;
056:
057: /**
058: * Class which represents model of editor area element for GUI hierarchy.
059: *
060: * @author Peter Zavadsky
061: */
062: public class EditorView extends ViewElement {
063:
064: private static final boolean IS_GTK = "GTK".equals(UIManager
065: .getLookAndFeel().getID()); //NOI18N
066:
067: private ViewElement editorArea;
068:
069: private EditorAreaComponent editorAreaComponent;
070:
071: // XXX PENDING
072: private final WindowDnDManager windowDnDManager;
073:
074: public EditorView(Controller controller,
075: WindowDnDManager windowDnDManager, double resizeWeight,
076: ViewElement editorArea) {
077: super (controller, resizeWeight);
078:
079: this .editorArea = editorArea;
080: this .windowDnDManager = windowDnDManager;
081: }
082:
083: // XXX
084: Rectangle getPureBounds() {
085: Component comp = getEditorAreaComponent();
086: Rectangle bounds = comp.getBounds();
087: Point location = new Point(0, 0);
088: javax.swing.SwingUtilities.convertPointToScreen(location, comp);
089: bounds.setLocation(location);
090: return bounds;
091: }
092:
093: private EditorAreaComponent getEditorAreaComponent() {
094: if (editorAreaComponent == null) {
095: editorAreaComponent = new EditorAreaComponent(this ,
096: windowDnDManager);
097: }
098:
099: // Workaround for #42640
100: if (EditorView.IS_GTK && !editorAreaComponent.isValid()) {
101: editorAreaComponent.repaint();
102: }
103: return editorAreaComponent;
104: }
105:
106: /** Handles special border policy - scroll pane like border only
107: * if editor area is null.
108: */
109: private void manageBorder(JPanel panel) {
110: if (editorArea != null) {
111: panel.setBorder(null);
112: } else {
113: if (Utilities.isMac()) {
114: //#64701 on macosx the nb.scrollpane.border draws ugly line on top
115: panel.setBorder(BorderFactory.createEmptyBorder());
116: } else {
117: // special border installed into UI manager by netbeans
118: panel.setBorder((Border) UIManager
119: .get("Nb.ScrollPane.border"));
120: }
121: }
122: }
123:
124: public ViewElement getEditorArea() {
125: return editorArea;
126: }
127:
128: public void setEditorArea(ViewElement editorArea) {
129: this .editorArea = editorArea;
130: }
131:
132: public Component getComponent() {
133: // assureComponentInEditorArea();
134: return getEditorAreaComponent();
135: }
136:
137: public boolean updateAWTHierarchy(Dimension availableSpace) {
138: // System.out.println("EditorView:updateAWTHierarchy=" + availableSpace);
139: boolean result = false;
140: EditorAreaComponent comp = getEditorAreaComponent();
141: Dimension d = (Dimension) comp
142: .getClientProperty("lastAvailableSpace"); //NOI18N
143: Dimension currDim = comp.getPreferredSize();
144: if (!availableSpace.equals(d)
145: || !availableSpace.equals(currDim)) {
146: //We will only return true if we actually did something
147: comp.setPreferredSize(availableSpace);
148: // comp.setMinimumSize(availableSpace);
149: comp
150: .putClientProperty("lastAvailableSpace",
151: availableSpace); //NOI18N
152: result = true;
153: }
154: assureComponentInEditorArea();
155: if (editorArea != null) {
156: result |= editorArea
157: .updateAWTHierarchy(new Dimension(
158: availableSpace.width - 5,
159: availableSpace.height - 5));
160: }
161: return result;
162: }
163:
164: void assureComponentInEditorArea() {
165: EditorAreaComponent eac = getEditorAreaComponent();
166: if (editorArea == null) {
167: eac.setAreaComponent(null);
168: } else {
169: eac.setAreaComponent(editorArea.getComponent());
170: }
171: manageBorder(eac);
172:
173: // // XXX #36885 When in maximixed and compact mode, we cannot add the components
174: // // into the editor area, it would remove it from the screen.
175: // if(addingAllowed) {
176: // if(this.editorArea != null) {
177: // editorAreaComp.add(this.editorArea.getComponent(), BorderLayout.CENTER);
178: // }
179: //
180: // editorAreaComp.validate();
181: // editorAreaComp.repaint();
182: // }
183: }
184:
185: private static DataFlavor URI_LIST_DATA_FLAVOR;
186: static {
187: try {
188: URI_LIST_DATA_FLAVOR = new DataFlavor(
189: "text/uri-list;class=java.lang.String");
190: } catch (ClassNotFoundException cnfE) {
191: cnfE.printStackTrace();
192: }
193: }
194:
195: private static class EditorAreaComponent extends JPanel implements
196: TopComponentDroppable {
197:
198: private final EditorView editorView;
199:
200: // XXX PENDING
201: private final WindowDnDManager windowDnDManager;
202:
203: private Component areaComponent;
204:
205: public EditorAreaComponent(EditorView editorView,
206: WindowDnDManager windowDnDManager) {
207: this .editorView = editorView;
208: this .windowDnDManager = windowDnDManager;
209:
210: init();
211: }
212:
213: private void init() {
214: setLayout(new BorderLayout());
215: // special background for XP style
216: String lfID = UIManager.getLookAndFeel().getID();
217: // if (lfID.equals("Windows")) {
218: // setBackground((Color)UIManager.get("nb_workplace_fill"));
219: // }
220:
221: // PENDING Adding image into empty area.
222: String imageSource = Constants.SWITCH_IMAGE_SOURCE; // NOI18N
223: if (imageSource != null) {
224: Image image = Utilities.loadImage(imageSource);
225: if (image != null) {
226: JLabel label = new JLabel(new ImageIcon(image));
227: label.setMinimumSize(new Dimension(0, 0)); // XXX To be able shrink the area.
228: add(label, BorderLayout.CENTER);
229: } else {
230: Logger.getLogger(EditorView.class.getName())
231: .log(
232: Level.WARNING,
233: null,
234: new java.lang.NullPointerException(
235: "Image not found at "
236: + imageSource)); // NOI18N
237: }
238: }
239: //listen to files being dragged over the editor area
240: DropTarget dropTarget = new DropTarget(this ,
241: new DropTargetListener() {
242: public void dragEnter(DropTargetDragEvent dtde) {
243: }
244:
245: public void dragExit(DropTargetEvent dte) {
246: }
247:
248: public void dragOver(DropTargetDragEvent dtde) {
249: ExternalDropHandler handler = (ExternalDropHandler) Lookup
250: .getDefault().lookup(
251: ExternalDropHandler.class);
252: //check if a file is being dragged over and if anybody can process it
253: if (null != handler
254: && handler.canDrop(dtde)) {
255: dtde
256: .acceptDrag(DnDConstants.ACTION_COPY);
257: } else {
258: dtde.rejectDrag();
259: }
260: }
261:
262: public void drop(DropTargetDropEvent dtde) {
263: ExternalDropHandler handler = (ExternalDropHandler) Lookup
264: .getDefault().lookup(
265: ExternalDropHandler.class);
266: if (handler.canDrop(dtde)) {
267: //file is being dragged over
268: dtde
269: .acceptDrop(DnDConstants.ACTION_COPY);
270: //let the handler to take care of it
271: dtde.dropComplete(handler
272: .handleDrop(dtde));
273: } else {
274: dtde.dropComplete(false);
275: }
276: }
277:
278: public void dropActionChanged(
279: DropTargetDragEvent dtde) {
280: }
281: });
282: setDropTarget(dropTarget);
283: }
284:
285: public void setAreaComponent(Component areaComponent) {
286: if (this .areaComponent == areaComponent) {
287: // XXX PENDING revise how to better manipulate with components
288: // so there don't happen unneeded removals.
289: if (areaComponent != null
290: && !Arrays.asList(getComponents()).contains(
291: areaComponent)) {
292: add(areaComponent, BorderLayout.CENTER);
293: }
294:
295: return;
296: }
297:
298: if (this .areaComponent != null) {
299: remove(this .areaComponent);
300: }
301:
302: this .areaComponent = areaComponent;
303:
304: if (this .areaComponent != null) {
305: add(this .areaComponent, BorderLayout.CENTER);
306: }
307: }
308:
309: public Shape getIndicationForLocation(Point location) {
310: ModeImpl mode = (ModeImpl) WindowManagerImpl.getInstance()
311: .findMode(windowDnDManager.getStartingTransfer());
312: int kind = mode != null ? mode.getKind()
313: : Constants.MODE_KIND_EDITOR;
314:
315: if (kind == Constants.MODE_KIND_EDITOR) {
316: Rectangle rect = getBounds();
317: rect.setLocation(0, 0);
318: return rect;
319: } else {
320: Rectangle rect = getBounds();
321: rect.setLocation(0, 0);
322:
323: String side = getSideForLocation(location);
324:
325: double ratio = Constants.DROP_AROUND_RATIO;
326: if (Constants.TOP.equals(side)) {
327: return new Rectangle(0, 0, rect.width,
328: (int) (rect.height * ratio));
329: } else if (side == Constants.LEFT) {
330: return new Rectangle(0, 0,
331: (int) (rect.width * ratio), rect.height);
332: } else if (side == Constants.RIGHT) {
333: return new Rectangle(rect.width
334: - (int) (rect.width * ratio), 0,
335: (int) (rect.width * ratio), rect.height);
336: } else if (side == Constants.BOTTOM) {
337: return new Rectangle(0, rect.height
338: - (int) (rect.height * ratio), rect.width,
339: (int) (rect.height * ratio));
340: } else if (Constants.SWITCH_MODE_ADD_NO_RESTRICT
341: || WindowManagerImpl.getInstance()
342: .isTopComponentAllowedToMoveAnywhere(
343: windowDnDManager
344: .getStartingTransfer())) {
345: return rect;
346: } else {
347: return null;
348: }
349: }
350: };
351:
352: public Object getConstraintForLocation(Point location) {
353: ModeImpl mode = (ModeImpl) WindowManagerImpl.getInstance()
354: .findMode(windowDnDManager.getStartingTransfer());
355: int kind = mode != null ? mode.getKind()
356: : Constants.MODE_KIND_EDITOR;
357:
358: if (kind == Constants.MODE_KIND_EDITOR) {
359: return null;
360: } else {
361: return getSideForLocation(location);
362: }
363: }
364:
365: private String getSideForLocation(Point location) {
366: Rectangle bounds = getBounds();
367: bounds.setLocation(0, 0);
368:
369: // Size of area which indicates creation of new split.
370: int delta = Constants.DROP_AREA_SIZE;
371:
372: Rectangle top = new Rectangle(0, 0, bounds.width, delta);
373: if (top.contains(location)) {
374: return Constants.TOP;
375: }
376:
377: Rectangle left = new Rectangle(0, delta, delta,
378: bounds.height - 2 * delta);
379: if (left.contains(location)) {
380: return Constants.LEFT;
381: }
382:
383: Rectangle right = new Rectangle(bounds.width - delta,
384: delta, delta, bounds.height - 2 * delta);
385: if (right.contains(location)) {
386: return Constants.RIGHT;
387: }
388:
389: Rectangle bottom = new Rectangle(0, bounds.height - delta,
390: bounds.width, delta);
391: if (bottom.contains(location)) {
392: return Constants.BOTTOM;
393: }
394:
395: return null;
396: }
397:
398: public Component getDropComponent() {
399: return this ;
400: }
401:
402: public ViewElement getDropViewElement() {
403: return editorView;
404: }
405:
406: public boolean canDrop(TopComponent transfer, Point location) {
407: if (Constants.SWITCH_MODE_ADD_NO_RESTRICT
408: || WindowManagerImpl.getInstance()
409: .isTopComponentAllowedToMoveAnywhere(
410: transfer)) {
411: return true;
412: }
413:
414: ModeImpl mode = (ModeImpl) WindowManagerImpl.getInstance()
415: .findMode(transfer);
416: int kind = mode != null ? mode.getKind()
417: : Constants.MODE_KIND_EDITOR;
418:
419: if (kind == Constants.MODE_KIND_EDITOR) {
420: return true;
421: } else {
422: if (WindowManagerImpl.getInstance()
423: .getEditorAreaState() == Constants.EDITOR_AREA_JOINED
424: && getSideForLocation(location) != null) {
425: return true;
426: } else {
427: return false;
428: }
429: }
430: }
431:
432: public boolean supportsKind(int kind, TopComponent tc) {
433: return true;
434: }
435:
436: } // End of EditorAreaComponent class.
437:
438: }
|