Source Code Cross Referenced for TopComponentDragSupport.java in  » IDE-Netbeans » core » org » netbeans » core » windows » view » dnd » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Netbeans » core » org.netbeans.core.windows.view.dnd 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003:         *
0004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * The contents of this file are subject to the terms of either the GNU
0007:         * General Public License Version 2 only ("GPL") or the Common
0008:         * Development and Distribution License("CDDL") (collectively, the
0009:         * "License"). You may not use this file except in compliance with the
0010:         * License. You can obtain a copy of the License at
0011:         * http://www.netbeans.org/cddl-gplv2.html
0012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013:         * specific language governing permissions and limitations under the
0014:         * License.  When distributing the software, include this License Header
0015:         * Notice in each file and include the License file at
0016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
0017:         * particular file as subject to the "Classpath" exception as provided
0018:         * by Sun in the GPL Version 2 section of the License file that
0019:         * accompanied this code. If applicable, add the following below the
0020:         * License Header, with the fields enclosed by brackets [] replaced by
0021:         * your own identifying information:
0022:         * "Portions Copyrighted [year] [name of copyright owner]"
0023:         *
0024:         * Contributor(s):
0025:         *
0026:         * The Original Software is NetBeans. The Initial Developer of the Original
0027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028:         * Microsystems, Inc. All Rights Reserved.
0029:         *
0030:         * If you wish your version of this file to be governed by only the CDDL
0031:         * or only the GPL Version 2, indicate your decision by adding
0032:         * "[Contributor] elects to include this software in this distribution
0033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034:         * single choice of license, a recipient has the option to distribute
0035:         * your version of this file under either the CDDL, the GPL Version 2 or
0036:         * to extend the choice of license to its licensees as provided above.
0037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
0038:         * Version 2 license, then the option applies only if the new code is
0039:         * made subject to such option by the copyright holder.
0040:         */
0041:
0042:        package org.netbeans.core.windows.view.dnd;
0043:
0044:        import java.awt.AWTEvent;
0045:        import java.awt.Color;
0046:        import java.awt.Component;
0047:        import java.awt.Cursor;
0048:        import java.awt.Dialog;
0049:        import java.awt.Graphics2D;
0050:        import java.awt.GraphicsConfiguration;
0051:        import java.awt.GraphicsEnvironment;
0052:        import java.awt.Image;
0053:        import java.awt.Point;
0054:        import java.awt.Toolkit;
0055:        import java.awt.datatransfer.*;
0056:        import java.awt.dnd.*;
0057:        import java.awt.event.*;
0058:        import java.awt.image.BufferedImage;
0059:        import java.lang.ref.*;
0060:        import java.util.*;
0061:        import java.util.logging.Level;
0062:        import java.util.logging.Logger;
0063:        import javax.swing.*;
0064:        import org.netbeans.core.windows.*;
0065:        import org.netbeans.core.windows.view.ui.*;
0066:        import org.openide.util.*;
0067:        import org.openide.windows.TopComponent;
0068:
0069:        /**
0070:         * Window system drag support for <code>TopComponet</code>'s.
0071:         * It imitates role of drag gesture recognizer, possible
0072:         * on any kind of <code>Component</code>, currently on <code>Tabbed</code>.
0073:         * Starts also programatically the DnD for TopComponent in container
0074:         * when the starting gestures are Shift+Mouse Drag or Ctrl+Mouse Drag
0075:         * respectivelly.
0076:         * It serves as <code>DragSourceListener</code> during the DnD in progress
0077:         * and sets dragging cursor appopriatelly.
0078:         *
0079:         * <em>Note:</em> There is used only one singleton instance in window system
0080:         * DnD available via {@link #getDefault}.
0081:         *
0082:         *
0083:         * @author  Peter Zavadsky
0084:         *
0085:         * @see java awt.dnd.DragSourceListener
0086:         */
0087:        final class TopComponentDragSupport implements  AWTEventListener,
0088:                DragSourceListener, DragSourceMotionListener {
0089:
0090:            /** Mime type for <code>TopComponent</code> <code>DataFlavor</code>. */
0091:            public static final String MIME_TOP_COMPONENT = DataFlavor.javaJVMLocalObjectMimeType
0092:                    // Note: important is the space after semicolon, thus to match
0093:                    // when comparing.
0094:                    + "; class=org.openide.windows.TopComponent"; // NOI18N
0095:
0096:            /** Mime type for <code>TopComponent.Cloneable</code> <code>DataFlavor</code>. */
0097:            public static final String MIME_TOP_COMPONENT_CLONEABLE = DataFlavor.javaJVMLocalObjectMimeType
0098:                    + "; class=org.openide.windows.TopComponent$Cloneable"; // NOI18N
0099:
0100:            /** Mime type for <code>TopComponent</code>'s array <code>DataFlavor</code>. */
0101:            public static final String MIME_TOP_COMPONENT_ARRAY = DataFlavor.javaJVMLocalObjectMimeType
0102:                    + "; class=org.netbeans.core.windows.view.dnd.TopComponentDragSupport$TopComponentArray"; // NOI18N
0103:
0104:            /** 'Copy window' cursor type. */
0105:            private static final int CURSOR_COPY = 0;
0106:            /** 'Copy_No window' cursor type. */
0107:            private static final int CURSOR_COPY_NO = 1;
0108:            /** 'Move window' cursor type. */
0109:            private static final int CURSOR_MOVE = 2;
0110:            /** 'Move_No window' cursor type. */
0111:            private static final int CURSOR_MOVE_NO = 3;
0112:            /** Cursor type indicating there cannont be copy operation 
0113:             * done, but could be done move operation. In fact is
0114:             * the same like {@link #CURSOR_COPY_NO} with the diff name
0115:             * to be recognized correctly when switching action over drop target */
0116:            private static final int CURSOR_COPY_NO_MOVE = 4;
0117:            /** Move to free area cursor type */
0118:            private static final int CURSOR_MOVE_FREE = 5;
0119:
0120:            /** Name for 'Copy window' cursor. */
0121:            private static final String NAME_CURSOR_COPY = "CursorTopComponentCopy"; // NOI18N
0122:            /** Name for 'Copy_No window' cursor. */
0123:            private static final String NAME_CURSOR_COPY_NO = "CursorTopComponentCopyNo"; // NOI18N
0124:            /** Name for 'Move window' cursor. */
0125:            private static final String NAME_CURSOR_MOVE = "CursorTopComponentMove"; // NOI18N
0126:            /** Name for 'Move_No window' cursor. */
0127:            private static final String NAME_CURSOR_MOVE_NO = "CursorTopComponentMoveNo"; // NOI18N
0128:            /** */
0129:            private static final String NAME_CURSOR_COPY_NO_MOVE = "CursorTopComponentCopyNoMove"; // NOI18N
0130:            /** Name for cursor to drop to free area. */
0131:            private static final String NAME_CURSOR_MOVE_FREE = "CursorTopComponentMoveFree"; // NOI18N
0132:
0133:            /** Debugging flag. */
0134:            private static final boolean DEBUG = Debug
0135:                    .isLoggable(TopComponentDragSupport.class);
0136:
0137:            private final WindowDnDManager windowDnDManager;
0138:
0139:            /** Weak reference to <code>DragSourceContext</code> used in processed
0140:             * drag operation. Used for by fixing bugs while not passed correct
0141:             * order of events to <code>DragSourceListener</code>. */
0142:            private Reference<DragSourceContext> dragContextWRef = new WeakReference<DragSourceContext>(
0143:                    null);
0144:
0145:            /** Flag indicating the current window drag operation transferable
0146:             * can be 'copied', i.e. the dragged <code>TopComponent</code> is
0147:             * <code>TopComponent.Cloneable</code> instance. */
0148:            private boolean canCopy;
0149:
0150:            // #21918. There is not possible to indicate drop action in "free" desktop
0151:            // area. This field helps to workaround the problem.
0152:            /** Flag indicating user drop action. */
0153:            private int hackUserDropAction;
0154:
0155:            // #21918. Determine the ESC pressed.
0156:            /** Flag indicating the user has cancelled drag operation by pressing ESC key. */
0157:            private boolean hackESC;
0158:
0159:            /** Weak set of componens on which we listen for ESC key. */
0160:            private final Set keyObservers = new WeakSet(4);
0161:
0162:            private Point startingPoint;
0163:            private Component startingComponent;
0164:            private long startingTime;
0165:
0166:            private DragAndDropFeedbackVisualizer visualizer;
0167:
0168:            private boolean dropFailed = false;
0169:
0170:            /** Creates a new instance of TopComponentDragSupport. */
0171:            TopComponentDragSupport(WindowDnDManager windowDnDManager) {
0172:                this .windowDnDManager = windowDnDManager;
0173:            }
0174:
0175:            /** Informs whether the 'copy' operation is possible. Gets valid result
0176:             * during processed drag operation only.
0177:             * @return <code>true</code> if the drop copy operation is possible from
0178:             * drag source point of view
0179:             * @see #canCopy */
0180:            public boolean isCopyOperationPossible() {
0181:                return canCopy;
0182:            }
0183:
0184:            /** Simulates drag gesture recongition valid for winsys.
0185:             * Implements <code>AWTEventListener</code>. */
0186:            public void eventDispatched(AWTEvent evt) {
0187:                MouseEvent me = (MouseEvent) evt;
0188:                //#118828
0189:                if (!(evt.getSource() instanceof  Component)) {
0190:                    return;
0191:                }
0192:
0193:                // #40736: only left mouse button drag should start DnD
0194:                if ((me.getID() == MouseEvent.MOUSE_PRESSED)
0195:                        && SwingUtilities.isLeftMouseButton(me)) {
0196:                    startingPoint = me.getPoint();
0197:                    startingComponent = me.getComponent();
0198:                    startingTime = me.getWhen();
0199:                } else if (me.getID() == MouseEvent.MOUSE_RELEASED) {
0200:                    startingPoint = null;
0201:                    startingComponent = null;
0202:                }
0203:
0204:                if (evt.getID() != MouseEvent.MOUSE_DRAGGED) {
0205:                    return;
0206:                }
0207:                if (windowDnDManager.isDragging()) {
0208:                    return;
0209:                }
0210:                if (startingPoint == null) {
0211:                    return;
0212:                }
0213:                if (evt.getSource() instanceof  JButton) {
0214:                    //do not initiate topcomponent drag when the mouse is dragged out of a tabcontrol button
0215:                    return;
0216:                }
0217:                if (!WindowDnDManager.isDnDEnabled()) {
0218:                    return;
0219:                }
0220:
0221:                Component srcComp = startingComponent;
0222:                if (srcComp == null) {
0223:                    return;
0224:                }
0225:
0226:                final Point point = new Point(startingPoint);
0227:                Point currentPoint = me.getPoint();
0228:                Component currentComponent = me.getComponent();
0229:                if (currentComponent == null) {
0230:                    return;
0231:                }
0232:                currentPoint = SwingUtilities.convertPoint(currentComponent,
0233:                        currentPoint, srcComp);
0234:                if (Math.abs(currentPoint.x - point.x) <= Constants.DRAG_GESTURE_START_DISTANCE
0235:                        && Math.abs(currentPoint.y - point.y) <= Constants.DRAG_GESTURE_START_DISTANCE) {
0236:                    return;
0237:                }
0238:                // time check, to prevent wild mouse clicks to be considered DnD start
0239:                if (me.getWhen() - startingTime <= Constants.DRAG_GESTURE_START_TIME) {
0240:                    return;
0241:                }
0242:                startingPoint = null;
0243:                startingComponent = null;
0244:
0245:                if (DEBUG) {
0246:                    debugLog(""); // NOI18N
0247:                    debugLog("eventDispatched (MOUSE_DRAGGED)"); // NOI18N
0248:                }
0249:
0250:                // XXX Do not clash with JTree (e.g. in explorer) drag.
0251:                if ((srcComp instanceof  JTree)
0252:                        && ((JTree) srcComp).getPathForLocation(me.getX(), me
0253:                                .getY()) != null) {
0254:                    return;
0255:                }
0256:
0257:                // #22622: AWT listener just passivelly listnens what is happenning around,
0258:                // and we need always the deepest component to start from.
0259:                srcComp = SwingUtilities.getDeepestComponentAt(srcComp,
0260:                        point.x, point.y);
0261:
0262:                boolean ctrlDown = me.isControlDown();
0263:
0264:                TopComponent tc = null;
0265:                Tabbed tabbed;
0266:
0267:                if (srcComp instanceof  Tabbed) {
0268:                    tabbed = (Tabbed) srcComp;
0269:                } else {
0270:                    tabbed = (Tabbed) SwingUtilities.getAncestorOfClass(
0271:                            Tabbed.class, srcComp);
0272:                }
0273:                if (tabbed == null) {
0274:                    if (srcComp instanceof  Tabbed.Accessor) {
0275:                        tabbed = ((Tabbed.Accessor) srcComp).getTabbed();
0276:                    } else {
0277:                        Tabbed.Accessor acc = (Tabbed.Accessor) SwingUtilities
0278:                                .getAncestorOfClass(Tabbed.Accessor.class,
0279:                                        srcComp);
0280:                        tabbed = acc != null ? acc.getTabbed() : null;
0281:                    }
0282:                }
0283:                if (tabbed == null) {
0284:                    return;
0285:                }
0286:
0287:                Point ppp = new Point(point);
0288:                Point p = SwingUtilities.convertPoint(srcComp, ppp, tabbed
0289:                        .getComponent());
0290:
0291:                // #106761: tabForCoordinate may return -1, so check is needed
0292:                int tabIndex = tabbed.tabForCoordinate(p);
0293:                tc = tabIndex != -1 ? tabbed.getTopComponentAt(tabIndex) : null;
0294:                if (tc == null) {
0295:                    return;
0296:                }
0297:
0298:                // #21918. See above.
0299:                if (ctrlDown) {
0300:                    hackUserDropAction = DnDConstants.ACTION_COPY;
0301:                } else {
0302:                    hackUserDropAction = DnDConstants.ACTION_MOVE;
0303:                }
0304:
0305:                List<MouseEvent> list = new ArrayList<MouseEvent>();
0306:                list.add(me);
0307:
0308:                // Get start droppable (if there) and its starting point.
0309:                TopComponentDroppable startDroppable = (TopComponentDroppable) SwingUtilities
0310:                        .getAncestorOfClass(TopComponentDroppable.class, tc);
0311:                Point startPoint;
0312:                if (startDroppable == null) {
0313:                    startDroppable = (TopComponentDroppable) SwingUtilities
0314:                            .getAncestorOfClass(TopComponentDroppable.class,
0315:                                    tabbed.getComponent());
0316:                }
0317:                if (startDroppable != null) {
0318:                    startPoint = point;
0319:                    Point pp = new Point(point);
0320:                    startPoint = SwingUtilities.convertPoint(srcComp, pp,
0321:                            (Component) startDroppable);
0322:                } else {
0323:                    startPoint = null;
0324:                }
0325:                //dragSource.startDrag(event, Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR) ,image , new Point(-offX, -offY),text, this);
0326:
0327:                doStartDrag(srcComp, tc, new DragGestureEvent(
0328:                        new FakeDragGestureRecognizer(windowDnDManager, me),
0329:                        hackUserDropAction, point, list), startDroppable,
0330:                        startPoint);
0331:            }
0332:
0333:            /** Actually starts the drag operation. */
0334:            private void doStartDrag(Component startingComp, Object transfer,
0335:                    DragGestureEvent evt,
0336:                    TopComponentDroppable startingDroppable,
0337:                    final Point startingPoint) {
0338:                if (DEBUG) {
0339:                    debugLog(""); // NOI18N
0340:                    debugLog("doStartDrag"); // NOI18N
0341:                }
0342:                final TopComponent firstTC = transfer instanceof  TopComponent ? (TopComponent) transfer
0343:                        : (((TopComponent[]) transfer)[0]);
0344:
0345:                // #22132. If in modal dialog no drag allowed.
0346:                Dialog dlg = (Dialog) SwingUtilities.getAncestorOfClass(
0347:                        Dialog.class, firstTC);
0348:                if (dlg != null && dlg.isModal()) {
0349:                    return;
0350:                }
0351:
0352:                if (firstTC instanceof  TopComponent.Cloneable) {
0353:                    canCopy = true;
0354:                } else {
0355:                    canCopy = false;
0356:                }
0357:
0358:                // Inform window sys there is DnD about to start.
0359:                // XXX Using the firstTC in DnD manager is a hack.
0360:                windowDnDManager.dragStarting(startingDroppable, startingPoint,
0361:                        firstTC);
0362:
0363:                Cursor cursor = hackUserDropAction == DnDConstants.ACTION_MOVE ? getDragCursor(
0364:                        startingComp, CURSOR_MOVE)
0365:                        : (canCopy ? getDragCursor(startingComp, CURSOR_COPY)
0366:                                : getDragCursor(startingComp,
0367:                                        CURSOR_COPY_NO_MOVE));
0368:
0369:                // Sets listnening for ESC key.
0370:                addListening();
0371:                hackESC = false;
0372:
0373:                Tabbed tabbed = (Tabbed) SwingUtilities.getAncestorOfClass(
0374:                        Tabbed.class, startingComp);
0375:                if (tabbed == null) {
0376:                    Tabbed.Accessor acc = (Tabbed.Accessor) SwingUtilities
0377:                            .getAncestorOfClass(Tabbed.Accessor.class,
0378:                                    startingComp);
0379:                    tabbed = acc != null ? acc.getTabbed() : null;
0380:                }
0381:
0382:                int tabIndex = -1;
0383:                Image img = createDragImage();
0384:                if (tabbed != null) {//&& Constants.SWITCH_USE_DRAG_IMAGES) {
0385:                    tabIndex = tabbed.indexOf(firstTC);
0386:
0387:                    visualizer = new DragAndDropFeedbackVisualizer(tabbed,
0388:                            tabIndex);
0389:                }
0390:                try {
0391:
0392:                    evt
0393:                            .startDrag(
0394:                                    cursor,
0395:                                    img,
0396:                                    new Point(0, 0),
0397:                                    (transfer instanceof  TopComponent ? (Transferable) new TopComponentTransferable(
0398:                                            (TopComponent) transfer)
0399:                                            : (Transferable) new TopComponentArrayTransferable(
0400:                                                    (TopComponent[]) transfer)),
0401:                                    this );
0402:                    evt.getDragSource().addDragSourceMotionListener(this );
0403:
0404:                    if (null != visualizer) {
0405:                        visualizer.start(evt);
0406:                    }
0407:
0408:                } catch (InvalidDnDOperationException idoe) {
0409:                    Logger.getLogger(TopComponentDragSupport.class.getName())
0410:                            .log(Level.WARNING, null, idoe);
0411:
0412:                    removeListening();
0413:                    windowDnDManager.resetDragSource();
0414:                    if (null != visualizer) {
0415:                        visualizer.dispose(false);
0416:                        visualizer = null;
0417:                    }
0418:                }
0419:            }
0420:
0421:            private AWTEventListener keyListener = new AWTEventListener() {
0422:                public void eventDispatched(AWTEvent event) {
0423:                    KeyEvent keyevent = (KeyEvent) event;
0424:
0425:                    if (keyevent.getID() == KeyEvent.KEY_RELEASED
0426:                            && keyevent.getKeyCode() == KeyEvent.VK_ESCAPE) {
0427:                        hackESC = true;
0428:                    }
0429:                }
0430:
0431:            };
0432:
0433:            /** Adds <code>KeyListener</code> to container and its component
0434:             * hierarchy to listen for ESC key. */
0435:            private void addListening() {
0436:                Toolkit.getDefaultToolkit().addAWTEventListener(keyListener,
0437:                        AWTEvent.KEY_EVENT_MASK);
0438:            }
0439:
0440:            /** Removes ESC listening. Helper method. */
0441:            private void removeListening() {
0442:                Toolkit.getDefaultToolkit().removeAWTEventListener(keyListener);
0443:            }
0444:
0445:            // >> DragSourceListener implementation >>
0446:            /** Implements <code>DragSourceListener</code> method.
0447:             * It just refreshes the weak reference of <code>DragSourceContext</code>
0448:             * for the sake of setSuccessCursor method.
0449:             * The excpected code, changing of cursor, is done in setSuccessCursor method
0450:             * due to an undeterministic calls of this method especially in MDI mode.
0451:             * @see #setSuccessCursor */
0452:            public void dragEnter(DragSourceDragEvent evt) {
0453:                if (DEBUG) {
0454:                    debugLog(""); // NOI18N
0455:                    debugLog("dragEnter");// NOI18N
0456:                }
0457:
0458:                // Just refresh the weak ref to the context if necessary.
0459:                // The expected code here is done by ragExitHack method called from DropTarget's.
0460:                if (dragContextWRef.get() == null) {
0461:                    dragContextWRef = new java.lang.ref.WeakReference<DragSourceContext>(
0462:                            evt.getDragSourceContext());
0463:                }
0464:            }
0465:
0466:            /** Dummy implementation of <code>DragSourceListener</code> method. */
0467:            public void dragOver(DragSourceDragEvent evt) {
0468:                if (DEBUG) {
0469:                    debugLog(""); // NOI18N
0470:                    debugLog("dragOver"); // NOI18N
0471:                }
0472:            }
0473:
0474:            /** Implements <code>DragSourceListener</code> method.
0475:             * It just refreshes the weak reference of <code>DragSourceContext</code>
0476:             * for the sake of setUnsuccessCursor method.
0477:             * The excpected code, changing of cursor, is done in setUnsuccessCursor method
0478:             * due to an undeterministic calls of this method especially in MDI mode.
0479:             * @see #setUnsuccessCursor */
0480:            public void dragExit(DragSourceEvent evt) {
0481:                if (DEBUG) {
0482:                    debugLog(""); // NOI18N
0483:                    debugLog("dragExit"); // NOI18N
0484:                }
0485:
0486:                // Just refresh the weak ref to the context if necessary.
0487:                // The expected code here is done by ragExitHack method called from DropTarget's.
0488:                if (dragContextWRef.get() == null) {
0489:                    dragContextWRef = new WeakReference<DragSourceContext>(evt
0490:                            .getDragSourceContext());
0491:                }
0492:            }
0493:
0494:            /** Implements <code>DragSourceListener</code> method.
0495:             * It changes the cursor type from copy to move and bakc accordting the
0496:             * user action. */
0497:            public void dropActionChanged(DragSourceDragEvent evt) {
0498:                if (DEBUG) {
0499:                    debugLog(""); // NOI18N
0500:                    debugLog("dropActionChanged"); // NOI18N
0501:                }
0502:                String name = evt.getDragSourceContext().getCursor().getName();
0503:
0504:                if (name == null) {
0505:                    // Not our cursor??
0506:                    return;
0507:                }
0508:
0509:                // For us is the user action important.
0510:                int userAction = evt.getUserAction();
0511:
0512:                // Consider NONE action as MOVE one.
0513:                if (userAction == DnDConstants.ACTION_NONE) {
0514:                    userAction = DnDConstants.ACTION_MOVE;
0515:                }
0516:                // #21918. See above.
0517:                hackUserDropAction = userAction;
0518:
0519:                int type;
0520:                if ((NAME_CURSOR_COPY.equals(name) || NAME_CURSOR_COPY_NO_MOVE
0521:                        .equals(name))
0522:                        && userAction == DnDConstants.ACTION_MOVE) {
0523:                    type = CURSOR_MOVE;
0524:                } else if (NAME_CURSOR_COPY_NO.equals(name)
0525:                        && userAction == DnDConstants.ACTION_MOVE) {
0526:                    type = CURSOR_MOVE_NO;
0527:                } else if (NAME_CURSOR_MOVE.equals(name)
0528:                        && userAction == DnDConstants.ACTION_COPY) {
0529:                    type = CURSOR_COPY;
0530:                } else if (NAME_CURSOR_MOVE_NO.equals(name)
0531:                        && userAction == DnDConstants.ACTION_COPY) {
0532:                    type = CURSOR_COPY_NO;
0533:                } else {
0534:                    return;
0535:                }
0536:
0537:                // There can't be copy operation performed,
0538:                // transferreed TopComponent in not of TopComponent.Cloneable instance.
0539:                if (type == CURSOR_COPY && !canCopy) {
0540:                    type = CURSOR_COPY_NO_MOVE;
0541:                }
0542:
0543:                // Check if there is already our cursor.
0544:                if (getDragCursorName(type).equals(
0545:                        evt.getDragSourceContext().getCursor().getName())) {
0546:                    return;
0547:                }
0548:
0549:                evt.getDragSourceContext()
0550:                        .setCursor(
0551:                                getDragCursor(evt.getDragSourceContext()
0552:                                        .getComponent(), type));
0553:            }
0554:
0555:            /** Implements <code>DragSourceListener</code> method.
0556:             * Informs window dnd manager the drag operation finished.
0557:             * @see WindowDnDManager#dragFinished */
0558:            public void dragDropEnd(final DragSourceDropEvent evt) {
0559:                if (DEBUG) {
0560:                    debugLog(""); // NOI18N
0561:                    debugLog("dragDropEnd"); // NOI18N
0562:                }
0563:
0564:                try {
0565:                    if (checkDropSuccess(evt)) {
0566:                        windowDnDManager.dragFinished();
0567:
0568:                        removeListening();
0569:                        return;
0570:                    }
0571:
0572:                    // Now simulate drop into "free" desktop area.
0573:                    final Set<Component> floatingFrames = windowDnDManager
0574:                            .getFloatingFrames();
0575:                    // Finally schedule the "drop" task later to be able to
0576:                    // detect if ESC was pressed.
0577:                    RequestProcessor.getDefault().post(new Runnable() {
0578:                        public void run() {
0579:                            SwingUtilities
0580:                                    .invokeLater(createDropIntoFreeAreaTask(
0581:                                            evt, evt.getLocation(),
0582:                                            floatingFrames));
0583:                        }
0584:                    }, 250 // XXX #21918, Neccessary to skip after possible ESC key event.
0585:                            );
0586:                } finally {
0587:                    windowDnDManager.dragFinishedEx();
0588:                }
0589:            }
0590:
0591:            // << DragSourceListener implementation <<
0592:
0593:            /** Checks whether there was a successfull drop. */
0594:            private boolean checkDropSuccess(DragSourceDropEvent evt) {
0595:                // XXX #21917.
0596:                if (windowDnDManager.isDropSuccess()) {
0597:                    return true;
0598:                }
0599:
0600:                // Gets location.
0601:                Point location = evt.getLocation();
0602:                if (location == null) {
0603:                    return true;
0604:                }
0605:
0606:                if (WindowDnDManager.isInMainWindow(location)
0607:                        || windowDnDManager.isInFloatingFrame(location)
0608:                        || WindowDnDManager.isAroundCenterPanel(location)) {
0609:                    return false;
0610:                }
0611:                //        else if(evt.getDropSuccess()) {
0612:                //            return true;
0613:                //        } // PENDING it seem it is not working correctly (at least on linux).
0614:                return false;
0615:            }
0616:
0617:            /** Creates task which performs actual drop into "free area", i.e. it
0618:             * creates new separated (floating) window. */
0619:            private Runnable createDropIntoFreeAreaTask(
0620:                    final DragSourceDropEvent evt, final Point location,
0621:                    final Set<Component> floatingFrames) {
0622:                return new Runnable() {
0623:                    public void run() {
0624:                        // XXX #21918. Don't move the check sooner
0625:                        // (before the enclosing blocks), it would be invalid.
0626:                        if (hackESC) {
0627:                            windowDnDManager.dragFinished();
0628:                            removeListening();
0629:                            return;
0630:                        }
0631:
0632:                        TopComponent[] tcArray = WindowDnDManager
0633:                                .extractTopComponent(false, evt
0634:                                        .getDragSourceContext()
0635:                                        .getTransferable());
0636:
0637:                        // Provide actual drop into "free" desktop area.
0638:                        if (tcArray != null) {
0639:                            // XXX there is a problem if jdk dnd framework sets as drop action
0640:                            // ACTION_NONE, there is not called drop event on DropTargetListener,
0641:                            // even it is there.
0642:                            // Performs hacked drop action, simulates ACTION_MOVE when
0643:                            // system set ACTION_NONE (which we do not use).
0644:                            boolean res = windowDnDManager.tryPerformDrop(
0645:                                    windowDnDManager.getController(),
0646:                                    floatingFrames, location,
0647:                                    DnDConstants.ACTION_MOVE, // MOVE only
0648:                                    evt.getDragSourceContext()
0649:                                            .getTransferable());
0650:
0651:                        }
0652:                        windowDnDManager.dragFinished();
0653:                    }
0654:                };
0655:            }
0656:
0657:            /** Hacks problems with <code>dragEnter</code> wrong method calls.
0658:             * It plays its role. Sets the cursor from 'no-drop' state
0659:             * to its 'drop' state sibling.
0660:             * @param freeArea true when mouse pointer in free screen area
0661:             * @see #dragEnter */
0662:            void setSuccessCursor(boolean freeArea) {
0663:                int dropAction = hackUserDropAction;
0664:                DragSourceContext ctx = dragContextWRef.get();
0665:
0666:                if (ctx == null) {
0667:                    return;
0668:                }
0669:
0670:                if (null != visualizer)
0671:                    visualizer.setDropFeedback(true);
0672:
0673:                dropFailed = false;
0674:
0675:                //        int type;
0676:                //        if(dropAction == DnDConstants.ACTION_MOVE) {
0677:                //            type = freeArea ? CURSOR_MOVE_FREE : CURSOR_MOVE;
0678:                //        } else if(dropAction == DnDConstants.ACTION_COPY) {
0679:                //            if(canCopy) {
0680:                //                type = CURSOR_COPY;
0681:                //            } else {
0682:                //                type = CURSOR_COPY_NO_MOVE;
0683:                //            }
0684:                //        } else {
0685:                //            // PENDING throw exception?
0686:                //            Logger.getLogger(TopComponentDragSupport.class.getName()).log(Level.WARNING, null,
0687:                //                              new java.lang.IllegalStateException("Invalid action type->" +
0688:                //                                                                  dropAction)); // NOI18N
0689:                //            return;
0690:                //        }
0691:                //
0692:                //        // Check if there is already our cursor.
0693:                //        if(getDragCursorName(type).equals(ctx.getCursor().getName())) {
0694:                //            return;
0695:                //        }
0696:                //
0697:                //        ctx.setCursor(getDragCursor(ctx.getComponent(),type));
0698:            }
0699:
0700:            /** Hacks problems with <code>dragExit</code> wrong method calls.
0701:             * It plays its role. Sets the cursor from 'drop' state
0702:             * to its 'no-drop' state sibling.
0703:             * @see #dragExit */
0704:            void setUnsuccessCursor() {
0705:                DragSourceContext ctx = dragContextWRef.get();
0706:
0707:                if (ctx == null) {
0708:                    return;
0709:                }
0710:
0711:                if (null != visualizer)
0712:                    visualizer.setDropFeedback(false);
0713:
0714:                String name = ctx.getCursor().getName();
0715:
0716:                dropFailed = true;
0717:
0718:                //        int type;
0719:                //        if(NAME_CURSOR_COPY.equals(name)
0720:                //        || NAME_CURSOR_COPY_NO_MOVE.equals(name)) {
0721:                //            type = CURSOR_COPY_NO;
0722:                //        } else if(NAME_CURSOR_MOVE.equals(name) || NAME_CURSOR_MOVE_NO.equals(name)) {
0723:                //            type = CURSOR_MOVE_NO;
0724:                //        } else {
0725:                //            return;
0726:                //        }
0727:                //
0728:                //        ctx.setCursor(getDragCursor(ctx.getComponent(),type));
0729:            }
0730:
0731:            /** Provides cleanup when finished drag operation. Ideally the code
0732:             * should reside in {@ling #dragDropEnd} method only. But that one
0733:             * is not called in case of error in DnD framework. */
0734:            void dragFinished() {
0735:                dragContextWRef = new WeakReference<DragSourceContext>(null);
0736:                if (null != visualizer) {
0737:                    visualizer.dispose(!(dropFailed || hackESC));
0738:                    dropFailed = false;
0739:                    visualizer = null;
0740:                }
0741:            }
0742:
0743:            private static void debugLog(String message) {
0744:                Debug.log(TopComponentDragSupport.class, message);
0745:            }
0746:
0747:            // Helpers>>
0748:            /** Gets window drag <code>Cursor</code> of specified type. Utility method.
0749:             * @param type valid one of {@link #CURSOR_COPY}, {@link #CURSOR_COPY_NO}, 
0750:             *             {@link #CURSOR_MOVE}, {@link #CURSOR_MOVE_NO}, {@link #CURSOR_MOVE_FREE} */
0751:            private static String getDragCursorName(int type) {
0752:                if (type == CURSOR_COPY) {
0753:                    return NAME_CURSOR_COPY;
0754:                } else if (type == CURSOR_COPY_NO) {
0755:                    return NAME_CURSOR_COPY_NO;
0756:                } else if (type == CURSOR_MOVE) {
0757:                    return NAME_CURSOR_MOVE;
0758:                } else if (type == CURSOR_MOVE_NO) {
0759:                    return NAME_CURSOR_MOVE_NO;
0760:                } else if (type == CURSOR_COPY_NO_MOVE) {
0761:                    return NAME_CURSOR_COPY_NO_MOVE;
0762:                } else if (type == CURSOR_MOVE_FREE) {
0763:                    return NAME_CURSOR_MOVE_FREE;
0764:                } else {
0765:                    return null;
0766:                }
0767:            }
0768:
0769:            /** Gets window drag <code>Cursor</code> of specified type. Utility method.
0770:             * @param type valid one of {@link #CURSOR_COPY}, {@link #CURSOR_COPY_NO}, 
0771:             *             {@link #CURSOR_MOVE}, {@link #CURSOR_MOVE_NO}, {@link #CURSOR_MOVE_FREE}
0772:             * @exception IllegalArgumentException if invalid type parameter passed in */
0773:            private static Cursor getDragCursor(Component comp, int type) {
0774:                Image image = null;
0775:                String name = null;
0776:
0777:                if (type == CURSOR_COPY) {
0778:                    image = Utilities
0779:                            .loadImage("org/netbeans/core/resources/topComponentDragCopy.gif"); // NOI18N
0780:                    name = NAME_CURSOR_COPY;
0781:                } else if (type == CURSOR_COPY_NO) {
0782:                    image = Utilities
0783:                            .loadImage("org/netbeans/core/resources/topComponentDragCopyNo.gif"); // NOI18N
0784:                    name = NAME_CURSOR_COPY_NO;
0785:                } else if (type == CURSOR_MOVE) {
0786:                    image = Utilities
0787:                            .loadImage("org/netbeans/core/resources/topComponentDragMove.gif"); // NOI18N
0788:                    name = NAME_CURSOR_MOVE;
0789:                } else if (type == CURSOR_MOVE_NO) {
0790:                    image = Utilities
0791:                            .loadImage("org/netbeans/core/resources/topComponentDragMoveNo.gif"); // NOI18N
0792:                    name = NAME_CURSOR_MOVE_NO;
0793:                } else if (type == CURSOR_COPY_NO_MOVE) {
0794:                    image = Utilities
0795:                            .loadImage("org/netbeans/core/resources/topComponentDragCopyNo.gif"); // NOI18N
0796:                    name = NAME_CURSOR_COPY_NO_MOVE;
0797:                } else if (type == CURSOR_MOVE_FREE) {
0798:                    image = Utilities
0799:                            .loadImage("org/netbeans/core/windows/resources/topComponentDragMoveFreeArea.gif"); // NOI18N
0800:                    name = NAME_CURSOR_MOVE_FREE;
0801:                } else {
0802:                    throw new IllegalArgumentException("Unknown cursor type="
0803:                            + type); // NOI18N
0804:                }
0805:
0806:                return Utilities.createCustomCursor(comp, image, name);
0807:            }
0808:
0809:            // Helpers<<
0810:
0811:            /** <code>Transferable</code> used for <code>TopComponent</code> instances
0812:             * to be used in window system DnD. */
0813:            private static class TopComponentTransferable extends Object
0814:                    implements  Transferable {
0815:
0816:                // #86564: Hold TopComponent weakly to workaround AWT bug #6555816
0817:                /** <code>TopComponent</code> to be transferred. */
0818:                private WeakReference<TopComponent> weakTC;
0819:
0820:                /** Crates <code>Transferable</code> for specified <code>TopComponent</code> */
0821:                public TopComponentTransferable(TopComponent tc) {
0822:                    this .weakTC = new WeakReference<TopComponent>(tc);
0823:                }
0824:
0825:                // >> Transferable implementation >>
0826:                /** Implements <code>Transferable</code> method.
0827:                 * @return <code>TopComponent</code> instance for <code>DataFlavor</code>
0828:                 * with mimetype equal to {@link #MIME_TOP_COMPONENT} or if mimetype
0829:                 * equals to {@link #MIME_CLONEABLE_TOP_COMPONENT} and the top component
0830:                 * is instance of <code>TopComponent.Cloneable</code> returns the instance */
0831:                public Object getTransferData(DataFlavor df) {
0832:                    TopComponent tc = weakTC.get();
0833:                    if (MIME_TOP_COMPONENT.equals(df.getMimeType())) {
0834:                        return tc;
0835:                    } else if (MIME_TOP_COMPONENT_CLONEABLE.equals(df
0836:                            .getMimeType())
0837:                            && tc instanceof  TopComponent.Cloneable) {
0838:                        return tc;
0839:                    }
0840:
0841:                    return null;
0842:                }
0843:
0844:                /** Implements <code>Transferable</code> method.
0845:                 * @return Array of <code>DataFlavor</code> with mimetype
0846:                 * {@link #MIME_TOP_COMPONENT} and also with mimetype
0847:                 * {@link #MIME_CLONEABLE_TOP_COMPONENT}
0848:                 * if the <code>tc</code> is instance
0849:                 * of <code>TopComponent.Cloneable</code> */
0850:                public DataFlavor[] getTransferDataFlavors() {
0851:                    try {
0852:                        TopComponent tc = weakTC.get();
0853:                        if (tc instanceof  TopComponent.Cloneable) {
0854:                            return new DataFlavor[] {
0855:                                    new DataFlavor(MIME_TOP_COMPONENT, null,
0856:                                            TopComponent.class.getClassLoader()),
0857:                                    new DataFlavor(
0858:                                            MIME_TOP_COMPONENT_CLONEABLE, null,
0859:                                            TopComponent.Cloneable.class
0860:                                                    .getClassLoader()) };
0861:                        } else {
0862:                            return new DataFlavor[] { new DataFlavor(
0863:                                    MIME_TOP_COMPONENT, null,
0864:                                    TopComponent.class.getClassLoader()) };
0865:                        }
0866:                    } catch (ClassNotFoundException ex) {
0867:                        Logger.getLogger(
0868:                                TopComponentDragSupport.class.getName()).log(
0869:                                Level.WARNING, ex.getMessage(), ex);
0870:                    }
0871:                    return new DataFlavor[0];
0872:                }
0873:
0874:                /** Implements <code>Transferable</code> method.
0875:                 * @return <code>true</code> for <code>DataFlavor</code> with mimetype
0876:                 * equal to {@link #MIME_TOP_COMPONENT}
0877:                 * and if <code>tc</code> is instance
0878:                 * of <code>TopComponent.Cloneable</code> also for the one
0879:                 * with mimetype {@link #MIME_TOP_COMPONENT_CLONEABLE},
0880:                 * <code>false</code> otherwise */
0881:                public boolean isDataFlavorSupported(DataFlavor df) {
0882:                    TopComponent tc = weakTC.get();
0883:                    if (MIME_TOP_COMPONENT.equals(df.getMimeType())) {
0884:                        return true;
0885:                    } else if (MIME_TOP_COMPONENT_CLONEABLE.equals(df
0886:                            .getMimeType())
0887:                            && tc instanceof  TopComponent.Cloneable) {
0888:                        return true;
0889:                    }
0890:
0891:                    return false;
0892:                }
0893:                // << Transferable implementation <<
0894:            } // End of class TopComponentTransferable.
0895:
0896:            /** <code>Transferable</code> used for <code>TopComponent</code> instances
0897:             * to be used in window system DnD. */
0898:            private static class TopComponentArrayTransferable extends Object
0899:                    implements  Transferable {
0900:
0901:                // #86564: Hold TopComponents weakly to workaround AWT bug #6555816
0902:                /** <code>TopComponent</code> to be transferred. */
0903:                private List<WeakReference<TopComponent>> weakTCList;
0904:
0905:                /** Crates <code>Transferable</code> for specified <code>TopComponent</code> */
0906:                public TopComponentArrayTransferable(TopComponent[] tcArray) {
0907:                    this .weakTCList = new ArrayList<WeakReference<TopComponent>>();
0908:                    for (TopComponent topComponent : tcArray) {
0909:                        weakTCList.add(new WeakReference<TopComponent>(
0910:                                topComponent));
0911:                    }
0912:                }
0913:
0914:                // >> Transferable implementation >>
0915:                /** Implements <code>Transferable</code> method.
0916:                 * @return <code>TopComponent</code> instance for <code>DataFlavor</code>
0917:                 * with mimetype equal to {@link #MIME_TOP_COMPONENT}
0918:                 * or if mimetype equals to
0919:                 * {@link #MIME_CLONEABLE_TOP_COMPONENT} and
0920:                 * the top component is instance
0921:                 * of <code>TopComponent.Cloneable</code> returns the instance. */
0922:                public Object getTransferData(DataFlavor df) {
0923:                    if (MIME_TOP_COMPONENT_ARRAY.equals(df.getMimeType())) {
0924:                        List<TopComponent> tcList = new ArrayList<TopComponent>(
0925:                                weakTCList.size());
0926:                        TopComponent curTC = null;
0927:                        for (WeakReference<TopComponent> weakTC : weakTCList) {
0928:                            curTC = weakTC.get();
0929:                            if (curTC != null) {
0930:                                tcList.add(curTC);
0931:                            }
0932:                        }
0933:                    }
0934:                    return null;
0935:                }
0936:
0937:                /** Implements <code>Transferable</code> method.
0938:                 * @return Array of <code>DataFlavor</code> with mimetype
0939:                 * {@link #MIME_TOP_COMPONENT} and also with mimetype
0940:                 * {@link #MIME_CLONEABLE_TOP_COMPONENT}
0941:                 * if the <code>tc</code> is 
0942:                 * instance of <code>TopComponent.Cloneable</code> */
0943:                public DataFlavor[] getTransferDataFlavors() {
0944:                    try {
0945:                        return new DataFlavor[] { new DataFlavor(
0946:                                MIME_TOP_COMPONENT_ARRAY, null,
0947:                                TopComponent.class.getClassLoader()) };
0948:                    } catch (ClassNotFoundException ex) {
0949:                        Logger.getLogger(
0950:                                TopComponentDragSupport.class.getName()).log(
0951:                                Level.WARNING, ex.getMessage(), ex);
0952:                    }
0953:                    return new DataFlavor[0];
0954:                }
0955:
0956:                /** Implements <code>Transferable</code> method.
0957:                 * @return <code>true</code> for <code>DataFlavor</code> with mimetype
0958:                 * equal to {@link #MIME_TOP_COMPONENT}
0959:                 * and if <code>tc</code> is instance
0960:                 * of <code>TopComponent.Cloneable</code> also for the one
0961:                 * with mimetype {@link #MIME_TOP_COMPONENT_CLONEABLE},
0962:                 * <code>false</code> otherwise. */
0963:                public boolean isDataFlavorSupported(DataFlavor df) {
0964:                    if (MIME_TOP_COMPONENT_ARRAY.equals(df.getMimeType())) {
0965:                        return true;
0966:                    }
0967:
0968:                    return false;
0969:                }
0970:                // << Transferable implementation <<
0971:            } // End of class TopComponentArrayTransferable.
0972:
0973:            /** Fake <code>DragGestureRecognizer</code> used when starting
0974:             * DnD programatically. */
0975:            private static class FakeDragGestureRecognizer extends
0976:                    DragGestureRecognizer {
0977:
0978:                /** Constructs <code>FakeDragGestureRecpgnizer</code>.
0979:                 * @param evt trigger event */
0980:                public FakeDragGestureRecognizer(
0981:                        WindowDnDManager windowDnDManager, MouseEvent evt) {
0982:                    super (windowDnDManager.getWindowDragSource(),
0983:                            (Component) evt.getSource(),
0984:                            DnDConstants.ACTION_COPY_OR_MOVE, null);
0985:
0986:                    appendEvent(evt);
0987:                }
0988:
0989:                /** Dummy implementation of superclass abstract method. */
0990:                public void registerListeners() {
0991:                }
0992:
0993:                /** Dummy implementation of superclass abstract method. */
0994:                public void unregisterListeners() {
0995:                }
0996:
0997:            } // End of class FakeDragGestureRecognizer
0998:
0999:            /**
1000:             * Ugly fake class to pass by the issue #4752224. There is not possible
1001:             * to create DataFlavor of mime type application/x-java-jvm-local-objectref 
1002:             * for array class type. */
1003:            static class TopComponentArray {
1004:            } // End of TopComponentArray.
1005:
1006:            public void dragMouseMoved(DragSourceDragEvent dsde) {
1007:                if (null != visualizer)
1008:                    visualizer.update(dsde);
1009:            }
1010:
1011:            /**
1012:             * @return An invisible (size 1x1) image to be used for dragging to replace 
1013:             * the default one supplied by the operating system (if any).
1014:             */
1015:            private Image createDragImage() {
1016:                GraphicsConfiguration config = GraphicsEnvironment
1017:                        .getLocalGraphicsEnvironment().getDefaultScreenDevice()
1018:                        .getDefaultConfiguration();
1019:
1020:                BufferedImage res = config.createCompatibleImage(1, 1);
1021:                Graphics2D g = res.createGraphics();
1022:                g.setColor(Color.white);
1023:                g.fillRect(0, 0, 1, 1);
1024:                return res;
1025:            }
1026:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.