]> git.saurik.com Git - wxWidgets.git/blob - samples/dnd/dnd.cpp
0b3e1c894fc4f87182b30339a64a03bf7620a56d
[wxWidgets.git] / samples / dnd / dnd.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: dnd.cpp
3 // Purpose: Drag and drop sample
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright:
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17
18 #ifndef WX_PRECOMP
19 #include "wx/wx.h"
20 #endif
21
22 #include "wx/intl.h"
23 #include "wx/log.h"
24
25 #include "wx/dnd.h"
26
27 #ifdef __WXMOTIF__
28 #error Sorry, drag and drop is not yet implemented on wxMotif.
29 #endif
30
31 #if defined(__WXGTK__) || defined(__WXMOTIF__)
32 #include "mondrian.xpm"
33 #endif
34
35 #include "wx/clipbrd.h"
36
37 // ----------------------------------------------------------------------------
38 // Derive two simple classes which just put in the listbox the strings (text or
39 // file names) we drop on them
40 // ----------------------------------------------------------------------------
41
42 // FIXME this is ugly and should be fixed in the library itself
43 #ifdef __WXMSW__
44 typedef long wxDropPointCoord;
45 #else // wxGTK
46 typedef int wxDropPointCoord;
47 #endif // MSW/GTK
48
49 class DnDText : public wxTextDropTarget
50 {
51 public:
52 DnDText(wxListBox *pOwner) { m_pOwner = pOwner; }
53
54 virtual bool OnDropText(wxDropPointCoord x, wxDropPointCoord y,
55 const wxChar* psz);
56
57 private:
58 wxListBox *m_pOwner;
59 };
60
61 class DnDFile : public wxFileDropTarget
62 {
63 public:
64 DnDFile(wxListBox *pOwner) { m_pOwner = pOwner; }
65
66 virtual bool OnDropFiles(wxDropPointCoord x, wxDropPointCoord y,
67 size_t nFiles, const wxChar* const aszFiles[] );
68
69 private:
70 wxListBox *m_pOwner;
71 };
72
73 // ----------------------------------------------------------------------------
74 // Define a new application type
75 // ----------------------------------------------------------------------------
76
77 class DnDApp : public wxApp
78 {
79 public:
80 bool OnInit();
81 };
82
83 IMPLEMENT_APP(DnDApp);
84
85 // ----------------------------------------------------------------------------
86 // Define a new frame type
87 // ----------------------------------------------------------------------------
88 class DnDFrame : public wxFrame
89 {
90 public:
91 DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h);
92 ~DnDFrame();
93
94 void OnPaint(wxPaintEvent& event);
95 void OnQuit (wxCommandEvent& event);
96 void OnAbout(wxCommandEvent& event);
97 void OnDrag (wxCommandEvent& event);
98 void OnHelp (wxCommandEvent& event);
99 void OnLogClear(wxCommandEvent& event);
100 void OnCopy(wxCommandEvent& event);
101 void OnPaste(wxCommandEvent& event);
102
103 void OnLeftDown(wxMouseEvent& event);
104 void OnRightDown(wxMouseEvent& event);
105
106 DECLARE_EVENT_TABLE()
107
108 private:
109 wxListBox *m_ctrlFile,
110 *m_ctrlText;
111 wxTextCtrl *m_ctrlLog;
112
113 wxLog *m_pLog, *m_pLogPrev;
114
115 wxString m_strText;
116 };
117
118 // ----------------------------------------------------------------------------
119 // IDs for the menu commands
120 // ----------------------------------------------------------------------------
121
122 enum
123 {
124 Menu_Quit = 1,
125 Menu_Drag,
126 Menu_About = 101,
127 Menu_Help,
128 Menu_Clear,
129 Menu_Copy,
130 Menu_Paste
131 };
132
133 BEGIN_EVENT_TABLE(DnDFrame, wxFrame)
134 EVT_MENU(Menu_Quit, DnDFrame::OnQuit)
135 EVT_MENU(Menu_About, DnDFrame::OnAbout)
136 EVT_MENU(Menu_Drag, DnDFrame::OnDrag)
137 EVT_MENU(Menu_Help, DnDFrame::OnHelp)
138 EVT_MENU(Menu_Clear, DnDFrame::OnLogClear)
139 EVT_MENU(Menu_Copy, DnDFrame::OnCopy)
140 EVT_MENU(Menu_Paste, DnDFrame::OnPaste)
141
142 EVT_LEFT_DOWN( DnDFrame::OnLeftDown)
143 EVT_RIGHT_DOWN( DnDFrame::OnRightDown)
144 EVT_PAINT( DnDFrame::OnPaint)
145 END_EVENT_TABLE()
146
147 // `Main program' equivalent, creating windows and returning main app frame
148 bool DnDApp::OnInit()
149 {
150 // create the main frame window
151 DnDFrame *frame = new DnDFrame((wxFrame *) NULL,
152 "Drag-and-Drop/Clipboard wxWindows Sample",
153 50, 50, 450, 340);
154
155 // activate it
156 frame->Show(TRUE);
157
158 SetTopWindow(frame);
159
160 return TRUE;
161 }
162
163 DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h)
164 : wxFrame(frame, -1, title, wxPoint(x, y), wxSize(w, h)),
165 m_strText("wxWindows drag & drop works :-)")
166
167 {
168 // frame icon and status bar
169 SetIcon(wxICON(mondrian));
170
171 CreateStatusBar();
172
173 // construct menu
174 wxMenu *file_menu = new wxMenu;
175 file_menu->Append(Menu_Drag, "&Test drag...");
176 file_menu->AppendSeparator();
177 file_menu->Append(Menu_Quit, "E&xit");
178
179 wxMenu *log_menu = new wxMenu;
180 log_menu->Append(Menu_Clear, "Clear");
181
182 wxMenu *help_menu = new wxMenu;
183 help_menu->Append(Menu_Help, "&Help...");
184 help_menu->AppendSeparator();
185 help_menu->Append(Menu_About, "&About");
186
187 wxMenu *clip_menu = new wxMenu;
188 clip_menu->Append(Menu_Copy, "&Copy\tCtrl+C");
189 clip_menu->Append(Menu_Paste, "&Paste\tCtrl+V");
190
191 wxMenuBar *menu_bar = new wxMenuBar;
192 menu_bar->Append(file_menu, "&File");
193 menu_bar->Append(log_menu, "&Log");
194 menu_bar->Append(clip_menu, "&Clipboard");
195 menu_bar->Append(help_menu, "&Help");
196
197 SetMenuBar(menu_bar);
198
199 // make a panel with 3 subwindows
200 wxPoint pos(0, 0);
201 wxSize size(400, 200);
202
203 wxString strFile("Drop files here!"), strText("Drop text on me");
204
205 m_ctrlFile = new wxListBox(this, -1, pos, size, 1, &strFile, wxLB_HSCROLL);
206 m_ctrlText = new wxListBox(this, -1, pos, size, 1, &strText, wxLB_HSCROLL);
207
208 m_ctrlLog = new wxTextCtrl(this, -1, "", pos, size,
209 wxTE_MULTILINE | wxTE_READONLY |
210 wxSUNKEN_BORDER );
211
212 // redirect log messages to the text window (don't forget to delete it!)
213 m_pLog = new wxLogTextCtrl(m_ctrlLog);
214 m_pLogPrev = wxLog::SetActiveTarget(m_pLog);
215
216 // associate drop targets with 2 text controls
217 m_ctrlFile->SetDropTarget(new DnDFile(m_ctrlFile));
218 m_ctrlText->SetDropTarget( new DnDText(m_ctrlText) );
219
220 wxLayoutConstraints *c;
221
222 // Top-left listbox
223 c = new wxLayoutConstraints;
224 c->left.SameAs(this, wxLeft);
225 c->top.SameAs(this, wxTop);
226 c->right.PercentOf(this, wxRight, 50);
227 c->height.PercentOf(this, wxHeight, 40);
228 m_ctrlFile->SetConstraints(c);
229
230 // Top-right listbox
231 c = new wxLayoutConstraints;
232 c->left.SameAs (m_ctrlFile, wxRight);
233 c->top.SameAs (this, wxTop);
234 c->right.SameAs (this, wxRight);
235 c->height.PercentOf(this, wxHeight, 40);
236 m_ctrlText->SetConstraints(c);
237
238 // Lower text control
239 c = new wxLayoutConstraints;
240 c->left.SameAs (this, wxLeft);
241 c->right.SameAs (this, wxRight);
242 c->height.PercentOf(this, wxHeight, 40);
243 c->top.SameAs(m_ctrlText, wxBottom);
244 m_ctrlLog->SetConstraints(c);
245
246 // construct menu
247 wxMenu *file_menu = new wxMenu;
248 file_menu->Append(Menu_Drag, "&Test drag...");
249 file_menu->AppendSeparator();
250 file_menu->Append(Menu_Quit, "E&xit");
251
252 wxMenu *log_menu = new wxMenu;
253 log_menu->Append(Menu_Clear, "Clear");
254
255 wxMenu *help_menu = new wxMenu;
256 help_menu->Append(Menu_Help, "&Help...");
257 help_menu->AppendSeparator();
258 help_menu->Append(Menu_About, "&About");
259
260 wxMenuBar *menu_bar = new wxMenuBar;
261 menu_bar->Append(file_menu, "&File");
262 menu_bar->Append(log_menu, "&Log");
263 menu_bar->Append(help_menu, "&Help");
264
265 SetMenuBar(menu_bar);
266
267 // make a panel with 3 subwindows
268 wxPoint pos(0, 0);
269 wxSize size(400, 200);
270
271 wxString strFile("Drop files here!"), strText("Drop text on me");
272
273 m_ctrlFile = new wxListBox(this, -1, pos, size, 1, &strFile, wxLB_HSCROLL);
274 m_ctrlText = new wxListBox(this, -1, pos, size, 1, &strText, wxLB_HSCROLL);
275
276 m_ctrlLog = new wxTextCtrl(this, -1, "", pos, size,
277 wxTE_MULTILINE | wxTE_READONLY |
278 wxSUNKEN_BORDER );
279
280 // redirect log messages to the text window (don't forget to delete it!)
281 m_pLog = new wxLogTextCtrl(m_ctrlLog);
282 m_pLogPrev = wxLog::SetActiveTarget(m_pLog);
283
284 // associate drop targets with 2 text controls
285 m_ctrlFile->SetDropTarget(new DnDFile(m_ctrlFile));
286 m_ctrlText->SetDropTarget(new DnDText(m_ctrlText));
287
288 wxLayoutConstraints *c;
289
290 // Top-left listbox
291 c = new wxLayoutConstraints;
292 c->left.SameAs(this, wxLeft);
293 c->top.SameAs(this, wxTop);
294 c->right.PercentOf(this, wxRight, 50);
295 c->height.PercentOf(this, wxHeight, 40);
296 m_ctrlFile->SetConstraints(c);
297
298 // Top-right listbox
299 c = new wxLayoutConstraints;
300 c->left.SameAs (m_ctrlFile, wxRight);
301 c->top.SameAs (this, wxTop);
302 c->right.SameAs (this, wxRight);
303 c->height.PercentOf(this, wxHeight, 40);
304 m_ctrlText->SetConstraints(c);
305
306 // Lower text control
307 c = new wxLayoutConstraints;
308 c->left.SameAs (this, wxLeft);
309 c->right.SameAs (this, wxRight);
310 c->height.PercentOf(this, wxHeight, 40);
311 c->top.SameAs(m_ctrlText, wxBottom);
312 m_ctrlLog->SetConstraints(c);
313
314 SetAutoLayout(TRUE);
315 }
316
317 void DnDFrame::OnQuit(wxCommandEvent& /* event */)
318 {
319 Close(TRUE);
320 }
321
322 void DnDFrame::OnPaint(wxPaintEvent& /*event*/)
323 {
324 int w = 0;
325 int h = 0;
326 GetClientSize( &w, &h );
327
328 wxPaintDC dc(this);
329 dc.SetFont( wxFont( 24, wxDECORATIVE, wxNORMAL, wxNORMAL, FALSE, "charter" ) );
330 dc.DrawText( "Drag text from here!", 20, h-35 );
331 }
332
333 void DnDFrame::OnDrag(wxCommandEvent& /* event */)
334 {
335 wxString strText = wxGetTextFromUser
336 (
337 "After you enter text in this dialog, press any mouse\n"
338 "button in the bottom (empty) part of the frame and \n"
339 "drag it anywhere - you will be in fact dragging the\n"
340 "text object containing this text",
341 "Please enter some text", m_strText, this
342 );
343
344 m_strText = strText;
345 }
346
347 void DnDFrame::OnAbout(wxCommandEvent& /* event */)
348 {
349 wxMessageBox("Drag-&-Drop Demo\n"
350 "Please see \"Help|Help...\" for details\n"
351 "Copyright (c) 1998 Vadim Zeitlin",
352 "About wxDnD",
353 wxICON_INFORMATION | wxOK,
354 this);
355 }
356
357 void DnDFrame::OnHelp(wxCommandEvent& /* event */)
358 {
359 wxMessageDialog dialog(this,
360 "This small program demonstrates drag & drop support in wxWindows. The program window\n"
361 "consists of 3 parts: the bottom pane is for debug messages, so that you can see what's\n"
362 "going on inside. The top part is split into 2 listboxes, the left one accepts files\n"
363 "and the right one accepts text.\n"
364 "\n"
365 "To test wxDropTarget: open wordpad (write.exe), select some text in it and drag it to\n"
366 "the right listbox (you'll notice the usual visual feedback, i.e. the cursor will change).\n"
367 "Also, try dragging some files (you can select several at once) from Windows Explorer (or \n"
368 "File Manager) to the left pane. Hold down Ctrl/Shift keys when you drop text (doesn't \n"
369 "work with files) and see what changes.\n"
370 "\n"
371 "To test wxDropSource: just press any mouse button on the empty zone of the window and drag\n"
372 "it to wordpad or any other droptarget accepting text (and of course you can just drag it\n"
373 "to the right pane). Due to a lot of trace messages, the cursor might take some time to \n"
374 "change, don't release the mouse button until it does. You can change the string being\n"
375 "dragged in in \"File|Test drag...\" dialog.\n"
376 "\n"
377 "\n"
378 "Please send all questions/bug reports/suggestions &c to \n"
379 "Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>",
380 "wxDnD Help");
381
382 dialog.ShowModal();
383 }
384
385 void DnDFrame::OnLogClear(wxCommandEvent& /* event */ )
386 {
387 m_ctrlLog->Clear();
388 }
389
390 void DnDFrame::OnLeftDown(wxMouseEvent &WXUNUSED(event) )
391 {
392 if ( !m_strText.IsEmpty() )
393 {
394 // start drag operation
395 #ifdef __WXMSW__
396 wxTextDataObject textData(m_strText);
397 wxDropSource dragSource( textData, this );
398 #else
399 wxDropSource dragSource( new wxTextDataObject (m_strText), this, wxIcon(mondrian_xpm) );
400 #endif
401 const char *pc;
402
403 switch ( dragSource.DoDragDrop(TRUE) )
404 {
405 case wxDragError: pc = "Error!"; break;
406 case wxDragNone: pc = "Nothing"; break;
407 case wxDragCopy: pc = "Copied"; break;
408 case wxDragMove: pc = "Moved"; break;
409 case wxDragCancel: pc = "Cancelled"; break;
410 default: pc = "Huh?"; break;
411 }
412
413 SetStatusText(wxString("Drag result: ") + pc);
414 }
415 }
416
417 void DnDFrame::OnRightDown(wxMouseEvent &event )
418 {
419 wxMenu *menu = new wxMenu;
420
421 menu->Append(Menu_Drag, "&Test drag...");
422 menu->Append(Menu_About, "&About");
423 menu->Append(Menu_Quit, "E&xit");
424
425 PopupMenu( menu, event.GetX(), event.GetY() );
426 }
427
428 DnDFrame::~DnDFrame()
429 {
430 if ( m_pLog != NULL ) {
431 if ( wxLog::SetActiveTarget(m_pLogPrev) == m_pLog )
432 delete m_pLog;
433 }
434 }
435
436 // ---------------------------------------------------------------------------
437 // clipboard
438 // ---------------------------------------------------------------------------
439
440 void DnDFrame::OnCopy(wxCommandEvent& WXUNUSED(event))
441 {
442 if ( !wxTheClipboard->Open() )
443 {
444 wxLogError("Can't open clipboard.");
445
446 return;
447 }
448
449 if ( !wxTheClipboard->AddData(new wxTextDataObject(m_strText)) )
450 {
451 wxLogError("Can't copy data to the clipboard");
452 }
453 else
454 {
455 wxLogMessage("Text '%s' put on the clipboard", m_strText.c_str());
456 }
457
458 wxTheClipboard->Close();
459 }
460
461 void DnDFrame::OnPaste(wxCommandEvent& WXUNUSED(event))
462 {
463 if ( !wxTheClipboard->Open() )
464 {
465 wxLogError("Can't open clipboard.");
466
467 return;
468 }
469
470 if ( !wxTheClipboard->IsSupported(wxDF_TEXT) )
471 {
472 wxLogWarning("No text data on clipboard");
473
474 return;
475 }
476
477 wxTextDataObject text;
478 if ( !wxTheClipboard->GetData(&text) )
479 {
480 wxLogError("Can't paste data from the clipboard");
481 }
482 else
483 {
484 wxLogMessage("Text '%s' pasted from the clipboard",
485 text.GetText().c_str());
486 }
487
488 wxTheClipboard->Close();
489 }
490
491 // ----------------------------------------------------------------------------
492 // Notifications called by the base class
493 // ----------------------------------------------------------------------------
494 bool DnDText::OnDropText( wxDropPointCoord, wxDropPointCoord, const wxChar *psz )
495 {
496 m_pOwner->Append(psz);
497
498 return TRUE;
499 }
500
501 bool DnDFile::OnDropFiles( wxDropPointCoord, wxDropPointCoord, size_t nFiles,
502 const wxChar* const aszFiles[])
503 {
504 wxString str;
505 str.Printf( _T("%d files dropped"), nFiles);
506 m_pOwner->Append(str);
507 for ( size_t n = 0; n < nFiles; n++ ) {
508 m_pOwner->Append(aszFiles[n]);
509 }
510
511 return TRUE;
512 }