001/* [{
002Copyright 2007-2011 Nicolas Carranza <nicarran at gmail.com>
003
004This file is part of jpen.
005
006jpen is free software: you can redistribute it and/or modify
007it under the terms of the GNU Lesser General Public License as published by
008the Free Software Foundation, either version 3 of the License,
009or (at your option) any later version.
010
011jpen is distributed in the hope that it will be useful,
012but WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014GNU Lesser General Public License for more details.
015
016You should have received a copy of the GNU Lesser General Public License
017along with jpen.  If not, see <http://www.gnu.org/licenses/>.
018}] */
019package jpen.owner;
020
021import jpen.event.PenAdapter;
022import jpen.event.PenListener;
023import jpen.PButtonEvent;
024import jpen.Pen;
025import jpen.PenEvent;
026
027/**
028Provides a mechanism to start/stop the drag-out operation.
029*/
030public abstract class AbstractPenOwner
031        implements PenOwner{
032
033        protected PenManagerHandle penManagerHandle;
034        private boolean isDraggingOut; // state: true when dragging outside the component
035        private final PenListener draggingOutPenListener=new PenAdapter(){
036                                @Override
037                                public void penButtonEvent(PButtonEvent ev){
038                                        synchronized(penManagerHandle.getPenSchedulerLock()){
039                                                if(!ev.button.value &&
040                                                         !getPen().hasPressedButtons() &&
041                                                         isDraggingOut
042                                                        ){
043                                                        stopDraggingOut();
044                                                        draggingOutDisengaged();
045                                                }
046                                        }
047                                }
048                        };
049
050        /**
051        Force stopping a drag-out operation if it was in progress. This method must be called when entering the {@link PenClip} to stop the drag-out operation if it was still in progress.
052
053        This method must be called while holding the {@link jpen.owner.PenOwner.PenManagerHandle#getPenSchedulerLock()} (See {@link PenOwner#isDraggingOut()}).
054
055        @return {@code true} if a drag-out operation was in progress and was stopped.
056        */
057        protected final boolean stopDraggingOut(){
058                if(!isDraggingOut)
059                        return false;
060                isDraggingOut=false;
061                getPen().removeListener(draggingOutPenListener);
062                return true;
063        }
064
065        protected abstract void draggingOutDisengaged();
066
067        /**
068        Starts a drag-out operation if there are pressed buttons and installs a penListener which automatically stops the drag-out operation when all the buttons are unpressed.
069
070        This method must be called while holding the {@link jpen.owner.PenOwner.PenManagerHandle#getPenSchedulerLock()} (See {@link PenOwner#isDraggingOut()}).
071
072        @return {@code true} if a drag-out operation was started or was already in progress.
073        */
074        protected final boolean startDraggingOut(){
075                if(isDraggingOut)
076                        return true;
077                if(!getPen().hasPressedButtons())
078                        return false;
079                isDraggingOut=true;
080                getPen().addListener(draggingOutPenListener);
081                return true;
082        }
083
084        //@Override
085        public final void setPenManagerHandle(PenManagerHandle penManagerHandle){
086                if(this.penManagerHandle!=null)
087                        throw new IllegalStateException("The penManagerHandle has already being set. This PenOwner can't be used on multiple PenManagers.");
088                this.penManagerHandle=penManagerHandle;
089                init();
090        }
091
092        /**
093        Override this method to do initialization. This method is called after the {@link #penManagerHandle} is set.
094        */
095        protected abstract void init();
096
097        //@Override
098        public final boolean isDraggingOut(){
099                return isDraggingOut;
100        }
101
102        protected final Pen getPen(){
103                return penManagerHandle.getPenManager().pen;
104        }
105
106        //@Override
107        public Object evalPenEventTag(PenEvent ev){
108                return null;
109        }
110
111        //@Override
112        public boolean enforceSinglePenManager(){
113                return false;
114        }
115
116}