X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/a3e7d24d21f5371c88caffe4a85c8e4a5362db3f..a66fa4a84b405396d522106e5bbc9735889f5a02:/samples/dnd/dnd.cpp?ds=inline diff --git a/samples/dnd/dnd.cpp b/samples/dnd/dnd.cpp index 9ce9518b12..0b26e485d8 100644 --- a/samples/dnd/dnd.cpp +++ b/samples/dnd/dnd.cpp @@ -43,15 +43,12 @@ // file names) we drop on them // ---------------------------------------------------------------------------- -typedef long wxDropPointCoord; - class DnDText : public wxTextDropTarget { public: DnDText(wxListBox *pOwner) { m_pOwner = pOwner; } - virtual bool OnDropText(wxDropPointCoord x, wxDropPointCoord y, - const wxChar* psz); + virtual bool OnDropText(wxCoord x, wxCoord y, const wxString& text); private: wxListBox *m_pOwner; @@ -62,8 +59,8 @@ class DnDFile : public wxFileDropTarget public: DnDFile(wxListBox *pOwner) { m_pOwner = pOwner; } - virtual bool OnDropFiles(wxDropPointCoord x, wxDropPointCoord y, - size_t nFiles, const wxChar* const aszFiles[] ); + virtual bool OnDropFiles(wxCoord x, wxCoord y, + const wxArrayString& filenames); private: wxListBox *m_pOwner; @@ -98,11 +95,15 @@ public: void OnNewFrame(wxCommandEvent& event); void OnHelp (wxCommandEvent& event); void OnLogClear(wxCommandEvent& event); + void OnCopy(wxCommandEvent& event); void OnPaste(wxCommandEvent& event); + void OnCopyBitmap(wxCommandEvent& event); void OnPasteBitmap(wxCommandEvent& event); + void OnCopyFiles(wxCommandEvent& event); + void OnLeftDown(wxMouseEvent& event); void OnRightDown(wxMouseEvent& event); @@ -113,10 +114,11 @@ public: private: wxListBox *m_ctrlFile, - *m_ctrlText; + *m_ctrlText; wxTextCtrl *m_ctrlLog; - wxLog *m_pLog, *m_pLogPrev; + wxLog *m_pLog, + *m_pLogPrev; wxString m_strText; wxBitmap m_bitmap; @@ -146,6 +148,10 @@ public: { } + // this is for debugging - lets us see when exactly an object is freed + // (this may be later than you think if it's on the clipboard, for example) + virtual ~DnDShape() { } + // the functions used for drag-and-drop: they dump and restore a shape into // some bitwise-copiable data (might use streams too...) // ------------------------------------------------------------------------ @@ -211,6 +217,12 @@ public: const wxColour& col) : DnDShape(pos, size, col) { + wxLogMessage("DnDTriangularShape is being created"); + } + + virtual ~DnDTriangularShape() + { + wxLogMessage("DnDTriangularShape is being deleted"); } virtual Kind GetKind() const { return Triangle; } @@ -242,6 +254,12 @@ public: const wxColour& col) : DnDShape(pos, size, col) { + wxLogMessage("DnDRectangularShape is being created"); + } + + virtual ~DnDRectangularShape() + { + wxLogMessage("DnDRectangularShape is being deleted"); } virtual Kind GetKind() const { return Rectangle; } @@ -273,6 +291,12 @@ public: const wxColour& col) : DnDShape(pos, size, col) { + wxLogMessage("DnDEllipticShape is being created"); + } + + virtual ~DnDEllipticShape() + { + wxLogMessage("DnDEllipticShape is being deleted"); } virtual Kind GetKind() const { return Ellipse; } @@ -299,9 +323,24 @@ class DnDShapeDataObject : public wxDataObject public: // ctor doesn't copy the pointer, so it shouldn't go away while this object // is alive - DnDShapeDataObject(DnDShape *shape) + DnDShapeDataObject(DnDShape *shape = (DnDShape *)NULL) { - m_shape = shape; + if ( shape ) + { + // we need to copy the shape because the one we're handled may be + // deleted while it's still on the clipboard (for example) - and we + // reuse the serialisation methods here to copy it + void *buf = malloc(shape->DnDShape::GetDataSize()); + shape->GetDataHere(buf); + m_shape = DnDShape::New(buf); + + free(buf); + } + else + { + // nothing to copy + m_shape = NULL; + } // this string should uniquely identify our format, but is otherwise // arbitrary @@ -312,36 +351,51 @@ public: m_hasBitmap = FALSE; } - // accessors - DnDShape *GetShape() const { return m_shape; } + virtual ~DnDShapeDataObject() { delete m_shape; } + + // after a call to this function, the shape is owned by the caller and it + // is responsible for deleting it! + // + // NB: a better solution would be to make DnDShapes ref counted and this + // is what should probably be done in a real life program, otherwise + // the ownership problems become too complicated really fast + DnDShape *GetShape() + { + DnDShape *shape = m_shape; + + m_shape = (DnDShape *)NULL; + m_hasBitmap = FALSE; + + return shape; + } // implement base class pure virtuals // ---------------------------------- - virtual wxDataFormat GetPreferredFormat() const + virtual wxDataFormat GetPreferredFormat(Direction WXUNUSED(dir)) const { return m_formatShape; } - virtual size_t GetFormatCount(bool outputOnlyToo) const + virtual size_t GetFormatCount(Direction dir) const { // our custom format is supported by both GetData() and SetData() size_t nFormats = 1; - if ( outputOnlyToo ) + if ( dir == Get ) { // but the bitmap format(s) are only supported for output - nFormats += m_dataobj.GetFormatCount(); + nFormats += m_dataobj.GetFormatCount(dir); } return nFormats; } - virtual void GetAllFormats(wxDataFormat *formats, bool outputOnlyToo) const + virtual void GetAllFormats(wxDataFormat *formats, Direction dir) const { formats[0] = m_formatShape; - if ( outputOnlyToo ) + if ( dir == Get ) { - m_dataobj.GetAllFormats(&formats[1]); + m_dataobj.GetAllFormats(&formats[1], dir); } } @@ -356,7 +410,7 @@ public: if ( !m_hasBitmap ) CreateBitmap(); - return m_dataobj.GetDataSize(format); + return m_dataobj.GetDataSize(); } } @@ -370,16 +424,15 @@ public: } else { - wxASSERT_MSG( format == wxDF_BITMAP, "unsupported format" ); - if ( !m_hasBitmap ) CreateBitmap(); - return m_dataobj.GetDataHere(format, pBuf); + return m_dataobj.GetDataHere(pBuf); } } - virtual bool SetData(const wxDataFormat& format, const void *buf) + virtual bool SetData(const wxDataFormat& format, + size_t len, const void *buf) { wxCHECK_MSG( format == m_formatShape, FALSE, "unsupported format" ); @@ -465,7 +518,7 @@ public: void OnDrag(wxMouseEvent& event); void OnPaint(wxPaintEvent& event); - void OnDrop(long x, long y, DnDShape *shape); + void OnDrop(wxCoord x, wxCoord y, DnDShape *shape); private: DnDShape *m_shape; @@ -483,33 +536,34 @@ class DnDShapeDropTarget : public wxDropTarget { public: DnDShapeDropTarget(DnDShapeFrame *frame) + : wxDropTarget(new DnDShapeDataObject) { m_frame = frame; - - // the same as used by DnDShapeDataObject - m_formatShape.SetId(shapeFormatId); } // override base class (pure) virtuals - virtual void OnEnter() - { m_frame->SetStatusText("Mouse entered the frame"); } + virtual wxDragResult OnEnter(wxCoord x, wxCoord y, wxDragResult def) + { m_frame->SetStatusText("Mouse entered the frame"); + return OnDragOver(x, y, def); } virtual void OnLeave() { m_frame->SetStatusText("Mouse left the frame"); } - virtual bool OnDrop(long x, long y, const void *pData) + virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def) { - m_frame->OnDrop(x, y, DnDShape::New(pData)); + if ( !GetData() ) + { + wxLogError("Failed to get drag and drop data"); - return TRUE; - } + return wxDragNone; + } -protected: - virtual size_t GetFormatCount() const { return 1; } - virtual wxDataFormat GetFormat(size_t WXUNUSED(n)) const - { return m_formatShape; } + m_frame->OnDrop(x, y, + ((DnDShapeDataObject *)GetDataObject())->GetShape()); + + return def; + } private: DnDShapeFrame *m_frame; - wxDataFormat m_formatShape; }; // ---------------------------------------------------------------------------- @@ -528,8 +582,7 @@ enum Menu_Paste, Menu_CopyBitmap, Menu_PasteBitmap, - Menu_ToBeGreyed, /* for testing */ - Menu_ToBeDeleted, /* for testing */ + Menu_CopyFiles, Menu_Shape_New = 500, Menu_Shape_Edit, Menu_Shape_Clear, @@ -549,6 +602,7 @@ BEGIN_EVENT_TABLE(DnDFrame, wxFrame) EVT_MENU(Menu_Paste, DnDFrame::OnPaste) EVT_MENU(Menu_CopyBitmap, DnDFrame::OnCopyBitmap) EVT_MENU(Menu_PasteBitmap,DnDFrame::OnPasteBitmap) + EVT_MENU(Menu_CopyFiles, DnDFrame::OnCopyFiles) EVT_UPDATE_UI(Menu_Paste, DnDFrame::OnUpdateUIPasteText) EVT_UPDATE_UI(Menu_PasteBitmap, DnDFrame::OnUpdateUIPasteBitmap) @@ -575,7 +629,7 @@ BEGIN_EVENT_TABLE(DnDShapeFrame, wxFrame) END_EVENT_TABLE() BEGIN_EVENT_TABLE(DnDShapeDialog, wxDialog) - EVT_BUTTON(Button_Colour, OnColour) + EVT_BUTTON(Button_Colour, DnDShapeDialog::OnColour) END_EVENT_TABLE() // ============================================================================ @@ -585,22 +639,50 @@ END_EVENT_TABLE() // `Main program' equivalent, creating windows and returning main app frame bool DnDApp::OnInit() { + // load our ressources + wxPathList pathList; + pathList.Add("."); +#ifdef __WXMSW__ + pathList.Add("./Debug"); + pathList.Add("./Release"); +#endif // wxMSW + + wxString path = pathList.FindValidPath("dnd.wxr"); + if ( !path ) + { + wxLogError("Can't find the resource file dnd.wxr in the current " + "directory, aborting."); + + return FALSE; + } + + wxDefaultResourceTable->ParseResourceFile(path); + + // switch on trace messages +#if defined(__WXGTK__) + wxLog::AddTraceMask(_T("clipboard")); +#elif defined(__WXMSW__) + wxLog::AddTraceMask(wxTRACE_OleCalls); +#endif + #if wxUSE_LIBPNG wxImage::AddHandler( new wxPNGHandler ); #endif + // under X we usually want to use the primary selection by default (which + // is shared with other apps) + wxTheClipboard->UsePrimarySelection(); + // create the main frame window DnDFrame *frame = new DnDFrame((wxFrame *) NULL, "Drag-and-Drop/Clipboard wxWindows Sample", - 50, 50, 450, 340); + 10, 10, 450, 340); // activate it frame->Show(TRUE); SetTopWindow(frame); - wxDefaultResourceTable->ParseResourceFile("dnd.wxr"); - return TRUE; } @@ -623,7 +705,7 @@ DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h) file_menu->Append(Menu_Quit, "E&xit"); wxMenu *log_menu = new wxMenu; - log_menu->Append(Menu_Clear, "Clear\tDel"); + log_menu->Append(Menu_Clear, "Clear\tCtrl-L"); wxMenu *help_menu = new wxMenu; help_menu->Append(Menu_Help, "&Help..."); @@ -636,6 +718,8 @@ DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h) clip_menu->AppendSeparator(); clip_menu->Append(Menu_CopyBitmap, "&Copy bitmap\tAlt+C"); clip_menu->Append(Menu_PasteBitmap, "&Paste bitmap\tAlt+V"); + clip_menu->AppendSeparator(); + clip_menu->Append(Menu_CopyFiles, "&Copy files\tCtrl+F"); wxMenuBar *menu_bar = new wxMenuBar; menu_bar->Append(file_menu, "&File"); @@ -660,11 +744,7 @@ DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h) wxTE_MULTILINE | wxTE_READONLY | wxSUNKEN_BORDER ); -#ifdef __WXMSW__ - // redirect log messages to the text window and switch on OLE messages - // logging - wxLog::AddTraceMask(wxTRACE_OleCalls); -#endif + // redirect log messages to the text window m_pLog = new wxLogTextCtrl(m_ctrlLog); m_pLogPrev = wxLog::SetActiveTarget(m_pLog); @@ -727,11 +807,23 @@ void DnDFrame::OnPaint(wxPaintEvent& WXUNUSED(event)) void DnDFrame::OnUpdateUIPasteText(wxUpdateUIEvent& event) { +#ifdef __WXDEBUG__ + // too many trace messages if we don't do it - this function is called + // very often + wxLogNull nolog; +#endif + event.Enable( wxTheClipboard->IsSupported(wxDF_TEXT) ); } void DnDFrame::OnUpdateUIPasteBitmap(wxUpdateUIEvent& event) { +#ifdef __WXDEBUG__ + // too many trace messages if we don't do it - this function is called + // very often + wxLogNull nolog; +#endif + event.Enable( wxTheClipboard->IsSupported(wxDF_BITMAP) ); } @@ -797,6 +889,8 @@ void DnDFrame::OnHelp(wxCommandEvent& /* event */) void DnDFrame::OnLogClear(wxCommandEvent& /* event */ ) { m_ctrlLog->Clear(); + m_ctrlText->Clear(); + m_ctrlFile->Clear(); } void DnDFrame::OnLeftDown(wxMouseEvent &WXUNUSED(event) ) @@ -805,7 +899,19 @@ void DnDFrame::OnLeftDown(wxMouseEvent &WXUNUSED(event) ) { // start drag operation wxTextDataObject textData(m_strText); - wxDropSource source(textData, this, wxICON(mondrian)); +/* + wxFileDataObject textData; + textData.AddFile( "/file1.txt" ); + textData.AddFile( "/file2.txt" ); +*/ + wxDropSource source(textData, this + +#ifdef __WXMSW__ + ,wxCURSOR_PENCIL, // for copy + wxCURSOR_SPRAYCAN, // for move + wxCURSOR_QUESTION_ARROW // for nothing +#endif + ); const char *pc; @@ -825,18 +931,13 @@ void DnDFrame::OnLeftDown(wxMouseEvent &WXUNUSED(event) ) void DnDFrame::OnRightDown(wxMouseEvent &event ) { - wxMenu *menu = new wxMenu; - - menu->Append(Menu_Drag, "&Test drag..."); - menu->Append(Menu_About, "&About"); - menu->Append(Menu_Quit, "E&xit"); - menu->Append(Menu_ToBeDeleted, "To be deleted"); - menu->Append(Menu_ToBeGreyed, "To be greyed"); + wxMenu menu("Dnd sample menu"); - menu->Delete( Menu_ToBeDeleted ); - menu->Enable( Menu_ToBeGreyed, FALSE ); + menu.Append(Menu_Drag, "&Test drag..."); + menu.AppendSeparator(); + menu.Append(Menu_About, "&About"); - PopupMenu( menu, event.GetX(), event.GetY() ); + PopupMenu( &menu, event.GetX(), event.GetY() ); } DnDFrame::~DnDFrame() @@ -938,7 +1039,7 @@ void DnDFrame::OnPasteBitmap(wxCommandEvent& WXUNUSED(event)) } wxBitmapDataObject data; - if ( !wxTheClipboard->GetData(&data) ) + if ( !wxTheClipboard->GetData(data) ) { wxLogError(_T("Can't paste bitmap from the clipboard")); } @@ -952,6 +1053,58 @@ void DnDFrame::OnPasteBitmap(wxCommandEvent& WXUNUSED(event)) wxTheClipboard->Close(); } +// ---------------------------------------------------------------------------- +// file clipboard +// ---------------------------------------------------------------------------- + +void DnDFrame::OnCopyFiles(wxCommandEvent& WXUNUSED(event)) +{ +#ifdef __WXMSW__ + wxFileDialog dialog(this, "Select a file to copy", "", "", + "All files (*.*)|*.*", 0); + + wxArrayString filenames; + while ( dialog.ShowModal() == wxID_OK ) + { + filenames.Add(dialog.GetPath()); + } + + if ( !filenames.IsEmpty() ) + { + wxFileDataObject *dobj = new wxFileDataObject; + size_t count = filenames.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + dobj->AddFile(filenames[n]); + } + + wxClipboardLocker locker; + if ( !locker ) + { + wxLogError("Can't open clipboard"); + } + else + { + if ( !wxTheClipboard->AddData(dobj) ) + { + wxLogError("Can't copy file(s) to the clipboard"); + } + else + { + wxLogStatus(this, "%d file%s copied to the clipboard", + count, count == 1 ? "" : "s"); + } + } + } + else + { + wxLogStatus(this, "Aborted"); + } +#else // !MSW + wxLogError("Sorry, not implemented"); +#endif // MSW/!MSW +} + // --------------------------------------------------------------------------- // text clipboard // --------------------------------------------------------------------------- @@ -995,7 +1148,7 @@ void DnDFrame::OnPaste(wxCommandEvent& WXUNUSED(event)) } wxTextDataObject text; - if ( !wxTheClipboard->GetData(&text) ) + if ( !wxTheClipboard->GetData(text) ) { wxLogError(_T("Can't paste data from the clipboard")); } @@ -1012,21 +1165,21 @@ void DnDFrame::OnPaste(wxCommandEvent& WXUNUSED(event)) // Notifications called by the base class // ---------------------------------------------------------------------------- -bool DnDText::OnDropText( wxDropPointCoord, wxDropPointCoord, const wxChar *psz ) +bool DnDText::OnDropText(wxCoord, wxCoord, const wxString& text) { - m_pOwner->Append(psz); + m_pOwner->Append(text); return TRUE; } -bool DnDFile::OnDropFiles( wxDropPointCoord, wxDropPointCoord, size_t nFiles, - const wxChar* const aszFiles[]) +bool DnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& filenames) { + size_t nFiles = filenames.GetCount(); wxString str; str.Printf( _T("%d files dropped"), nFiles); m_pOwner->Append(str); for ( size_t n = 0; n < nFiles; n++ ) { - m_pOwner->Append(aszFiles[n]); + m_pOwner->Append(filenames[n]); } return TRUE; @@ -1134,8 +1287,6 @@ DnDShapeFrame::DnDShapeFrame(wxFrame *parent) : wxFrame(parent, -1, "Shape Frame", wxDefaultPosition, wxSize(250, 150)) { - SetBackgroundColour(*wxWHITE); - CreateStatusBar(); wxMenu *menuShape = new wxMenu; @@ -1159,16 +1310,20 @@ DnDShapeFrame::DnDShapeFrame(wxFrame *parent) SetDropTarget(new DnDShapeDropTarget(this)); m_shape = NULL; + + SetBackgroundColour(*wxWHITE); } DnDShapeFrame::~DnDShapeFrame() { - delete m_shape; + if (m_shape) + delete m_shape; } void DnDShapeFrame::SetShape(DnDShape *shape) { - delete m_shape; + if (m_shape) + delete m_shape; m_shape = shape; Refresh(); } @@ -1185,7 +1340,7 @@ void DnDShapeFrame::OnDrag(wxMouseEvent& event) // start drag operation DnDShapeDataObject shapeData(m_shape); - wxDropSource source(shapeData, this, wxICON(mondrian)); + wxDropSource source(shapeData, this); const char *pc = NULL; switch ( source.DoDragDrop(TRUE) ) @@ -1224,6 +1379,20 @@ void DnDShapeFrame::OnDrag(wxMouseEvent& event) //else: status text already set } +void DnDShapeFrame::OnDrop(wxCoord x, wxCoord y, DnDShape *shape) +{ + ms_lastDropTarget = this; + + wxPoint pt(x, y); + + wxString s; + s.Printf("Shape dropped at (%ld, %ld)", pt.x, pt.y); + SetStatusText(s); + + shape->Move(pt); + SetShape(shape); +} + void DnDShapeFrame::OnEditShape(wxCommandEvent& event) { DnDShapeDialog dlg(this, m_shape); @@ -1253,13 +1422,31 @@ void DnDShapeFrame::OnClearShape(wxCommandEvent& event) void DnDShapeFrame::OnCopyShape(wxCommandEvent& event) { if ( m_shape ) + { + wxClipboardLocker clipLocker; + if ( !clipLocker ) + { + wxLogError("Can't open the clipboard"); + + return; + } + wxTheClipboard->AddData(new DnDShapeDataObject(m_shape)); + } } void DnDShapeFrame::OnPasteShape(wxCommandEvent& event) { + wxClipboardLocker clipLocker; + if ( !clipLocker ) + { + wxLogError("Can't open the clipboard"); + + return; + } + DnDShapeDataObject shapeDataObject(NULL); - if ( wxTheClipboard->GetData(&shapeDataObject) ) + if ( wxTheClipboard->GetData(shapeDataObject) ) { SetShape(shapeDataObject.GetShape()); } @@ -1282,21 +1469,15 @@ void DnDShapeFrame::OnUpdateUIPaste(wxUpdateUIEvent& event) void DnDShapeFrame::OnPaint(wxPaintEvent& event) { if ( m_shape ) - m_shape->Draw(wxPaintDC(this)); + { + wxPaintDC dc(this); + + m_shape->Draw(dc); + } else + { event.Skip(); -} - -void DnDShapeFrame::OnDrop(long x, long y, DnDShape *shape) -{ - ms_lastDropTarget = this; - - wxString s; - s.Printf("Shape dropped at (%ld, %ld)", x, y); - SetStatusText(s); - - shape->Move(ScreenToClient(wxPoint(x, y))); - SetShape(shape); + } } // ----------------------------------------------------------------------------