blob: cefc7e720bbc8e1a622dacd0cc3c31859e6b5714 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sd.hxx"
#include <com/sun/star/util/XChangesNotifier.hpp>
#include <vcl/help.hxx>
#include <vcl/svapp.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/dispatch.hxx>
#include <svx/sdr/overlay/overlaymanager.hxx>
#include <svx/sdr/overlay/overlayanimatedbitmapex.hxx>
#include <svx/sdr/overlay/overlaybitmapex.hxx>
#include <svx/svdpagv.hxx>
#include <svx/sdrpagewindow.hxx>
#include <svx/sdrpaintwindow.hxx>
#include <svx/svddrgmt.hxx>
#include "View.hxx"
#include "sdresid.hxx"
#include "annotations.hrc"
#include "annotationmanagerimpl.hxx"
#include "annotationwindow.hxx"
#include "annotationtag.hxx"
#include "sdpage.hxx"
#include "ViewShell.hxx"
#include "app.hrc"
#include "Window.hxx"
#include "drawdoc.hxx"
using ::rtl::OUString;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
//using namespace ::com::sun::star::util;
using namespace ::com::sun::star::drawing;
using namespace ::com::sun::star::office;
using namespace ::com::sun::star::geometry;
namespace sd
{
const sal_uInt32 SMART_TAG_HDL_NUM = SAL_MAX_UINT32;
static const int DRGPIX = 2; // Drag MinMove in Pixel
// --------------------------------------------------------------------
static OUString getInitials( const OUString& rName )
{
OUString sInitials;
const sal_Unicode * pStr = rName.getStr();
sal_Int32 nLength = rName.getLength();
while( nLength )
{
// skip whitespace
while( nLength && (*pStr <= ' ') )
{
nLength--; pStr++;
}
// take letter
if( nLength )
{
sInitials += OUString( *pStr );
nLength--; pStr++;
}
// skip letters until whitespace
while( nLength && (*pStr > ' ') )
{
nLength--; pStr++;
}
}
return sInitials;
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------
class AnnotationDragMove : public SdrDragMove
{
public:
AnnotationDragMove(SdrDragView& rNewView, const rtl::Reference <AnnotationTag >& xTag);
virtual bool BeginSdrDrag();
virtual bool EndSdrDrag(bool bCopy);
virtual void MoveSdrDrag(const Point& rNoSnapPnt);
virtual void CancelSdrDrag();
private:
rtl::Reference <AnnotationTag > mxTag;
Point maOrigin;
};
AnnotationDragMove::AnnotationDragMove(SdrDragView& rNewView, const rtl::Reference <AnnotationTag >& xTag)
: SdrDragMove(rNewView)
, mxTag( xTag )
{
}
bool AnnotationDragMove::BeginSdrDrag()
{
DragStat().Ref1()=GetDragHdl()->GetPos();
DragStat().SetShown(!DragStat().IsShown());
maOrigin = GetDragHdl()->GetPos();
DragStat().SetActionRect(Rectangle(maOrigin,maOrigin));
return true;
}
void AnnotationDragMove::MoveSdrDrag(const Point& rNoSnapPnt)
{
Point aPnt(rNoSnapPnt);
if (DragStat().CheckMinMoved(rNoSnapPnt))
{
if (aPnt!=DragStat().GetNow())
{
Hide();
DragStat().NextMove(aPnt);
GetDragHdl()->SetPos( maOrigin + Point( DragStat().GetDX(), DragStat().GetDY() ) );
Show();
DragStat().SetActionRect(Rectangle(aPnt,aPnt));
}
}
}
bool AnnotationDragMove::EndSdrDrag(bool /*bCopy*/)
{
Hide();
if( mxTag.is() )
mxTag->Move( DragStat().GetDX(), DragStat().GetDY() );
return sal_True;
}
void AnnotationDragMove::CancelSdrDrag()
{
Hide();
}
// --------------------------------------------------------------------
class AnnotationHdl : public SmartHdl
{
public:
AnnotationHdl( const SmartTagReference& xTag, const Reference< XAnnotation >& xAnnotation, const Point& rPnt );
virtual ~AnnotationHdl();
virtual void CreateB2dIAObject();
virtual sal_Bool IsFocusHdl() const;
virtual Pointer GetSdrDragPointer() const;
virtual bool isMarkable() const;
private:
Reference< XAnnotation > mxAnnotation;
rtl::Reference< AnnotationTag > mxTag;
};
// --------------------------------------------------------------------
AnnotationHdl::AnnotationHdl( const SmartTagReference& xTag, const Reference< XAnnotation >& xAnnotation, const Point& rPnt )
: SmartHdl( xTag, rPnt )
, mxAnnotation( xAnnotation )
, mxTag( dynamic_cast< AnnotationTag* >( xTag.get() ) )
{
}
// --------------------------------------------------------------------
AnnotationHdl::~AnnotationHdl()
{
}
// --------------------------------------------------------------------
void AnnotationHdl::CreateB2dIAObject()
{
// first throw away old one
GetRidOfIAObject();
if( mxAnnotation.is() )
{
const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
const Point aTagPos( GetPos() );
basegfx::B2DPoint aPosition( aTagPos.X(), aTagPos.Y() );
const bool bFocused = IsFocusHdl() && pHdlList && (pHdlList->GetFocusHdl() == this);
BitmapEx aBitmapEx( mxTag->CreateAnnotationBitmap(mxTag->isSelected()) );
BitmapEx aBitmapEx2;
if( bFocused )
aBitmapEx2 = mxTag->CreateAnnotationBitmap(!mxTag->isSelected() );
if(pHdlList)
{
SdrMarkView* pView = pHdlList->GetView();
if(pView && !pView->areMarkHandlesHidden())
{
SdrPageView* pPageView = pView->GetSdrPageView();
if(pPageView)
{
for(sal_uInt32 b = 0; b < pPageView->PageWindowCount(); b++)
{
// const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b];
const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
SdrPaintWindow& rPaintWindow = rPageWindow.GetPaintWindow();
if(rPaintWindow.OutputToWindow() && rPageWindow.GetOverlayManager() )
{
::sdr::overlay::OverlayObject* pOverlayObject = 0;
// animate focused handles
if(bFocused)
{
const sal_uInt32 nBlinkTime = sal::static_int_cast<sal_uInt32>(rStyleSettings.GetCursorBlinkTime());
pOverlayObject = new ::sdr::overlay::OverlayAnimatedBitmapEx(aPosition, aBitmapEx, aBitmapEx2, nBlinkTime, 0, 0, 0, 0 );
/*
(sal_uInt16)(aBitmapEx.GetSizePixel().Width() - 1) >> 1,
(sal_uInt16)(aBitmapEx.GetSizePixel().Height() - 1) >> 1,
(sal_uInt16)(aBitmapEx2.GetSizePixel().Width() - 1) >> 1,
(sal_uInt16)(aBitmapEx2.GetSizePixel().Height() - 1) >> 1);
*/
}
else
{
pOverlayObject = new ::sdr::overlay::OverlayBitmapEx( aPosition, aBitmapEx, 0, 0 );
}
rPageWindow.GetOverlayManager()->add(*pOverlayObject);
maOverlayGroup.append(*pOverlayObject);
}
}
}
}
}
}
}
// --------------------------------------------------------------------
sal_Bool AnnotationHdl::IsFocusHdl() const
{
return sal_True;
}
// --------------------------------------------------------------------
bool AnnotationHdl::isMarkable() const
{
return false;
}
// --------------------------------------------------------------------
Pointer AnnotationHdl::GetSdrDragPointer() const
{
PointerStyle eStyle = POINTER_NOTALLOWED;
if( mxTag.is() )
{
if( mxTag->isSelected() )
{
eStyle = POINTER_MOVE;
}
else
{
eStyle = POINTER_ARROW;
}
}
return Pointer( eStyle );
}
// ====================================================================
AnnotationTag::AnnotationTag( AnnotationManagerImpl& rManager, ::sd::View& rView, const Reference< XAnnotation >& xAnnotation, Color& rColor, int nIndex, const Font& rFont )
: SmartTag( rView )
, mrManager( rManager )
, mxAnnotation( xAnnotation )
, maColor( rColor )
, mnIndex( nIndex )
, mrFont( rFont )
, mnClosePopupEvent( 0 )
, mpListenWindow( 0 )
{
}
// --------------------------------------------------------------------
AnnotationTag::~AnnotationTag()
{
DBG_ASSERT( !mxAnnotation.is(), "sd::AnnotationTag::~AnnotationTag(), dispose me first!" );
Dispose();
}
// --------------------------------------------------------------------
/** returns true if the AnnotationTag handled the event. */
bool AnnotationTag::MouseButtonDown( const MouseEvent& rMEvt, SmartHdl& /*rHdl*/ )
{
if( !mxAnnotation.is() )
return false;
bool bRet = false;
if( !isSelected() )
{
SmartTagReference xTag( this );
mrView.getSmartTags().select( xTag );
bRet = true;
}
/*
if( rMEvt.IsLeft() && (rMEvt.GetClicks() == 2) )
{
// double click;
return true;
}
else */
if( rMEvt.IsLeft() && !rMEvt.IsRight() )
{
Window* pWindow = mrView.GetViewShell()->GetActiveWindow();
if( pWindow )
{
maMouseDownPos = pWindow->PixelToLogic( rMEvt.GetPosPixel() );
if( mpListenWindow )
mpListenWindow->RemoveEventListener( LINK(this, AnnotationTag, WindowEventHandler));
mpListenWindow = pWindow;
mpListenWindow->AddEventListener( LINK(this, AnnotationTag, WindowEventHandler));
}
bRet = true;
}
return bRet;
}
// --------------------------------------------------------------------
/** returns true if the SmartTag consumes this event. */
bool AnnotationTag::KeyInput( const KeyEvent& rKEvt )
{
if( !mxAnnotation.is() )
return false;
sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
switch( nCode )
{
case KEY_DELETE:
mrManager.DeleteAnnotation( mxAnnotation );
return true;
case KEY_DOWN:
case KEY_UP:
case KEY_LEFT:
case KEY_RIGHT:
return OnMove( rKEvt );
case KEY_ESCAPE:
{
SmartTagReference xThis( this );
mrView.getSmartTags().deselect();
return true;
}
case KEY_TAB:
mrManager.SelectNextAnnotation(!rKEvt.GetKeyCode().IsShift());
return true;
case KEY_RETURN:
case KEY_SPACE:
OpenPopup( true );
return true;
default:
return false;
}
}
/** returns true if the SmartTag consumes this event. */
bool AnnotationTag::RequestHelp( const HelpEvent& /*rHEvt*/ )
{
/*
::Window* pWindow = mrView.GetViewShell()->GetActiveWindow();
if( mxAnnotation.is() && pWindow )
{
OUString aHelpText( mrManager.GetHelpText( mxAnnotation ) );
RealPoint2D aPosition( mxAnnotation->getPosition() );
Point aPos( pWindow->LogicToPixel( Point( static_cast<long>(aPosition.X * 100.0), static_cast<long>(aPosition.Y * 100.0) ) ) );
Rectangle aRect( aPos, maSize );
if (Help::IsBalloonHelpEnabled())
Help::ShowBalloon( pWindow, aPos, aRect, aHelpText);
else if (Help::IsQuickHelpEnabled())
Help::ShowQuickHelp( pWindow, aRect, aHelpText);
return true;
}
*/
return false;
}
/** returns true if the SmartTag consumes this event. */
bool AnnotationTag::Command( const CommandEvent& rCEvt )
{
if ( rCEvt.GetCommand() == COMMAND_CONTEXTMENU )
{
::Window* pWindow = mrView.GetViewShell()->GetActiveWindow();
if( pWindow )
{
Rectangle aContextRect(rCEvt.GetMousePosPixel(),Size(1,1));
mrManager.ExecuteAnnotationContextMenu( mxAnnotation, pWindow, aContextRect );
return true;
}
}
return false;
}
void AnnotationTag::Move( int nDX, int nDY )
{
if( mxAnnotation.is() )
{
if( mrManager.GetDoc()->IsUndoEnabled() )
mrManager.GetDoc()->BegUndo( String( SdResId( STR_ANNOTATION_UNDO_MOVE ) ) );
RealPoint2D aPosition( mxAnnotation->getPosition() );
aPosition.X += (double)nDX / 100.0;
aPosition.Y += (double)nDY / 100.0;
mxAnnotation->setPosition( aPosition );
if( mrManager.GetDoc()->IsUndoEnabled() )
mrManager.GetDoc()->EndUndo();
mrView.updateHandles();
}
}
bool AnnotationTag::OnMove( const KeyEvent& rKEvt )
{
long nX = 0;
long nY = 0;
switch( rKEvt.GetKeyCode().GetCode() )
{
case KEY_UP: nY = -1; break;
case KEY_DOWN: nY = 1; break;
case KEY_LEFT: nX = -1; break;
case KEY_RIGHT: nX = 1; break;
default: break;
}
if(rKEvt.GetKeyCode().IsMod2())
{
OutputDevice* pOut = mrView.GetViewShell()->GetActiveWindow();
Size aLogicSizeOnePixel = (pOut) ? pOut->PixelToLogic(Size(1,1)) : Size(100, 100);
nX *= aLogicSizeOnePixel.Width();
nY *= aLogicSizeOnePixel.Height();
}
else
{
// old, fixed move distance
nX *= 100;
nY *= 100;
}
if( nX || nY )
{
// move the annotation
Move( nX, nY );
}
return true;
}
// --------------------------------------------------------------------
void AnnotationTag::CheckPossibilities()
{
}
// --------------------------------------------------------------------
sal_uLong AnnotationTag::GetMarkablePointCount() const
{
return 0;
}
// --------------------------------------------------------------------
sal_uLong AnnotationTag::GetMarkedPointCount() const
{
return 0;
}
// --------------------------------------------------------------------
sal_Bool AnnotationTag::MarkPoint(SdrHdl& /*rHdl*/, sal_Bool /*bUnmark*/ )
{
sal_Bool bRet=sal_False;
return bRet;
}
// --------------------------------------------------------------------
sal_Bool AnnotationTag::MarkPoints(const Rectangle* /*pRect*/, sal_Bool /*bUnmark*/ )
{
sal_Bool bChgd=sal_False;
return bChgd;
}
// --------------------------------------------------------------------
bool AnnotationTag::getContext( SdrViewContext& /*rContext*/ )
{
return false;
}
// --------------------------------------------------------------------
void AnnotationTag::addCustomHandles( SdrHdlList& rHandlerList )
{
if( mxAnnotation.is() )
{
SmartTagReference xThis( this );
Point aPoint;
AnnotationHdl* pHdl = new AnnotationHdl( xThis, mxAnnotation, aPoint );
pHdl->SetObjHdlNum( SMART_TAG_HDL_NUM );
pHdl->SetPageView( mrView.GetSdrPageView() );
RealPoint2D aPosition( mxAnnotation->getPosition() );
Point aBasePos( static_cast<long>(aPosition.X * 100.0), static_cast<long>(aPosition.Y * 100.0) );
pHdl->SetPos( aBasePos );
rHandlerList.AddHdl( pHdl );
}
}
// --------------------------------------------------------------------
void AnnotationTag::disposing()
{
if( mpListenWindow )
{
mpListenWindow->RemoveEventListener( LINK(this, AnnotationTag, WindowEventHandler));
}
if( mnClosePopupEvent )
{
Application::RemoveUserEvent( mnClosePopupEvent );
mnClosePopupEvent = 0;
}
mxAnnotation.clear();
ClosePopup();
SmartTag::disposing();
}
// --------------------------------------------------------------------
void AnnotationTag::select()
{
SmartTag::select();
mrManager.onTagSelected( *this );
Window* pWindow = mrView.GetViewShell()->GetActiveWindow();
if( pWindow )
{
RealPoint2D aPosition( mxAnnotation->getPosition() );
Point aPos( static_cast<long>(aPosition.X * 100.0), static_cast<long>(aPosition.Y * 100.0) );
Rectangle aVisRect( aPos, pWindow->PixelToLogic(maSize) );
mrView.MakeVisible(aVisRect, *pWindow);
}
}
// --------------------------------------------------------------------
void AnnotationTag::deselect()
{
SmartTag::deselect();
ClosePopup();
mrManager.onTagDeselected( *this );
}
// --------------------------------------------------------------------
BitmapEx AnnotationTag::CreateAnnotationBitmap( bool bSelected )
{
VirtualDevice aVDev;
OUString sAuthor( getInitials( mxAnnotation->getAuthor() ) );
sAuthor += OUString( sal_Unicode( ' ' ) );
sAuthor += OUString::valueOf( (sal_Int32)mnIndex );
aVDev.SetFont( mrFont );
const int BORDER_X = 4; // pixels
const int BORDER_Y = 4; // pixels
maSize = Size( aVDev.GetTextWidth( sAuthor ) + 2*BORDER_X, aVDev.GetTextHeight() + 2*BORDER_Y );
aVDev.SetOutputSizePixel( maSize, sal_False );
Color aBorderColor( maColor );
if( bSelected )
{
aBorderColor.Invert();
}
else
{
if( maColor.IsDark() )
{
aBorderColor.IncreaseLuminance( 32 );
}
else
{
aBorderColor.DecreaseLuminance( 32 );
}
}
Point aPos;
Rectangle aBorderRect( aPos, maSize );
aVDev.SetLineColor(aBorderColor);
aVDev.SetFillColor(maColor);
aVDev.DrawRect( aBorderRect );
aVDev.SetTextColor( maColor.IsDark() ? COL_WHITE : COL_BLACK );
aVDev.DrawText( Point( BORDER_X, BORDER_Y ), sAuthor );
return aVDev.GetBitmapEx( aPos, maSize );
}
void AnnotationTag::OpenPopup( bool bEdit )
{
if( !mxAnnotation.is() )
return;
if( !mpAnnotationWindow.get() )
{
::Window* pWindow = dynamic_cast< ::Window* >( getView().GetFirstOutputDevice() );
if( pWindow )
{
RealPoint2D aPosition( mxAnnotation->getPosition() );
Point aPos( pWindow->OutputToScreenPixel( pWindow->LogicToPixel( Point( static_cast<long>(aPosition.X * 100.0), static_cast<long>(aPosition.Y * 100.0) ) ) ) );
aPos.X() += 4; // magic!
aPos.Y() += 1;
Rectangle aRect( aPos, maSize );
mpAnnotationWindow.reset( new AnnotationWindow( mrManager, mrView.GetDocSh(), pWindow->GetWindow(WINDOW_FRAME) ) );
mpAnnotationWindow->InitControls();
mpAnnotationWindow->setAnnotation(mxAnnotation);
sal_uInt16 nArrangeIndex = 0;
Point aPopupPos( FloatingWindow::CalcFloatingPosition( mpAnnotationWindow.get(), aRect, FLOATWIN_POPUPMODE_RIGHT, nArrangeIndex ) );
Size aPopupSize( 320, 240 );
mpAnnotationWindow->SetPosSizePixel( aPopupPos, aPopupSize );
mpAnnotationWindow->DoResize();
mpAnnotationWindow->Show();
mpAnnotationWindow->GrabFocus();
mpAnnotationWindow->AddEventListener( LINK(this, AnnotationTag, WindowEventHandler));
}
}
if( bEdit && mpAnnotationWindow.get() )
mpAnnotationWindow->StartEdit();
}
void AnnotationTag::ClosePopup()
{
if( mpAnnotationWindow.get() )
{
mpAnnotationWindow->RemoveEventListener( LINK(this, AnnotationTag, WindowEventHandler));
mpAnnotationWindow->Deactivate();
mpAnnotationWindow.reset();
}
}
IMPL_LINK(AnnotationTag, WindowEventHandler, VclWindowEvent*, pEvent)
{
if( pEvent != NULL )
{
::Window* pWindow = pEvent->GetWindow();
if( pWindow )
{
if( pWindow == mpAnnotationWindow.get() )
{
if( pEvent->GetId() == VCLEVENT_WINDOW_DEACTIVATE )
{
if( mnClosePopupEvent )
Application::RemoveUserEvent( mnClosePopupEvent );
mnClosePopupEvent = Application::PostUserEvent( LINK( this, AnnotationTag, ClosePopupHdl ) );
}
}
else if( pWindow == mpListenWindow )
{
switch( pEvent->GetId() )
{
case VCLEVENT_WINDOW_MOUSEBUTTONUP:
{
// if we stop pressing the button without a mouse move we open the popup
mpListenWindow->RemoveEventListener( LINK(this, AnnotationTag, WindowEventHandler));
mpListenWindow = 0;
if( mpAnnotationWindow.get() == 0 )
OpenPopup(false);
}
break;
case VCLEVENT_WINDOW_MOUSEMOVE:
{
// if we move the mouse after a button down we wan't to start draging
mpListenWindow->RemoveEventListener( LINK(this, AnnotationTag, WindowEventHandler));
mpListenWindow = 0;
SdrHdl* pHdl = mrView.PickHandle(maMouseDownPos);
if( pHdl )
{
mrView.BrkAction();
const sal_uInt16 nDrgLog = (sal_uInt16)pWindow->PixelToLogic(Size(DRGPIX,0)).Width();
rtl::Reference< AnnotationTag > xTag( this );
SdrDragMethod* pDragMethod = new AnnotationDragMove( mrView, xTag );
mrView.BegDragObj(maMouseDownPos, NULL, pHdl, nDrgLog, pDragMethod );
}
}
break;
case VCLEVENT_OBJECT_DYING:
mpListenWindow = 0;
break;
}
}
}
}
return sal_True;
}
IMPL_LINK( AnnotationTag, ClosePopupHdl, void *, EMPTYARG )
{
mnClosePopupEvent = 0;
ClosePopup();
return 0;
}
} // end of namespace sd