/*************************************************************************** CClipboard.cpp (c) 2000-2007 Benoit Minisini This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ***************************************************************************/ #define __CCLIPBOARD_CPP #include "gambas.h" #include #include #include #include #include #include #include #include #include #include #include "CWidget.h" #include "CImage.h" #include "CClipboard.h" #include "CTreeView.h" CDRAG_INFO CDRAG_info = { 0 }; bool CDRAG_dragging = false; static void *CLASS_Image; //static CCURSOR *_cursor = 0; static CPICTURE *_picture = 0; static int _picture_x = -1; static int _picture_y = -1; static int get_type(QMimeSource *src) { if (QTextDrag::canDecode(src)) return 1; else if (QImageDrag::canDecode(src)) return 2; else return 0; } static QCString get_format(QMimeSource *src, int i = 0, bool charset = false) { QCString format = src->format(i); if (!charset) { int pos = format.find(';'); if (pos >= 0) format = format.left(pos); } return format; } static void get_formats(QMimeSource *src, GB_ARRAY array) { int i, j; QCString fmt; char *str; for (i = 0;; i++) { if (!src->format(i)) break; fmt = get_format(src, i, true); if (*fmt < 'a' || *fmt > 'z') continue; for (j = 0; j < GB.Array.Count(array); j++) { if (strcasecmp(fmt, *((char **)GB.Array.Get(array, j))) == 0) break; } if (j < GB.Array.Count(array)) continue; //fmt = get_format(src, i); GB.NewString(&str, fmt, 0); *((char **)GB.Array.Add(array)) = str; } } static void paste(QMimeSource *data, const char *fmt) { CIMAGE *img; if (fmt) { if (!data->provides(fmt)) { GB.ReturnNull(); return; } } if (QTextDrag::canDecode(data)) { QString text; QCString subtype; if (fmt) { subtype = fmt; if (subtype.left(5) == "text/") subtype = subtype.mid(5); else subtype = 0; } QTextDrag::decode(data, text, subtype); GB.ReturnNewZeroString(TO_UTF8(text)); } else if (QImageDrag::canDecode(data)) { GB.New(POINTER(&img), GB.FindClass("Image"), 0, 0); QImageDrag::decode(data, *(img->image)); img->image->convertDepth(32); GB.ReturnObject(img); } else GB.ReturnNull(); } /*************************************************************************** Clipboard ***************************************************************************/ BEGIN_METHOD_VOID(CCLIPBOARD_init) CLASS_Image = GB.FindClass("Image"); END_METHOD BEGIN_METHOD_VOID(CCLIPBOARD_clear) QApplication::clipboard()->clear(); END_METHOD BEGIN_PROPERTY(CCLIPBOARD_format) GB.ReturnNewZeroString(get_format(QApplication::clipboard()->data())); END_PROPERTY BEGIN_PROPERTY(CCLIPBOARD_formats) GB_ARRAY array; GB.Array.New(&array, GB_T_STRING, 0); get_formats(QApplication::clipboard()->data(), array); GB.ReturnObject(array); END_PROPERTY BEGIN_PROPERTY(CCLIPBOARD_type) GB.ReturnInteger(get_type(QApplication::clipboard()->data())); END_PROPERTY BEGIN_METHOD(CCLIPBOARD_copy, GB_VARIANT data; GB_STRING format) QCString format; int i; for (i = 0; i < 10; i++) { if (VARG(data).type == GB_T_STRING) { QString text = TO_QSTRING(VARG(data)._string.value); QTextDrag *drag = new QTextDrag(text); if (MISSING(format)) format = "plain"; else { format = GB.ToZeroString(ARG(format)); if (format.left(5) != "text/") goto _BAD_FORMAT; format = format.mid(5); if (format.length() == 0) goto _BAD_FORMAT; } drag->setSubtype(format); //drag->setText(text); QApplication::clipboard()->setData(drag, QClipboard::Clipboard); } else if (VARG(data).type >= GB_T_OBJECT && GB.Is(VARG(data)._object.value, CLASS_Image)) { CIMAGE *img; if (!MISSING(format)) goto _BAD_FORMAT; img = (CIMAGE *)VARG(data)._object.value; QApplication::clipboard()->setImage(*(img->image), QClipboard::Clipboard); } else goto _BAD_FORMAT; qApp->eventLoop()->processEvents(QEventLoop::ExcludeUserInput, 20); if (QApplication::clipboard()->ownsClipboard()) break; } //qDebug("ownsClipboard: %d", QApplication::clipboard()->ownsClipboard()); return; _BAD_FORMAT: GB.Error("Bad clipboard format"); END_METHOD BEGIN_METHOD(CCLIPBOARD_paste, GB_STRING format) paste(QApplication::clipboard()->data(), MISSING(format) ? NULL : GB.ToZeroString(ARG(format))); END_METHOD GB_DESC CClipboardDesc[] = { GB_DECLARE("Clipboard", 0), GB_VIRTUAL_CLASS(), GB_CONSTANT("None", "i", 0), GB_CONSTANT("Text", "i", 1), GB_CONSTANT("Image", "i", 2), GB_STATIC_METHOD("_init", NULL, CCLIPBOARD_init, NULL), GB_STATIC_METHOD("Clear", NULL, CCLIPBOARD_clear, NULL), GB_STATIC_PROPERTY_READ("Format", "s", CCLIPBOARD_format), GB_STATIC_PROPERTY_READ("Formats", "String[]", CCLIPBOARD_formats), GB_STATIC_PROPERTY_READ("Type", "i", CCLIPBOARD_type), GB_STATIC_METHOD("Copy", NULL, CCLIPBOARD_copy, "(Data)v[(Format)s]"), GB_STATIC_METHOD("Paste", "v", CCLIPBOARD_paste, "[(Format)s]"), GB_END_DECLARE }; /** Drag frame ***********************************************************/ //MyDragFrame::MyDragFrame() : QWidget(0, 0, Qt::WType_TopLevel | Qt::WStyle_Customize | Qt::WStyle_NoBorder | Qt::WStyle_StaysOnTop | Qt::WX11BypassWM) MyDragFrame::MyDragFrame(QWidget *parent) : QWidget(parent, 0, Qt::WStyle_Customize | Qt::WStyle_NoBorder | Qt::WX11BypassWM) { setPaletteBackgroundColor(Qt::black); } /*MyDragFrame::paintEvent(QPaintEvent *e) { }*/ static QWidget *_frame[4] = { 0 }; static bool _frame_visible = false; static CWIDGET *_frame_control =0; static void hide_frame(CWIDGET *control) { int i; if (!_frame_visible) return; if (control && control != _frame_control) return; for (i = 0; i < 4; i++) delete _frame[i]; _frame_visible = false; } void CDRAG_hide_frame(CWIDGET *control) { hide_frame(control); } static void show_frame(CWIDGET *control, int x, int y, int w, int h) { QWidget *wid; //QPoint p = wid->mapToGlobal(QPoint(0, 0)); int i; if (GB.Is(control, CLASS_Container)) wid = QCONTAINER(control); else wid = QWIDGET(control); if (w <= 0 || h <= 0) { x = y = 0; w = wid->width(); h = wid->height(); } //x += p.x(); //y += p.y(); if (!_frame_visible) { for (i = 0; i < 4; i++) _frame[i] = new MyDragFrame(wid); } //x -= 2; //y -= 2; //w += 4; //h += 4; if (w < 2 || h < 2) return; _frame[0]->setGeometry(x, y, w, 2); _frame[1]->setGeometry(x, y, 2, h); _frame[2]->setGeometry(x + w - 2, y, 2, h); _frame[3]->setGeometry(x, y + h - 2, w, 2); for (i = 0; i < 4; i++) _frame[i]->show(); _frame_control = control; _frame_visible = true; } /** Drag *****************************************************************/ void CDRAG_clear(bool valid) { if (valid) CDRAG_info.valid++; else CDRAG_info.valid--; if (CDRAG_info.valid == 0) CLEAR(&CDRAG_info); } static void post_exit_drag(intptr_t param) { CDRAG_dragging = false; } void CDRAG_drag(CWIDGET *source, GB_VARIANT_VALUE *data, GB_STRING *fmt) { QDragObject *drag; QCString format; CIMAGE *img; if (GB.CheckObject(source)) return; if (CDRAG_dragging) { GB.Error("Undergoing drag"); return; } if (data->type == GB_T_STRING) { drag = new QTextDrag(source->widget); if (fmt == NULL) format = "plain"; else { format = GB.ToZeroString(fmt); if (format.left(5) != "text/") goto _BAD_FORMAT; format = format.mid(5); if (format.length() == 0) goto _BAD_FORMAT; } ((QTextDrag *)drag)->setText(data->_string.value); ((QTextDrag *)drag)->setSubtype(format); } else if (data->type >= GB_T_OBJECT && GB.Is(data->_object.value, CLASS_Image)) { if (fmt) goto _BAD_FORMAT; drag = new QImageDrag(source->widget); img = (CIMAGE *)data->_object.value; ((QImageDrag *)drag)->setImage(*(img->image)); } else goto _BAD_FORMAT; if (_picture) { //QPoint p(_cursor->x, _cursor->y); //pict = _cursor->picture; if (_picture_x >= 0 && _picture_y >= 0) drag->setPixmap(*(_picture->pixmap), QPoint(_picture_x, _picture_y)); else drag->setPixmap(*(_picture->pixmap)); } CDRAG_dragging = true; drag->drag(); hide_frame(NULL); GB.Post((GB_POST_FUNC)post_exit_drag, 0); return; _BAD_FORMAT: GB.Error("Bad drag format"); } bool CDRAG_drag_enter(QWidget *w, CWIDGET *control, QDropEvent *e) { bool cancel; //qDebug("CDRAG_drag_enter: (%s %p) %d", GB.GetClassName(control), control, w->inherits("QListView")); // Hack for QScrollView if (CWIDGET_test_flag(control, WF_SCROLLVIEW) && QWIDGET(control)->inherits("MyListView")) ((MyListView *)QWIDGET(control))->contentsDragEnterEvent((QDragEnterEvent *)e); if (!GB.CanRaise(control, EVENT_Drag)) { if (!GB.CanRaise(control, EVENT_DragMove) && GB.CanRaise(control, EVENT_Drop)) e->acceptAction(); else e->ignore(); return true; } CDRAG_clear(true); CDRAG_info.drop = e; cancel = GB.Raise(control, EVENT_Drag, 0); CDRAG_clear(false); if (cancel) e->ignore(); else e->acceptAction(true); return cancel; } bool CDRAG_drag_move(QWidget *w, CWIDGET *control, QDropEvent *e) { bool accepted; bool cancel; QPoint p; //qDebug("CDRAG_drag_move: widget = %p control = %p", w, control); //qDebug("CDRAG_drag_move: (%s %p) %d", GB.GetClassName(control), control, w->inherits("QListView")); /*if (!e->isAccepted()) return true;*/ // Hack for QScrollView if (CWIDGET_test_flag(control, WF_SCROLLVIEW) && QWIDGET(control)->inherits("MyListView")) { accepted = e->isAccepted(); ((MyListView *)QWIDGET(control))->contentsDragMoveEvent((QDragMoveEvent *)e); if (accepted) e->acceptAction(); else e->ignore(); } if (!GB.CanRaise(control, EVENT_DragMove)) { /*if (GB.CanRaise(control, EVENT_Drop)) e->accept(); else e->ignore();*/ return true; } CDRAG_clear(true); CDRAG_info.drop = e; p = e->pos(); p = w->mapTo(QWIDGET(control), p); CDRAG_info.x = p.x(); CDRAG_info.y = p.y(); cancel = GB.Raise(control, EVENT_DragMove, 0); if (cancel) CDRAG_info.drop->ignore(); else CDRAG_info.drop->acceptAction(true); CDRAG_clear(false); return cancel; } void CDRAG_drag_drop(QWidget *w, CWIDGET *control, QDropEvent *e) { QPoint p; //hide_frame(); if (!GB.CanRaise(control, EVENT_Drop)) return; // Hack for QScrollView if (CWIDGET_test_flag(control, WF_SCROLLVIEW) && QWIDGET(control)->inherits("MyListView")) ((MyListView *)QWIDGET(control))->contentsDropEvent((QDragMoveEvent *)e); CDRAG_clear(true); CDRAG_info.drop = e; p = e->pos(); p = w->mapTo(QWIDGET(control), p); CDRAG_info.x = p.x(); CDRAG_info.y = p.y(); GB.Raise(control, EVENT_Drop, 0); CDRAG_clear(false); } BEGIN_METHOD(CDRAG_call, GB_OBJECT source; GB_VARIANT data; GB_STRING format) CDRAG_drag((CWIDGET *)VARG(source), &VARG(data), MISSING(format) ? NULL : ARG(format)); END_METHOD BEGIN_METHOD_VOID(CDRAG_exit) GB.Unref(POINTER(&_picture)); END_METHOD BEGIN_PROPERTY(CDRAG_icon) if (READ_PROPERTY) GB.ReturnObject(_picture); else GB.StoreObject(PROP(GB_OBJECT), POINTER(&_picture)); END_PROPERTY BEGIN_PROPERTY(CDRAG_icon_x) if (READ_PROPERTY) GB.ReturnInteger(_picture_x); else _picture_x = VPROP(GB_INTEGER); END_PROPERTY BEGIN_PROPERTY(CDRAG_icon_y) if (READ_PROPERTY) GB.ReturnInteger(_picture_y); else _picture_y = VPROP(GB_INTEGER); END_PROPERTY #define CHECK_VALID() \ if (!CDRAG_info.valid) \ { \ GB.Error("No drag data"); \ return; \ } BEGIN_PROPERTY(CDRAG_type) CHECK_VALID(); GB.ReturnInteger(get_type(CDRAG_info.drop)); END_PROPERTY BEGIN_PROPERTY(CDRAG_format) CHECK_VALID(); GB.ReturnNewZeroString(get_format(CDRAG_info.drop)); END_PROPERTY BEGIN_PROPERTY(CDRAG_formats) GB_ARRAY array; CHECK_VALID(); GB.Array.New(&array, GB_T_STRING, 0); get_formats(CDRAG_info.drop, array); GB.ReturnObject(array); END_PROPERTY BEGIN_PROPERTY(CDRAG_data) if (!CDRAG_info.valid) { GB.ReturnNull(); return; } paste(CDRAG_info.drop, NULL); END_PROPERTY BEGIN_METHOD(CDRAG_paste, GB_STRING format) if (!CDRAG_info.valid) { GB.ReturnNull(); return; } paste(CDRAG_info.drop, MISSING(format) ? NULL : GB.ToZeroString(ARG(format))); END_METHOD BEGIN_PROPERTY(CDRAG_action) CHECK_VALID(); switch(CDRAG_info.drop->action()) { case QDropEvent::Link: GB.ReturnInteger(1); break; case QDropEvent::Move: GB.ReturnInteger(2); break; default: GB.ReturnInteger(0); break; } END_PROPERTY BEGIN_PROPERTY(CDRAG_source) CHECK_VALID(); GB.ReturnObject(CWidget::get(CDRAG_info.drop->source())); END_PROPERTY BEGIN_PROPERTY(CDRAG_x) CHECK_VALID(); GB.ReturnInteger(CDRAG_info.x); END_PROPERTY BEGIN_PROPERTY(CDRAG_y) CHECK_VALID(); GB.ReturnInteger(CDRAG_info.y); END_PROPERTY BEGIN_PROPERTY(CDRAG_pending) GB.ReturnBoolean(CDRAG_dragging); END_PROPERTY BEGIN_METHOD(CDRAG_show, GB_OBJECT control; GB_INTEGER x; GB_INTEGER y; GB_INTEGER w; GB_INTEGER h) if (GB.CheckObject(VARG(control))) return; if (!CDRAG_dragging) { GB.Error("No undergoing drag"); return; } if (MISSING(x) || MISSING(y) || MISSING(w) || MISSING(h)) show_frame((CWIDGET *)VARG(control), 0, 0, -1, -1); else show_frame((CWIDGET *)VARG(control), VARG(x), VARG(y), VARG(w), VARG(h)); END_METHOD BEGIN_METHOD_VOID(CDRAG_hide) hide_frame(NULL); END_METHOD GB_DESC CDragDesc[] = { GB_DECLARE("Drag", 0), GB_VIRTUAL_CLASS(), GB_CONSTANT("None", "i", 0), GB_CONSTANT("Text", "i", 1), GB_CONSTANT("Image", "i", 2), GB_CONSTANT("Copy", "i", 0), GB_CONSTANT("Link", "i", 1), GB_CONSTANT("Move", "i", 2), GB_STATIC_PROPERTY("Icon", "Picture", CDRAG_icon), GB_STATIC_PROPERTY("IconX", "i", CDRAG_icon_x), GB_STATIC_PROPERTY("IconY", "i", CDRAG_icon_y), GB_STATIC_PROPERTY_READ("Data", "v", CDRAG_data), GB_STATIC_PROPERTY_READ("Format", "s", CDRAG_format), GB_STATIC_PROPERTY_READ("Formats", "String[]", CDRAG_formats), GB_STATIC_PROPERTY_READ("Type", "i", CDRAG_type), GB_STATIC_PROPERTY_READ("Action", "i", CDRAG_action), GB_STATIC_PROPERTY_READ("Source", "Control", CDRAG_source), GB_STATIC_PROPERTY_READ("X", "i", CDRAG_x), GB_STATIC_PROPERTY_READ("Y", "i", CDRAG_y), GB_STATIC_PROPERTY_READ("Pending", "b", CDRAG_pending), GB_STATIC_METHOD("_call", NULL, CDRAG_call, "(Source)Control;(Data)v[(Format)s]"), GB_STATIC_METHOD("_exit", NULL, CDRAG_exit, NULL), GB_STATIC_METHOD("Show", NULL, CDRAG_show, "(Control)Control;[(X)i(Y)i(Width)i(Height)i]"), GB_STATIC_METHOD("Hide", NULL, CDRAG_hide, NULL), GB_STATIC_METHOD("Paste", "v", CDRAG_paste, "[(Format)s]"), GB_END_DECLARE };