New drag and drop architecture using CURLDragMixin subclasses. Fixed bug where dropping text clipping would drop at old insertion point, not at mouse location. (appr brade).

This commit is contained in:
pinkerton 1998-05-08 15:34:07 +00:00
Родитель 1205850979
Коммит b127a39a89
2 изменённых файлов: 239 добавлений и 215 удалений

Просмотреть файл

@ -16,6 +16,8 @@
* Reserved. * Reserved.
*/ */
#include <vector>
#include "CEditView.h" #include "CEditView.h"
#include "CHTMLView.h" // ::SafeSetCursor #include "CHTMLView.h" // ::SafeSetCursor
@ -139,6 +141,71 @@ void SetMenuCommandAndString( CommandT oldCommand, CommandT newCommand,
} }
} }
#pragma mark -- CComposerAwareURLDragMixin
//
// CComposerAwareURLDragMixin constructor
//
// As the name implies, this version of the URLDragMixin class knows about composer.
// Add the composer native drag flavor to the front of the acceptable flavors
// list, because we want to use that first if it is present over all other drag flavors
//
CComposerAwareURLDragMixin :: CComposerAwareURLDragMixin ( )
{
AcceptedFlavors().insert ( AcceptedFlavors().begin(), 1, (FlavorType)emComposerNativeDrag );
} // constructor
//
// ReceiveDragItem
//
// Overridden to handle the composer native drag flavor before all the others
//
void
CComposerAwareURLDragMixin :: ReceiveDragItem ( DragReference inDragRef, DragAttributes inDragAttrs,
ItemReference inItemRef, Rect & inItemBounds,
SPoint32 & inMouseLoc )
{
try {
FlavorType useFlavor;
FindBestFlavor ( inDragRef, inItemRef, useFlavor );
Size theDataSize = 0;
switch ( useFlavor ) {
case emComposerNativeDrag:
{
SInt16 mods, mouseDownModifiers, mouseUpModifiers;
OSErr err = ::GetDragModifiers( inDragRef, &mods, &mouseDownModifiers, &mouseUpModifiers );
if (err != noErr)
mouseDownModifiers = 0;
bool doCopy = ( (mods & optionKey) == optionKey ) || ( (mouseDownModifiers & optionKey) == optionKey );
err = ::GetFlavorDataSize( inDragRef, inItemRef, emComposerNativeDrag, &theDataSize );
ThrowIfOSErr_( err );
vector<char> datap ( theDataSize + 1 );
if ( noErr == ::GetFlavorData( inDragRef, inItemRef, emComposerNativeDrag, datap.begin(), &theDataSize, 0 )
&& ( theDataSize > 0 ) ) {
datap[ theDataSize ] = 0;
HandleDropOfComposerFlavor ( datap.begin(), doCopy, inMouseLoc );
}
}
break;
default:
CHTAwareURLDragMixin::ReceiveDragItem(inDragRef, inDragAttrs, inItemRef, inItemBounds);
break;
} // switch on best flavor
}
catch ( ... ) {
DebugStr ( "\pCan't find the flavor we want; g" );
}
} // ReceiveDragItem
#pragma mark -- CEditView -- #pragma mark -- CEditView --
CEditView::CEditView(LStream * inStream) : CHTMLView(inStream), CEditView::CEditView(LStream * inStream) : CHTMLView(inStream),
@ -2836,87 +2903,101 @@ CEditView::InsideDropArea(DragReference inDragRef)
} }
//
// ReceiveDragItem
//
// Called once for each item reference dropped on the composer window. After doing some view
// specific work, farm off the bulk of data extraction to our mixin class which will in turn
// call the HandleDropOf* classes below to do the work.
//
void void
CEditView::ReceiveDragItem ( DragReference inDragRef, DragAttributes inDragAttr, CEditView::ReceiveDragItem ( DragReference inDragRef, DragAttributes inDragAttr,
ItemReference inItemRef, Rect& inItemBounds ) ItemReference inItemRef, Rect& inItemBounds )
{ {
#pragma unused( inDragAttr, inItemBounds )
Boolean isImageDropped = false;
char *isURLDroppedString = NULL, *isTitleDroppedString = NULL;
mIsHilited = false; mIsHilited = false;
UnhiliteDropArea( inDragRef ); UnhiliteDropArea( inDragRef );
try
{
HFSFlavor fileData;
Size dataSize = sizeof(fileData);
OSErr err;
Point mouseLoc;
SPoint32 imagePt;
Size size;
FlavorFlags flags;
SInt16 mods, mouseDownModifiers, mouseUpModifiers;
err = ::GetDragModifiers( inDragRef, &mods, &mouseDownModifiers, &mouseUpModifiers );
if (err != noErr)
mouseDownModifiers = 0;
Boolean doCopy = ( (mods & optionKey) == optionKey ) || ( (mouseDownModifiers & optionKey) == optionKey );
FocusDraw(); FocusDraw();
Point mouseLoc;
::GetDragMouse( inDragRef, &mouseLoc, NULL ); ::GetDragMouse( inDragRef, &mouseLoc, NULL );
::GlobalToLocal( &mouseLoc ); ::GlobalToLocal( &mouseLoc );
LocalToImagePoint( mouseLoc, imagePt ); LocalToImagePoint( mouseLoc, mDropLocationImageCoords );
if ( ::GetFlavorData( inDragRef, inItemRef, flavorTypeHFS, &fileData, &dataSize, 0 ) == noErr ) CComposerAwareURLDragMixin::ReceiveDragItem ( inDragRef, inDragAttr, inItemRef, inItemBounds,
mDropLocationImageCoords );
} // ReceiveDragItem
//
// HandleDropOfComposerFlavor
//
// Put the data in the right place, given the current mouse location and if this is a copy
// or a move. Will delete the current selection if it is a move.
//
void
CEditView :: HandleDropOfComposerFlavor ( const char* inData, bool inDoCopy, SPoint32 & inMouseLoc )
{ {
switch ( fileData.fileType ) EDT_BeginBatchChanges( *GetContext() );
if ( inDoCopy || mDragData == NULL )
EDT_PositionCaret( *GetContext(), inMouseLoc.h, inMouseLoc.v );
else
EDT_DeleteSelectionAndPositionCaret( *GetContext(), inMouseLoc.h, inMouseLoc.v );
EDT_PasteHTML( *GetContext(), const_cast<char*>(inData) );
EDT_EndBatchChanges( *GetContext() );
} // HandleDropOfComposerFlavor
//
// HandleDropOfPageProxy
//
// This one's real easy since all the data extraction code is already done for us.
//
void
CEditView :: HandleDropOfPageProxy ( const char* inURL, const char* inTitle )
{
char* url = const_cast<char*>(inURL);
char* title = const_cast<char*>(inTitle);
if ( inURL ) {
if ( inTitle )
EDT_PasteHREF( *GetContext(), &url, &title, 1 );
else
EDT_PasteHREF( *GetContext(), &url, &url, 1 );
}
} // HandleDropOfPageProxy
//
// HandleDropOfLocalFile
//
// Accepts gif/jpeg drops and puts them inline and inserts the url for other kinds
// of files. Clippings files are already handled by responding to the 'TEXT' flavor, so we
// never get here (which is why that code was removed).
//
void
CEditView :: HandleDropOfLocalFile ( const char* inFileURL, const char* fileName,
const HFSFlavor & inFileData )
{
Boolean isImageDropped = false;
char* URLStr = const_cast<char*>(inFileURL);
char* titleStr = const_cast<char*>(fileName);
switch ( inFileData.fileType )
{ {
case 'GIFf': case 'GIFf':
case 'JPEG': case 'JPEG':
isImageDropped = true; isImageDropped = true;
isURLDroppedString = CFileMgr::GetURLFromFileSpec( fileData.fileSpec ); titleStr = NULL;
isTitleDroppedString = NULL;
break;
case 'clpt':
/* This implements support for text clippings. Note: I assume that
the text clippings are of type 'clpt' and store the text in 'TEXT'
resource ID 256. All the examples I found fit this criteria.
Unfortunately, I couldn't find any Apple documentation that
verified this. The actual pasting is done below.
*/
short resnum = ::FSpOpenResFile( &fileData.fileSpec, fsRdPerm );
if ( -1 != resnum )
{
Handle clipping_text = ::Get1Resource ( 'TEXT', 256 );
if ( clipping_text != NULL )
{ // Assuming we got the resource, create it
int clipping_text_size = ::GetHandleSize( clipping_text );
if ( clipping_text_size > 0 )
{
char *droppedString = (char *)XP_ALLOC( clipping_text_size + 1 );
if ( droppedString )
{
::BlockMove( *clipping_text, droppedString, clipping_text_size );
droppedString[ clipping_text_size ] = '\0';
EDT_PasteText( *GetContext(), droppedString );
XP_FREE( droppedString );
}
}
}
::CloseResFile( resnum );
}
return;
break; break;
default: default:
char *link = CFileMgr::GetURLFromFileSpec( fileData.fileSpec ); if ( inFileURL )
if ( link )
{ {
char *link = URLStr;
Bool bAutoAdjustLinks = CPrefs::GetBoolean( CPrefs::PublishMaintainLinks ); Bool bAutoAdjustLinks = CPrefs::GetBoolean( CPrefs::PublishMaintainLinks );
if ( bAutoAdjustLinks ) if ( bAutoAdjustLinks )
{ {
@ -2924,7 +3005,6 @@ CEditView::ReceiveDragItem( DragReference inDragRef, DragAttributes inDragAttr,
if ( NET_MakeRelativeURL( LO_GetBaseURL( *GetContext() ), link, &abs ) if ( NET_MakeRelativeURL( LO_GetBaseURL( *GetContext() ), link, &abs )
!= NET_URL_FAIL && abs ) != NET_URL_FAIL && abs )
{ {
XP_FREE( link );
link = abs; link = abs;
abs = NULL; abs = NULL;
} }
@ -2932,139 +3012,56 @@ CEditView::ReceiveDragItem( DragReference inDragRef, DragAttributes inDragAttr,
XP_FREE(abs); XP_FREE(abs);
} }
isURLDroppedString = link; URLStr = link;
isTitleDroppedString = XP_STRDUP( link ); titleStr = link;
} }
break; break;
} }
}
else if ( ::GetFlavorDataSize( inDragRef, inItemRef, emBookmarkDrag, &size ) == noErr )
{
char *buffer = (char *)XP_ALLOC( size + 1 );
if ( buffer )
{
if ( ::GetFlavorData( inDragRef, inItemRef, emBookmarkDrag, buffer, &size, 0 ) == noErr )
{
buffer[ size ] = 0; // Terminate the string
isURLDroppedString = XP_STRDUP( buffer );
char * title = strchr( isURLDroppedString, '\r' ); // if the user dragged an image, insert the image inline, otherwise paste in the URL (with
if ( title == NULL ) // title if one is present).
{ if ( URLStr ) {
// Bookmark without a title if ( isImageDropped ) {
isTitleDroppedString = XP_STRDUP( buffer );
// EDT_PasteHREF( mContext, &buffer, &buffer, 1);
}
else
{
*title = 0;
title++;
isImageDropped = (XP_STRCMP(title,"[Image]") == 0);
if ( isImageDropped )
{
isTitleDroppedString = NULL;
// we need to chop off [Image] from isURLDroppedString
if ( isURLDroppedString )
{
char *positionMarker = strchr( isURLDroppedString, '\r' );
if ( positionMarker )
positionMarker[0] = 0;
}
}
else
{
isTitleDroppedString = XP_STRDUP(title);
// EDT_PasteHREF( mContext, &buffer, &title, 1);
}
}
}
XP_FREE( buffer );
}
}
else if ( ::GetFlavorFlags( inDragRef, inItemRef, emComposerNativeDrag, &flags ) == noErr )
{
/* if the mouse is over the selection (in the same window), we shouldn't do anything/just bail out */
OSErr err = ::GetFlavorDataSize( inDragRef, inItemRef, emComposerNativeDrag, &size );
ThrowIfOSErr_( err );
char *datap = (char *)XP_ALLOC( size + 1 );
if ( datap )
{
if ( noErr == ::GetFlavorData( inDragRef, inItemRef, emComposerNativeDrag, datap, &size, 0 )
&& ( size > 0 ) )
{
datap[ size ] = 0;
EDT_BeginBatchChanges( *GetContext() );
if ( doCopy || mDragData == NULL )
EDT_PositionCaret( *GetContext(), mouseLoc.h, mouseLoc.v );
else
EDT_DeleteSelectionAndPositionCaret( *GetContext(), mouseLoc.h, mouseLoc.v );
EDT_PasteHTML( *GetContext(), datap );
EDT_EndBatchChanges( *GetContext() );
}
XP_FREE( datap );
}
return;
}
else if ( ::GetFlavorFlags( inDragRef, inItemRef, 'TEXT', &flags ) == noErr )
{
/* text being dragged */
OSErr err = ::GetFlavorDataSize( inDragRef, inItemRef, 'TEXT', &size );
ThrowIfOSErr_ (err); // caught by PP handler
char *lDroppedString = (char *)XP_ALLOC( size + 1 );
if ( lDroppedString )
{
if ( ::GetFlavorData( inDragRef, inItemRef, 'TEXT', lDroppedString, &size, 0 ) == noErr )
{
lDroppedString[ size ] = 0;
EDT_PasteText( *GetContext(), lDroppedString );
}
XP_FREE( lDroppedString );
}
return;
}
}
catch(...)
{
}
if ( isURLDroppedString )
{
if ( isImageDropped )
{
EDT_ImageData* imageData = EDT_NewImageData(); EDT_ImageData* imageData = EDT_NewImageData();
if ( imageData ) if ( imageData )
{ {
imageData->pSrc = isURLDroppedString; imageData->pSrc = XP_STRDUP(URLStr);
EDT_InsertImage( *GetContext(), imageData, CPrefs::GetBoolean( CPrefs::PublishKeepImages ) ); EDT_InsertImage( *GetContext(), imageData, CPrefs::GetBoolean( CPrefs::PublishKeepImages ) );
EDT_FreeImageData( imageData ); EDT_FreeImageData( imageData );
} }
XP_FREEIF( isTitleDroppedString );
isURLDroppedString = NULL;
isTitleDroppedString = NULL;
} }
else {
if ( titleStr )
EDT_PasteHREF( *GetContext(), &URLStr, &titleStr, 1 );
else else
EDT_PasteHREF( *GetContext(), &URLStr, &URLStr, 1 );
}
}
} // HandleDropOfLocalFile
//
// HandleDropOfText
//
// Very simple, since all of the data extraction is done for us already
//
void
CEditView :: HandleDropOfText ( const char* inTextData )
{ {
if ( isTitleDroppedString ) EDT_PositionCaret( *GetContext(), mDropLocationImageCoords.h, mDropLocationImageCoords.v );
EDT_PasteHREF( *GetContext(), &isURLDroppedString, &isTitleDroppedString, 1 ); EDT_PasteText( *GetContext(), const_cast<char*>(inTextData) );
else
EDT_PasteHREF( *GetContext(), &isURLDroppedString, &isURLDroppedString, 1 );
XP_FREE( isURLDroppedString ); } // HandleDropOfText
XP_FREEIF( isTitleDroppedString );
isURLDroppedString = NULL;
isTitleDroppedString = NULL;
} void
} CEditView :: HandleDropOfHTResource ( HT_Resource /*node*/ )
} {
DebugStr("\pNot yet implemented");
} // HandleDropOfHTResource
void CEditView::InsertDefaultLine() void CEditView::InsertDefaultLine()

Просмотреть файл

@ -20,6 +20,7 @@
#include <TextServices.h> #include <TextServices.h>
#include "CHTMLView.h" #include "CHTMLView.h"
#include "CURLDragHelper.h"
// dangling prototype // dangling prototype
Boolean GetCaretPosition(MWContext *context, LO_Element * element, int32 caretPos, Boolean GetCaretPosition(MWContext *context, LO_Element * element, int32 caretPos,
@ -35,7 +36,27 @@ class CFontMenuPopup;
class HTMLInlineTSMProxy; class HTMLInlineTSMProxy;
class HoldUpdatesProxy; class HoldUpdatesProxy;
class CEditView: public CHTMLView
class CComposerAwareURLDragMixin : public CHTAwareURLDragMixin
{
CComposerAwareURLDragMixin ( );
virtual ~CComposerAwareURLDragMixin ( ) { } ;
protected:
// overridden to handle composer flavor drops
virtual void ReceiveDragItem ( DragReference inDragRef, DragAttributes inDragAttrs,
ItemReference inItemRef, Rect & inItemBounds,
SPoint32 & inMouse ) ;
// must override to do the right thing
virtual void HandleDropOfComposerFlavor ( const char* inData, bool inDoCopy, SPoint32 & inMouse ) = 0 ;
}; // class CComposerAwareURLDragMixin
class CEditView: public CHTMLView, public CComposerAwareURLDragMixin
{ {
#if !defined(__MWERKS__) || (__MWERKS__ >= 0x2000) #if !defined(__MWERKS__) || (__MWERKS__ >= 0x2000)
typedef CHTMLView inherited; typedef CHTMLView inherited;
@ -128,13 +149,6 @@ public:
void DisplayGenericCaret( MWContext *context, LO_Element * pLoAny, void DisplayGenericCaret( MWContext *context, LO_Element * pLoAny,
ED_CaretObjectPosition caretPos ); ED_CaretObjectPosition caretPos );
// ¥¥ Drag and Drop
virtual Boolean ItemIsAcceptable (DragReference dragRef, ItemReference itemRef);
virtual void ReceiveDragItem( DragReference inDragRef, DragAttributes inDragAttr,
ItemReference inItemRef, Rect& inItemBounds );
virtual void DoDragSendData( FlavorType inFlavor, ItemReference inItemRef,
DragReference inDragRef );
virtual void ClickSelf (const SMouseDownEvent& where ); virtual void ClickSelf (const SMouseDownEvent& where );
virtual Boolean ClickTrackSelection( const SMouseDownEvent& inMouseDown, virtual Boolean ClickTrackSelection( const SMouseDownEvent& inMouseDown,
CHTMLClickRecord& inClickRecord ); CHTMLClickRecord& inClickRecord );
@ -195,10 +209,23 @@ protected:
virtual void DisplayFeedback( int inLocation, LO_Element *inElement ); virtual void DisplayFeedback( int inLocation, LO_Element *inElement );
virtual void DisplaySelectionFeedback( uint16 ele_attrmask, const Rect &inRect ); virtual void DisplaySelectionFeedback( uint16 ele_attrmask, const Rect &inRect );
// ¥¥ Drag and Drop
virtual Boolean ItemIsAcceptable (DragReference dragRef, ItemReference itemRef);
virtual void ReceiveDragItem( DragReference inDragRef, DragAttributes inDragAttr,
ItemReference inItemRef, Rect& inItemBounds );
virtual void DoDragSendData( FlavorType inFlavor, ItemReference inItemRef,
DragReference inDragRef );
virtual void InsideDropArea( DragReference inDragRef ); virtual void InsideDropArea( DragReference inDragRef );
virtual void EnterDropArea( DragReference inDragRef, Boolean inDragHasLeftSender ); virtual void EnterDropArea( DragReference inDragRef, Boolean inDragHasLeftSender );
virtual void HandleDropOfComposerFlavor ( const char* inData, bool inDoCopy,
SPoint32 & inMouse ) ;
virtual void HandleDropOfPageProxy ( const char* inURL, const char* inTitle ) ;
virtual void HandleDropOfLocalFile ( const char* inFileURL, const char* fileName,
const HFSFlavor & inFileData ) ;
virtual void HandleDropOfText ( const char* inTextData ) ;
virtual void HandleDropOfHTResource ( HT_Resource node ) ;
DragReference mDragRef; DragReference mDragRef;
SPoint32 mDropLocationImageCoords;
enum { enum {
ED_SELECTION_BORDER = 3 ED_SELECTION_BORDER = 3