summaryrefslogtreecommitdiffstats
path: root/src/qt3support/other
diff options
context:
space:
mode:
Diffstat (limited to 'src/qt3support/other')
-rw-r--r--src/qt3support/other/other.pri24
-rw-r--r--src/qt3support/other/q3accel.cpp982
-rw-r--r--src/qt3support/other/q3accel.h110
-rw-r--r--src/qt3support/other/q3boxlayout.cpp132
-rw-r--r--src/qt3support/other/q3boxlayout.h122
-rw-r--r--src/qt3support/other/q3dragobject.cpp1577
-rw-r--r--src/qt3support/other/q3dragobject.h218
-rw-r--r--src/qt3support/other/q3dropsite.cpp82
-rw-r--r--src/qt3support/other/q3dropsite.h65
-rw-r--r--src/qt3support/other/q3gridlayout.h78
-rw-r--r--src/qt3support/other/q3membuf.cpp171
-rw-r--r--src/qt3support/other/q3membuf_p.h103
-rw-r--r--src/qt3support/other/q3mimefactory.cpp546
-rw-r--r--src/qt3support/other/q3mimefactory.h102
-rw-r--r--src/qt3support/other/q3polygonscanner.cpp939
-rw-r--r--src/qt3support/other/q3polygonscanner.h70
-rw-r--r--src/qt3support/other/q3process.cpp927
-rw-r--r--src/qt3support/other/q3process.h186
-rw-r--r--src/qt3support/other/q3process_unix.cpp1282
-rw-r--r--src/qt3support/other/q3process_win.cpp676
-rw-r--r--src/qt3support/other/qiconset.h48
-rw-r--r--src/qt3support/other/qt_compat_pch.h66
22 files changed, 8506 insertions, 0 deletions
diff --git a/src/qt3support/other/other.pri b/src/qt3support/other/other.pri
new file mode 100644
index 0000000..b2b0e56
--- /dev/null
+++ b/src/qt3support/other/other.pri
@@ -0,0 +1,24 @@
+# Qt compat module
+
+HEADERS += other/q3dropsite.h \
+ other/q3dragobject.h \
+ other/q3accel.h \
+ other/q3mimefactory.h \
+ other/q3polygonscanner.h \
+ other/q3process.h \
+ other/q3membuf_p.h \
+ other/q3boxlayout.h \
+ other/q3gridlayout.h
+
+SOURCES += other/q3dropsite.cpp \
+ other/q3dragobject.cpp \
+ other/q3accel.cpp \
+ other/q3mimefactory.cpp \
+ other/q3polygonscanner.cpp \
+ other/q3process.cpp \
+ other/q3membuf.cpp
+
+unix:SOURCES += other/q3process_unix.cpp
+win32:SOURCES+= other/q3process_win.cpp
+
+
diff --git a/src/qt3support/other/q3accel.cpp b/src/qt3support/other/q3accel.cpp
new file mode 100644
index 0000000..a570a70
--- /dev/null
+++ b/src/qt3support/other/q3accel.cpp
@@ -0,0 +1,982 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3accel.h"
+
+#include "q3signal.h"
+#include "qapplication.h"
+#include "qwidget.h"
+#include "q3ptrlist.h"
+#include "qwhatsthis.h"
+#include "qpointer.h"
+#include "qstatusbar.h"
+#include "qdockwidget.h"
+#include "qevent.h"
+#include "qkeysequence.h"
+#include "private/qapplication_p.h"
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt;
+
+/*!
+ \class Q3Accel
+ \brief The Q3Accel class handles keyboard accelerator and shortcut keys.
+
+ \compat
+
+ A keyboard accelerator triggers an action when a certain key
+ combination is pressed. The accelerator handles all keyboard
+ activity for all the children of one top-level widget, so it is
+ not affected by the keyboard focus.
+
+ In most cases, you will not need to use this class directly. Use
+ the QAction class to create actions with accelerators that can be
+ used in both menus and toolbars. If you're only interested in
+ menus use Q3MenuData::insertItem() or Q3MenuData::setAccel() to make
+ accelerators for operations that are also available on menus. Many
+ widgets automatically generate accelerators, such as QAbstractButton,
+ QGroupBox, QLabel (with QLabel::setBuddy()), QMenuBar, and QTabBar.
+ Example:
+ \snippet doc/src/snippets/code/src_qt3support_other_q3accel.cpp 0
+
+ A Q3Accel contains a list of accelerator items that can be
+ manipulated using insertItem(), removeItem(), clear(), key() and
+ findKey().
+
+ Each accelerator item consists of an identifier and a \l
+ QKeySequence. A single key sequence consists of a keyboard code
+ combined with modifiers (Qt::SHIFT, Qt::CTRL, Qt::ALT, or
+ Qt::UNICODE_ACCEL). For example, Qt::CTRL + Qt::Key_P could be a shortcut
+ for printing a document. As an alternative, use Qt::UNICODE_ACCEL with the
+ unicode code point of the character. For example, Qt::UNICODE_ACCEL
+ + 'A' gives the same accelerator as Qt::Key_A.
+
+ When an accelerator key is pressed, the accelerator sends out the
+ signal activated() with a number that identifies this particular
+ accelerator item. Accelerator items can also be individually
+ connected, so that two different keys will activate two different
+ slots (see connectItem() and disconnectItem()).
+
+ The activated() signal is \e not emitted when two or more
+ accelerators match the same key. Instead, the first matching
+ accelerator sends out the activatedAmbiguously() signal. By
+ pressing the key multiple times, users can navigate between all
+ matching accelerators. Some standard controls like QPushButton and
+ QCheckBox connect the activatedAmbiguously() signal to the
+ harmless setFocus() slot, whereas activated() is connected to a
+ slot invoking the button's action. Most controls, like QLabel and
+ QTabBar, treat activated() and activatedAmbiguously() as
+ equivalent.
+
+ Use setEnabled() to enable or disable all the items in an
+ accelerator, or setItemEnabled() to enable or disable individual
+ items. An item is active only when both the Q3Accel and the item
+ itself are enabled.
+
+ The function setWhatsThis() specifies a help text that appears
+ when the user presses an accelerator key in What's This mode.
+
+ The accelerator will be deleted when \e parent is deleted,
+ and will consume relevant key events until then.
+
+ Please note that the accelerator
+ \snippet doc/src/snippets/code/src_qt3support_other_q3accel.cpp 1
+ can be triggered with both the 'M' key, and with Shift+M,
+ unless a second accelerator is defined for the Shift+M
+ combination.
+
+
+ Example:
+ \snippet doc/src/snippets/code/src_qt3support_other_q3accel.cpp 2
+
+ \sa QKeyEvent QWidget::keyPressEvent()
+ QAbstractButton::setAccel() QLabel::setBuddy() QKeySequence
+*/
+
+
+struct Q3AccelItem { // internal accelerator item
+ Q3AccelItem(const QKeySequence &k, int i)
+ { key=k; id=i; enabled=true; signal=0; }
+ ~Q3AccelItem() { delete signal; }
+ int id;
+ QKeySequence key;
+ bool enabled;
+ Q3Signal *signal;
+ QString whatsthis;
+};
+
+
+typedef Q3PtrList<Q3AccelItem> Q3AccelList; // internal accelerator list
+
+class Q3AccelPrivate {
+public:
+ Q3AccelPrivate(Q3Accel* p);
+ ~Q3AccelPrivate();
+ Q3AccelList aitems;
+ bool enabled;
+ QPointer<QWidget> watch;
+ bool ignorewhatsthis;
+ Q3Accel* parent;
+
+ void activate(Q3AccelItem* item);
+ void activateAmbiguously(Q3AccelItem* item);
+};
+
+class Q3AccelManager {
+public:
+ static Q3AccelManager* self() { return self_ptr ? self_ptr : new Q3AccelManager; }
+ void registerAccel(Q3AccelPrivate* a) { accels.append(a); }
+ void unregisterAccel(Q3AccelPrivate* a) { accels.removeRef(a); if (accels.isEmpty()) delete this; }
+ bool tryAccelEvent(QWidget* w, QKeyEvent* e);
+ bool dispatchAccelEvent(QWidget* w, QKeyEvent* e);
+ bool tryComposeUnicode(QWidget* w, QKeyEvent* e);
+
+private:
+ Q3AccelManager()
+ : currentState(QKeySequence::NoMatch), clash(-1), metaComposeUnicode(false),composedUnicode(0)
+ { setFuncPtr(); self_ptr = this; }
+ ~Q3AccelManager() { self_ptr = 0; }
+ void setFuncPtr();
+
+ bool correctSubWindow(QWidget *w, Q3AccelPrivate* d);
+ QKeySequence::SequenceMatch match(QKeyEvent* e, Q3AccelItem* item, QKeySequence& temp);
+ int translateModifiers(ButtonState state);
+
+ Q3PtrList<Q3AccelPrivate> accels;
+ static Q3AccelManager* self_ptr;
+ QKeySequence::SequenceMatch currentState;
+ QKeySequence intermediate;
+ int clash;
+ bool metaComposeUnicode;
+ int composedUnicode;
+};
+Q3AccelManager* Q3AccelManager::self_ptr = 0;
+
+bool Q_COMPAT_EXPORT qt_tryAccelEvent(QWidget* w, QKeyEvent* e){
+ return Q3AccelManager::self()->tryAccelEvent(w, e);
+}
+
+bool Q_COMPAT_EXPORT qt_dispatchAccelEvent(QWidget* w, QKeyEvent* e){
+ return Q3AccelManager::self()->dispatchAccelEvent(w, e);
+}
+
+bool Q_COMPAT_EXPORT qt_tryComposeUnicode(QWidget* w, QKeyEvent* e){
+ return Q3AccelManager::self()->tryComposeUnicode(w, e);
+}
+
+void Q3AccelManager::setFuncPtr() {
+ if (qApp->d_func()->qt_compat_used)
+ return;
+ QApplicationPrivate *data = static_cast<QApplicationPrivate*>(qApp->d_ptr);
+ data->qt_tryAccelEvent = qt_tryAccelEvent;
+ data->qt_tryComposeUnicode = qt_tryComposeUnicode;
+ data->qt_dispatchAccelEvent = qt_dispatchAccelEvent;
+ data->qt_compat_used = true;
+}
+
+#ifdef Q_WS_MAC
+static bool qt_accel_no_shortcuts = true;
+#else
+static bool qt_accel_no_shortcuts = false;
+#endif
+void Q_COMPAT_EXPORT qt_set_accel_auto_shortcuts(bool b) { qt_accel_no_shortcuts = b; }
+
+/*
+ \internal
+ Returns true if the accel is in the current subwindow, else false.
+*/
+bool Q3AccelManager::correctSubWindow(QWidget* w, Q3AccelPrivate* d) {
+#if !defined (Q_OS_MACX)
+ if (!d->watch || !d->watch->isVisible() || !d->watch->isEnabled())
+#else
+ if (!d->watch || (!d->watch->isVisible() && !d->watch->inherits("QMenuBar")) || !d->watch->isEnabled())
+#endif
+ return false;
+ QWidget* tlw = w->window();
+ QWidget* wtlw = d->watch->window();
+
+ /* if we live in a floating dock window, keep our parent's
+ * accelerators working */
+#ifndef QT_NO_MAINWINDOW
+ if ((tlw->windowType() == Qt::Dialog) && tlw->parentWidget() && qobject_cast<QDockWidget*>(tlw))
+ return tlw->parentWidget()->window() == wtlw;
+
+ if (wtlw != tlw)
+ return false;
+#endif
+ /* if we live in a MDI subwindow, ignore the event if we are
+ not the active document window */
+ QWidget* sw = d->watch;
+ while (sw && sw->windowType() != Qt::SubWindow)
+ sw = sw->parentWidget(true);
+ if (sw) { // we are in a subwindow indeed
+ QWidget* fw = w;
+ while (fw && fw != sw)
+ fw = fw->parentWidget(true);
+ if (fw != sw) // focus widget not in our subwindow
+ return false;
+ }
+ return true;
+}
+
+inline int Q3AccelManager::translateModifiers(ButtonState state)
+{
+ int result = 0;
+ if (state & ShiftButton)
+ result |= SHIFT;
+ if (state & ControlButton)
+ result |= CTRL;
+ if (state & MetaButton)
+ result |= META;
+ if (state & AltButton)
+ result |= ALT;
+ return result;
+}
+
+/*
+ \internal
+ Matches the current intermediate key sequence + the latest
+ keyevent, with and AccelItem. Returns Identical,
+ PartialMatch or NoMatch, and fills \a temp with the
+ resulting key sequence.
+*/
+QKeySequence::SequenceMatch Q3AccelManager::match(QKeyEvent *e, Q3AccelItem* item, QKeySequence& temp)
+{
+ QKeySequence::SequenceMatch result = QKeySequence::NoMatch;
+ int index = intermediate.count();
+ temp = intermediate;
+
+ int modifier = translateModifiers(e->state());
+
+ if (e->key() && e->key() != Key_unknown) {
+ int key = e->key() | modifier;
+ if (e->key() == Key_BackTab) {
+ /*
+ In QApplication, we map shift+tab to shift+backtab.
+ This code here reverts the mapping in a way that keeps
+ backtab and shift+tab accelerators working, in that
+ order, meaning backtab has priority.*/
+ key &= ~SHIFT;
+
+ temp.setKey(key, index);
+ if (QKeySequence::NoMatch != (result = temp.matches(item->key)))
+ return result;
+ if (e->state() & ShiftButton)
+ key |= SHIFT;
+ key = Key_Tab | (key & MODIFIER_MASK);
+ temp.setKey(key, index);
+ if (QKeySequence::NoMatch != (result = temp.matches(item->key)))
+ return result;
+ } else {
+ temp.setKey(key, index);
+ if (QKeySequence::NoMatch != (result = temp.matches(item->key)))
+ return result;
+ }
+
+ if (key == Key_BackTab) {
+ if (e->state() & ShiftButton)
+ key |= SHIFT;
+ temp.setKey(key, index);
+ if (QKeySequence::NoMatch != (result = temp.matches(item->key)))
+ return result;
+ }
+ }
+ if (!e->text().isEmpty()) {
+ temp.setKey((int)e->text()[0].unicode() | UNICODE_ACCEL | modifier, index);
+ result = temp.matches(item->key);
+ }
+ return result;
+}
+
+bool Q3AccelManager::tryAccelEvent(QWidget* w, QKeyEvent* e)
+{
+ if (QKeySequence::NoMatch == currentState) {
+ e->t = QEvent::AccelOverride;
+ e->ignore();
+ QApplication::sendSpontaneousEvent(w, e);
+ if (e->isAccepted())
+ return false;
+ }
+ e->t = QEvent::Accel;
+ e->ignore();
+ QApplication::sendSpontaneousEvent(w, e);
+ return e->isAccepted();
+}
+
+bool Q3AccelManager::tryComposeUnicode(QWidget* w, QKeyEvent* e)
+{
+ if (metaComposeUnicode) {
+ int value = e->key() - Key_0;
+ // Ignore acceloverrides so we don't trigger
+ // accels on keypad when Meta compose is on
+ if ((e->type() == QEvent::AccelOverride) &&
+ (e->state() == Qt::Keypad + Qt::MetaButton)) {
+ e->accept();
+ // Meta compose start/continue
+ } else if ((e->type() == QEvent::KeyPress) &&
+ (e->state() == Qt::Keypad + Qt::MetaButton)) {
+ if (value >= 0 && value <= 9) {
+ composedUnicode *= 10;
+ composedUnicode += value;
+ return true;
+ } else {
+ // Composing interrupted, dispatch!
+ if (composedUnicode) {
+ QChar ch(composedUnicode);
+ QString s(ch);
+ QKeyEvent kep(QEvent::KeyPress, 0, ch.row() ? 0 : ch.cell(), 0, s);
+ QKeyEvent ker(QEvent::KeyRelease, 0, ch.row() ? 0 : ch.cell(), 0, s);
+ QApplication::sendEvent(w, &kep);
+ QApplication::sendEvent(w, &ker);
+ }
+ composedUnicode = 0;
+ return true;
+ }
+ // Meta compose end, dispatch
+ } else if ((e->type() == QEvent::KeyRelease) &&
+ (e->key() == Key_Meta) &&
+ (composedUnicode != 0)) {
+ if ((composedUnicode > 0) &&
+ (composedUnicode < 0xFFFE)) {
+ QChar ch(composedUnicode);
+ QString s(ch);
+ QKeyEvent kep(QEvent::KeyPress, 0, ch.row() ? 0 : ch.cell(), 0, s);
+ QKeyEvent ker(QEvent::KeyRelease, 0, ch.row() ? 0 : ch.cell(), 0, s);
+ QApplication::sendEvent(w, &kep);
+ QApplication::sendEvent(w, &ker);
+ }
+ composedUnicode = 0;
+ return true;
+ }
+ }
+ return false;
+}
+
+/*
+ \internal
+ Checks for possible accelerators, if no widget
+ ate the keypres, or we are in the middle of a
+ partial key sequence.
+*/
+bool Q3AccelManager::dispatchAccelEvent(QWidget* w, QKeyEvent* e)
+{
+#ifndef QT_NO_STATUSBAR
+ // Needs to be declared and used here because of "goto doclash"
+ QStatusBar* mainStatusBar = 0;
+#endif
+
+ // Modifiers can NOT be accelerators...
+ if (e->key() >= Key_Shift &&
+ e->key() <= Key_Alt)
+ return false;
+
+ QKeySequence::SequenceMatch result = QKeySequence::NoMatch;
+ QKeySequence tocheck, partial;
+ Q3AccelPrivate* accel = 0;
+ Q3AccelItem* item = 0;
+ Q3AccelPrivate* firstaccel = 0;
+ Q3AccelItem* firstitem = 0;
+ Q3AccelPrivate* lastaccel = 0;
+ Q3AccelItem* lastitem = 0;
+
+ QKeyEvent pe = *e;
+ int n = -1;
+ int hasShift = (e->state()&Qt::ShiftButton)?1:0;
+ bool identicalDisabled = false;
+ bool matchFound = false;
+ do {
+ accel = accels.first();
+ matchFound = false;
+ while (accel) {
+ if (correctSubWindow(w, accel)) {
+ if (accel->enabled) {
+ item = accel->aitems.last();
+ while(item) {
+ if (QKeySequence::Identical == (result = match(&pe, item, tocheck))) {
+ if (item->enabled) {
+ if (!firstaccel) {
+ firstaccel = accel;
+ firstitem = item;
+ }
+ lastaccel = accel;
+ lastitem = item;
+ n++;
+ matchFound = true;
+ if (n > QMAX(clash,0))
+ goto doclash;
+ } else {
+ identicalDisabled = true;
+ }
+ }
+ if (item->enabled && QKeySequence::PartialMatch == result) {
+ partial = tocheck;
+ matchFound = true;
+ }
+ item = accel->aitems.prev();
+ }
+ } else {
+ item = accel->aitems.last();
+ while(item) {
+ if (QKeySequence::Identical == match(&pe, item, tocheck))
+ identicalDisabled = true;
+ item = accel->aitems.prev();
+ }
+ }
+ }
+ accel = accels.next();
+ }
+ pe = QKeyEvent(QEvent::Accel, pe.key(), pe.ascii(), pe.state()&~Qt::ShiftButton, pe.text());
+ } while (hasShift-- && !matchFound && !identicalDisabled);
+
+#ifndef QT_NO_STATUSBAR
+ mainStatusBar = (QStatusBar*) w->window()->child(0, "QStatusBar");
+#endif
+ if (n < 0) { // no match found
+ currentState = partial.count() ? QKeySequence::PartialMatch : QKeySequence::NoMatch;
+#ifndef QT_NO_STATUSBAR
+ // Only display message if we are, or were, in a partial match
+ if (mainStatusBar && (QKeySequence::PartialMatch == currentState || intermediate.count())) {
+ if (currentState == QKeySequence::PartialMatch) {
+ mainStatusBar->showMessage((QString)partial + QLatin1String(", ..."));
+ } else if (!identicalDisabled) {
+ QString message = Q3Accel::tr("%1, %2 not defined").
+ arg((QString)intermediate).
+ arg(QKeySequence::encodeString(e->key() | translateModifiers(e->state())));
+ mainStatusBar->showMessage(message, 2000);
+ // Since we're a NoMatch, reset the clash count
+ clash = -1;
+ } else {
+ mainStatusBar->clearMessage();
+ }
+ }
+#endif
+
+ bool eatKey = (QKeySequence::PartialMatch == currentState || intermediate.count());
+ intermediate = partial;
+ if (eatKey)
+ e->accept();
+ return eatKey;
+ } else if (n == 0) { // found exactly one match
+ clash = -1; // reset
+#ifndef QT_NO_STATUSBAR
+ if (currentState == QKeySequence::PartialMatch && mainStatusBar)
+ mainStatusBar->clearMessage();
+#endif
+ currentState = QKeySequence::NoMatch; // Free sequence keylock
+ intermediate = QKeySequence();
+ lastaccel->activate(lastitem);
+ e->accept();
+ return true;
+ }
+
+ doclash: // found more than one match
+#ifndef QT_NO_STATUSBAR
+ if (!mainStatusBar) // if "goto doclash", we need to get status bar again.
+ mainStatusBar = (QStatusBar*) w->window()->child(0, "QStatusBar");
+#endif
+
+ QString message = Q3Accel::tr("Ambiguous %1 not handled").arg((QString)tocheck);
+ if (clash >= 0 && n > clash) { // pick next match
+ intermediate = QKeySequence();
+ currentState = QKeySequence::NoMatch; // Free sequence keylock
+ clash++;
+#ifndef QT_NO_STATUSBAR
+ if (mainStatusBar &&
+ !lastitem->signal &&
+ !(lastaccel->parent->receivers(SIGNAL(activatedAmbiguously(int)))))
+ mainStatusBar->showMessage(message, 2000);
+#endif
+ lastaccel->activateAmbiguously(lastitem);
+ } else { // start (or wrap) with the first matching
+ intermediate = QKeySequence();
+ currentState = QKeySequence::NoMatch; // Free sequence keylock
+ clash = 0;
+#ifndef QT_NO_STATUSBAR
+ if (mainStatusBar &&
+ !firstitem->signal &&
+ !(firstaccel->parent->receivers(SIGNAL(activatedAmbiguously(int)))))
+ mainStatusBar->showMessage(message, 2000);
+#endif
+ firstaccel->activateAmbiguously(firstitem);
+ }
+ e->accept();
+ return true;
+}
+
+Q3AccelPrivate::Q3AccelPrivate(Q3Accel* p)
+ : parent(p)
+{
+ Q3AccelManager::self()->registerAccel(this);
+ aitems.setAutoDelete(true);
+ ignorewhatsthis = false;
+}
+
+Q3AccelPrivate::~Q3AccelPrivate()
+{
+ Q3AccelManager::self()->unregisterAccel(this);
+}
+
+static Q3AccelItem *find_id(Q3AccelList &list, int id)
+{
+ register Q3AccelItem *item = list.first();
+ while (item && item->id != id)
+ item = list.next();
+ return item;
+}
+
+static Q3AccelItem *find_key(Q3AccelList &list, const QKeySequence &key)
+{
+ register Q3AccelItem *item = list.first();
+ while (item && !(item->key == key))
+ item = list.next();
+ return item;
+}
+
+/*!
+ Constructs a Q3Accel object called \a name, with parent \a parent.
+ The accelerator operates on \a parent.
+*/
+
+Q3Accel::Q3Accel(QWidget *parent, const char *name)
+ : QObject(parent, name)
+{
+ d = new Q3AccelPrivate(this);
+ d->enabled = true;
+ d->watch = parent;
+#if defined(QT_CHECK_NULL)
+ if (!d->watch)
+ qWarning("Q3Accel: An accelerator must have a parent or a watch widget");
+#endif
+}
+
+/*!
+ Constructs a Q3Accel object called \a name, that operates on \a
+ watch, and is a child of \a parent.
+
+ This constructor is not needed for normal application programming.
+*/
+Q3Accel::Q3Accel(QWidget* watch, QObject *parent, const char *name)
+ : QObject(parent, name)
+{
+ d = new Q3AccelPrivate(this);
+ d->enabled = true;
+ d->watch = watch;
+#if defined(QT_CHECK_NULL)
+ if (!d->watch)
+ qWarning("Q3Accel: An accelerator must have a parent or a watch widget");
+#endif
+}
+
+/*!
+ Destroys the accelerator object and frees all allocated resources.
+*/
+
+Q3Accel::~Q3Accel()
+{
+ delete d;
+}
+
+
+/*!
+ \fn void Q3Accel::activated(int id)
+
+ This signal is emitted when the user types the shortcut's key
+ sequence. \a id is a number that identifies this particular
+ accelerator item.
+
+ \sa activatedAmbiguously()
+*/
+
+/*!
+ \fn void Q3Accel::activatedAmbiguously(int id)
+
+ This signal is emitted when the user types a shortcut key
+ sequence that is ambiguous. For example, if one key sequence is a
+ "prefix" for another and the user types these keys it isn't clear
+ if they want the shorter key sequence, or if they're about to
+ type more to complete the longer key sequence. \a id is a number
+ that identifies this particular accelerator item.
+
+ \sa activated()
+*/
+
+/*!
+ Returns true if the accelerator is enabled; otherwise returns
+ false.
+
+ \sa setEnabled(), isItemEnabled()
+*/
+
+bool Q3Accel::isEnabled() const
+{
+ return d->enabled;
+}
+
+
+/*!
+ Enables the accelerator if \a enable is true, or disables it if \a
+ enable is false.
+
+ Individual keys can also be enabled or disabled using
+ setItemEnabled(). To work, a key must be an enabled item in an
+ enabled Q3Accel.
+
+ \sa isEnabled(), setItemEnabled()
+*/
+
+void Q3Accel::setEnabled(bool enable)
+{
+ d->enabled = enable;
+}
+
+
+/*!
+ Returns the number of accelerator items in this accelerator.
+*/
+
+uint Q3Accel::count() const
+{
+ return d->aitems.count();
+}
+
+
+static int get_seq_id()
+{
+ static int seq_no = -2; // -1 is used as return value in findKey()
+ return seq_no--;
+}
+
+/*!
+ Inserts an accelerator item and returns the item's identifier.
+
+ \a key is a key code and an optional combination of SHIFT, CTRL
+ and ALT. \a id is the accelerator item id.
+
+ If \a id is negative, then the item will be assigned a unique
+ negative identifier less than -1.
+
+ \snippet doc/src/snippets/code/src_qt3support_other_q3accel.cpp 3
+*/
+
+int Q3Accel::insertItem(const QKeySequence& key, int id)
+{
+ if (id == -1)
+ id = get_seq_id();
+ d->aitems.insert(0, new Q3AccelItem(key,id));
+ return id;
+}
+
+/*!
+ Removes the accelerator item with the identifier \a id.
+*/
+
+void Q3Accel::removeItem(int id)
+{
+ if (find_id(d->aitems, id))
+ d->aitems.remove();
+}
+
+
+/*!
+ Removes all accelerator items.
+*/
+
+void Q3Accel::clear()
+{
+ d->aitems.clear();
+}
+
+
+/*!
+ Returns the key sequence of the accelerator item with identifier
+ \a id, or an invalid key sequence (0) if the id cannot be found.
+*/
+
+QKeySequence Q3Accel::key(int id)
+{
+ Q3AccelItem *item = find_id(d->aitems, id);
+ return item ? item->key : QKeySequence(0);
+}
+
+
+/*!
+ Returns the identifier of the accelerator item with the key code
+ \a key, or -1 if the item cannot be found.
+*/
+
+int Q3Accel::findKey(const QKeySequence& key) const
+{
+ Q3AccelItem *item = find_key(d->aitems, key);
+ return item ? item->id : -1;
+}
+
+
+/*!
+ Returns true if the accelerator item with the identifier \a id is
+ enabled. Returns false if the item is disabled or cannot be found.
+
+ \sa setItemEnabled(), isEnabled()
+*/
+
+bool Q3Accel::isItemEnabled(int id) const
+{
+ Q3AccelItem *item = find_id(d->aitems, id);
+ return item ? item->enabled : false;
+}
+
+
+/*!
+ Enables the accelerator item with the identifier \a id if \a
+ enable is true, and disables item \a id if \a enable is false.
+
+ To work, an item must be enabled and be in an enabled Q3Accel.
+
+ \sa isItemEnabled(), isEnabled()
+*/
+
+void Q3Accel::setItemEnabled(int id, bool enable)
+{
+ Q3AccelItem *item = find_id(d->aitems, id);
+ if (item)
+ item->enabled = enable;
+}
+
+
+/*!
+ Connects the accelerator item \a id to the slot \a member of \a
+ receiver. Returns true if the connection is successful.
+
+ \snippet doc/src/snippets/code/src_qt3support_other_q3accel.cpp 4
+
+ Of course, you can also send a signal as \a member.
+
+ Normally accelerators are connected to slots which then receive
+ the \c activated(int id) signal with the id of the accelerator
+ item that was activated. If you choose to connect a specific
+ accelerator item using this function, the \c activated() signal is
+ emitted if the associated key sequence is pressed but no \c
+ activated(int id) signal is emitted.
+
+ \sa disconnectItem(), QObject::connect()
+*/
+
+bool Q3Accel::connectItem(int id, const QObject *receiver, const char *member)
+{
+ Q3AccelItem *item = find_id(d->aitems, id);
+ if (item) {
+ if (!item->signal) {
+ item->signal = new Q3Signal;
+ Q_CHECK_PTR(item->signal);
+ }
+ return item->signal->connect(receiver, member);
+ }
+ return false;
+}
+
+/*!
+ Disconnects the accelerator item identified by \a id from
+ the function called \a member in the \a receiver object.
+ Returns true if the connection existed and the disconnect
+ was successful.
+
+ \sa connectItem(), QObject::disconnect()
+*/
+
+bool Q3Accel::disconnectItem(int id, const QObject *receiver,
+ const char *member)
+{
+ Q3AccelItem *item = find_id(d->aitems, id);
+ if (item && item->signal)
+ return item->signal->disconnect(receiver, member);
+ return false;
+}
+
+void Q3AccelPrivate::activate(Q3AccelItem* item)
+{
+#ifndef QT_NO_WHATSTHIS
+ if (QWhatsThis::inWhatsThisMode() && !ignorewhatsthis) {
+ QWhatsThis::showText(QCursor::pos(), item->whatsthis);
+ return;
+ }
+#endif
+ if (item->signal)
+ item->signal->activate();
+ else
+ emit parent->activated(item->id);
+}
+
+void Q3AccelPrivate::activateAmbiguously(Q3AccelItem* item)
+{
+ if (item->signal)
+ item->signal->activate();
+ else
+ emit parent->activatedAmbiguously(item->id);
+}
+
+
+/*!
+ Returns the shortcut key sequence for \a str, or an invalid key
+ sequence (0) if \a str has no shortcut sequence.
+
+ For example, shortcutKey("E&xit") returns QKeySequence(Qt::ALT +
+ Qt::Key_X), shortcutKey("&Quit") returns QKeySequence(Qt::ALT +
+ Qt::Key_Q), and shortcutKey("Quit") returns QKeySequence().
+*/
+
+QKeySequence Q3Accel::shortcutKey(const QString &str)
+{
+ if(qt_accel_no_shortcuts)
+ return QKeySequence();
+
+ int p = 0;
+ while (p >= 0) {
+ p = str.find(QLatin1Char('&'), p) + 1;
+ if (p <= 0 || p >= (int)str.length())
+ return 0;
+ if (str[p] != QLatin1Char('&')) {
+ QChar c = str[p];
+ if (c.isPrint()) {
+ char ltr = c.upper().latin1();
+ if (ltr >= (char)Key_A && ltr <= (char)Key_Z)
+ c = QLatin1Char(ltr);
+ else
+ c = c.lower();
+ return QKeySequence(c.unicode() + ALT + UNICODE_ACCEL);
+ }
+ }
+ p++;
+ }
+ return QKeySequence();
+}
+
+/*! \obsolete
+
+ Creates an accelerator string for the key \a k.
+ For instance CTRL+Key_O gives "Ctrl+O". The "Ctrl" etc.
+ are translated (using QObject::tr()) in the "Q3Accel" context.
+
+ The function is superfluous. Cast the QKeySequence \a k to a
+ QString for the same effect.
+*/
+QString Q3Accel::keyToString(QKeySequence k)
+{
+ return (QString) k;
+}
+
+/*!\obsolete
+
+ Returns an accelerator code for the string \a s. For example
+ "Ctrl+O" gives CTRL+UNICODE_ACCEL+'O'. The strings "Ctrl",
+ "Shift", "Alt" are recognized, as well as their translated
+ equivalents in the "Q3Accel" context (using QObject::tr()). Returns 0
+ if \a s is not recognized.
+
+ This function is typically used with \link QObject::tr() tr
+ \endlink(), so that accelerator keys can be replaced in
+ translations:
+
+ \snippet doc/src/snippets/code/src_qt3support_other_q3accel.cpp 5
+
+ Notice the "File|Open" translator comment. It is by no means
+ necessary, but it provides some context for the human translator.
+
+ The function is superfluous. Construct a QKeySequence from the
+ string \a s for the same effect.
+
+ \sa QObject::tr(), {Internationalization with Qt}
+*/
+QKeySequence Q3Accel::stringToKey(const QString & s)
+{
+ return QKeySequence(s);
+}
+
+
+/*!
+ Sets a What's This help text for the accelerator item \a id to \a
+ text.
+
+ The text will be shown when the application is in What's This mode
+ and the user hits the accelerator key.
+
+ To set What's This help on a menu item (with or without an
+ accelerator key), use Q3MenuData::setWhatsThis().
+
+ \sa whatsThis(), QWhatsThis::inWhatsThisMode(), QAction::setWhatsThis()
+*/
+void Q3Accel::setWhatsThis(int id, const QString& text)
+{
+ Q3AccelItem *item = find_id(d->aitems, id);
+ if (item)
+ item->whatsthis = text;
+}
+
+/*!
+ Returns the What's This help text for the specified item \a id or
+ an empty string if no text has been specified.
+
+ \sa setWhatsThis()
+*/
+QString Q3Accel::whatsThis(int id) const
+{
+
+ Q3AccelItem *item = find_id(d->aitems, id);
+ return item? item->whatsthis : QString();
+}
+
+/*!\internal */
+void Q3Accel::setIgnoreWhatsThis(bool b)
+{
+ d->ignorewhatsthis = b;
+}
+
+/*!\internal */
+bool Q3Accel::ignoreWhatsThis() const
+{
+ return d->ignorewhatsthis;
+}
+
+/*!
+ \fn void Q3Accel::repairEventFilter()
+ \internal
+*/
+
+QT_END_NAMESPACE
diff --git a/src/qt3support/other/q3accel.h b/src/qt3support/other/q3accel.h
new file mode 100644
index 0000000..36adfa7
--- /dev/null
+++ b/src/qt3support/other/q3accel.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3ACCEL_H
+#define Q3ACCEL_H
+
+#include <QtCore/qobject.h>
+#include <QtGui/qkeysequence.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3SupportLight)
+
+class Q3AccelPrivate;
+
+class Q_COMPAT_EXPORT Q3Accel : public QObject // accelerator class
+{
+ Q_OBJECT
+public:
+ Q3Accel( QWidget *parent, const char *name=0 );
+ Q3Accel( QWidget* watch, QObject *parent, const char *name=0 );
+ ~Q3Accel();
+
+ bool isEnabled() const;
+ void setEnabled( bool );
+
+ uint count() const;
+
+ int insertItem( const QKeySequence& key, int id=-1);
+ void removeItem( int id );
+ void clear();
+
+ QKeySequence key( int id );
+ int findKey( const QKeySequence& key ) const;
+
+ bool isItemEnabled( int id ) const;
+ void setItemEnabled( int id, bool enable );
+
+ bool connectItem( int id, const QObject *receiver, const char* member );
+ bool disconnectItem( int id, const QObject *receiver, const char* member );
+
+ void repairEventFilter() {}
+
+ void setWhatsThis( int id, const QString& );
+ QString whatsThis( int id ) const;
+ void setIgnoreWhatsThis( bool );
+ bool ignoreWhatsThis() const;
+
+ static QKeySequence shortcutKey( const QString & );
+ static QString keyToString(QKeySequence k );
+ static QKeySequence stringToKey( const QString & );
+
+Q_SIGNALS:
+ void activated( int id );
+ void activatedAmbiguously( int id );
+
+private:
+ Q3AccelPrivate * d;
+
+private:
+ Q_DISABLE_COPY(Q3Accel)
+ friend class Q3AccelPrivate;
+ friend class Q3AccelManager;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // Q3ACCEL_H
diff --git a/src/qt3support/other/q3boxlayout.cpp b/src/qt3support/other/q3boxlayout.cpp
new file mode 100644
index 0000000..cc830bf
--- /dev/null
+++ b/src/qt3support/other/q3boxlayout.cpp
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class Q3HBoxLayout
+ \compat
+
+ \brief The Q3HBoxLayout class lines up widgets horizontally.
+ \sa Q3VBoxLayout
+*/
+
+/*!
+ \fn Q3HBoxLayout::Q3HBoxLayout(QWidget *parent, int margin = 0, int spacing = -1, const char *name = 0)
+
+ Constructs a new top-level horizontal box called \a name, with parent
+ \a parent. The \a margin is the number of pixels between the edge of the
+ widget and its managed children. The \a spacing is the default number of
+ pixels between neighboring children. If \a spacing is -1 the value of margin
+ is used for spacing.
+*/
+
+/*!
+ \fn Q3HBoxLayout::Q3HBoxLayout(QLayout *parentLayout, int spacing = -1, const char *name = 0)
+
+ Constructs a new horizontal box called \a name and adds it to
+ \a parentLayout. The \a spacing is the default number of pixels between
+ neighboring children. If \a spacing is -1, this Q3HBoxLayout will inherit
+ its parent's spacing.
+*/
+
+/*!
+ \fn Q3HBoxLayout::Q3HBoxLayout(int spacing = -1, const char *name = 0)
+
+ Constructs a new horizontal box called \a name. You must add it to another
+ layout. The \a spacing is the default number of pixels between neighboring
+ children. If \a spacing is -1, this QHBoxLayout will inherit its parent's
+ spacing().
+*/
+
+/*!
+ \fn Q3HBoxLayout::Q3HBoxLayout()
+ \internal
+*/
+
+/*!
+ \fn Q3HBoxLayout::Q3HBoxLayout(QWidget *parent)
+ \internal
+*/
+
+/*!
+ \class Q3VBoxLayout
+ \compat
+
+ \brief The Q3VBoxLayout class lines up widgets vertically.
+ \sa Q3HBoxLayout
+*/
+
+/*!
+ \fn Q3VBoxLayout::Q3VBoxLayout(QWidget *parent, int margin = 0, int spacing = -1, const char *name = 0)
+
+ Constructs a new top-level vertical box called \a name, with parent
+ \a parent. The \a margin is the number of pixels between the edge of the
+ widget and its managed children. The \a spacing is the default number of
+ pixels between neighboring children. If \a spacing is -1 the value of
+ margin is used for spacing.
+*/
+
+/*!
+ \fn Q3VBoxLayout::Q3VBoxLayout(QLayout *parentLayout, int spacing = -1, const char *name = 0)
+
+ Constructs a new vertical box called \a name and adds it to
+ \a parentLayout. The \a spacing is the default number of pixels between
+ neighboring children. If \a spacing is -1, this Q3VBoxLayout will inherit
+ its parent's spacing().
+*/
+
+/*!
+ \fn Q3VBoxLayout::Q3VBoxLayout(int spacing = -1, const char *name = 0)
+
+ Constructs a new vertical box called \a name. You must add it to another
+ layout. The \a spacing is the default number of pixels between neighboring
+ children. If \a spacing is -1, this Q3VBoxLayout will inherit its parent's
+ spacing().
+*/
+
+/*!
+ \fn Q3VBoxLayout::Q3VBoxLayout()
+ \internal
+*/
+
+/*!
+ \fn Q3VBoxLayout::Q3VBoxLayout(QWidget *parent)
+ \internal
+*/
diff --git a/src/qt3support/other/q3boxlayout.h b/src/qt3support/other/q3boxlayout.h
new file mode 100644
index 0000000..f0b527a
--- /dev/null
+++ b/src/qt3support/other/q3boxlayout.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3BOXLAYOUT_H
+#define Q3BOXLAYOUT_H
+
+#include <QtGui/qboxlayout.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3SupportLight)
+
+class Q3BoxLayout : public QBoxLayout
+{
+public:
+ inline explicit Q3BoxLayout(Direction dir, QWidget *parent = 0)
+ : QBoxLayout(dir, parent) { setMargin(0); setSpacing(0); }
+
+ inline Q3BoxLayout(QWidget *parent, Direction dir, int margin = 0, int spacing = -1,
+ const char *name = 0)
+ : QBoxLayout(parent, dir, margin, spacing, name) {}
+
+ inline Q3BoxLayout(QLayout *parentLayout, Direction dir, int spacing = -1,
+ const char *name = 0)
+ : QBoxLayout(parentLayout, dir, spacing, name) { setMargin(0); }
+
+ inline Q3BoxLayout(Direction dir, int spacing, const char *name = 0)
+ : QBoxLayout(dir, spacing, name) { setMargin(0); }
+
+private:
+ Q_DISABLE_COPY(Q3BoxLayout)
+};
+
+class Q3HBoxLayout : public Q3BoxLayout
+{
+public:
+ inline Q3HBoxLayout() : Q3BoxLayout(LeftToRight) {}
+
+ inline explicit Q3HBoxLayout(QWidget *parent) : Q3BoxLayout(LeftToRight, parent) {}
+
+ inline Q3HBoxLayout(QWidget *parent, int margin,
+ int spacing = -1, const char *name = 0)
+ : Q3BoxLayout(parent, LeftToRight, margin, spacing, name) {}
+
+ inline Q3HBoxLayout(QLayout *parentLayout,
+ int spacing = -1, const char *name = 0)
+ : Q3BoxLayout(parentLayout, LeftToRight, spacing, name) {}
+
+ inline Q3HBoxLayout(int spacing, const char *name = 0)
+ : Q3BoxLayout(LeftToRight, spacing, name) {}
+
+private:
+ Q_DISABLE_COPY(Q3HBoxLayout)
+};
+
+class Q3VBoxLayout : public Q3BoxLayout
+{
+public:
+ inline Q3VBoxLayout() : Q3BoxLayout(TopToBottom) {}
+
+ inline explicit Q3VBoxLayout(QWidget *parent) : Q3BoxLayout(TopToBottom, parent) {}
+
+ inline Q3VBoxLayout(QWidget *parent, int margin,
+ int spacing = -1, const char *name = 0)
+ : Q3BoxLayout(parent, TopToBottom, margin, spacing, name) {}
+
+ inline Q3VBoxLayout(QLayout *parentLayout,
+ int spacing = -1, const char *name = 0)
+ : Q3BoxLayout(parentLayout, TopToBottom, spacing, name) {}
+
+ inline Q3VBoxLayout(int spacing, const char *name = 0)
+ : Q3BoxLayout(TopToBottom, spacing, name) {}
+
+private:
+ Q_DISABLE_COPY(Q3VBoxLayout)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // Q3BOXLAYOUT_H
diff --git a/src/qt3support/other/q3dragobject.cpp b/src/qt3support/other/q3dragobject.cpp
new file mode 100644
index 0000000..fb57220
--- /dev/null
+++ b/src/qt3support/other/q3dragobject.cpp
@@ -0,0 +1,1577 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qplatformdefs.h"
+
+#ifndef QT_NO_MIME
+
+#include "q3dragobject.h"
+#include "qpixmap.h"
+#include "qevent.h"
+#include "qfile.h"
+#include "qtextcodec.h"
+#include "qapplication.h"
+#include "qpoint.h"
+#include "qwidget.h"
+#include "qbuffer.h"
+#include "qimagereader.h"
+#include "qimagewriter.h"
+#include "qimage.h"
+#include "qregexp.h"
+#include "qdir.h"
+#include "qdrag.h"
+#include "q3strlist.h"
+#include "q3cstring.h"
+
+#include <private/qobject_p.h>
+
+#include <ctype.h>
+#if defined(Q_OS_WINCE)
+#include <winsock.h>
+#include "qfunctions_wince.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+static QWidget *last_target = 0;
+
+class QDragMime;
+
+class Q3DragObjectPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(Q3DragObject)
+public:
+ Q3DragObjectPrivate(): hot(0,0),pm_cursor(0) {}
+ QPixmap pixmap;
+ QPoint hot;
+ // store default cursors
+ QPixmap *pm_cursor;
+};
+
+class Q3TextDragPrivate : public Q3DragObjectPrivate
+{
+ Q_DECLARE_PUBLIC(Q3TextDrag)
+public:
+ Q3TextDragPrivate() { setSubType(QLatin1String("plain")); }
+ void setSubType(const QString & st) {
+ subtype = st;
+ fmt = QString(QLatin1String("text/")).toLatin1() + subtype.toLatin1();
+ }
+
+ QString txt;
+ QString subtype;
+ QByteArray fmt;
+};
+
+class Q3StoredDragPrivate : public Q3DragObjectPrivate
+{
+ Q_DECLARE_PUBLIC(Q3StoredDrag)
+public:
+ Q3StoredDragPrivate() {}
+ const char* fmt;
+ QByteArray enc;
+};
+
+class Q3ImageDragPrivate : public Q3DragObjectPrivate
+{
+ Q_DECLARE_PUBLIC(Q3ImageDrag)
+public:
+ QImage img;
+ QList<QByteArray> ofmts;
+};
+
+class QDragMime : public QMimeData
+{
+public:
+ QDragMime(Q3DragObject *parent) : QMimeData(), dragObject(parent) { }
+ ~QDragMime();
+
+ QByteArray data(const QString &mimetype) const;
+ bool hasFormat(const QString &mimetype) const;
+ QStringList formats() const;
+
+ QPointer<Q3DragObject> dragObject;
+};
+
+QDragMime::~QDragMime()
+{
+ delete dragObject;
+}
+QByteArray QDragMime::data(const QString &mimetype) const
+{
+ return dragObject->encodedData(mimetype.latin1());
+}
+
+bool QDragMime::hasFormat(const QString &mimetype) const
+{
+ return dragObject->provides(mimetype.latin1());
+}
+
+QStringList QDragMime::formats() const
+{
+ int i = 0;
+ const char *format;
+ QStringList f;
+ while ((format = dragObject->format(i))) {
+ f.append(QLatin1String(format));
+ ++i;
+ }
+ return f;
+}
+
+/*!
+ Constructs a drag object called \a name with a parent \a
+ dragSource.
+
+ Note that the drag object will be deleted when the \a dragSource is
+ deleted.
+*/
+
+Q3DragObject::Q3DragObject(QWidget * dragSource, const char * name)
+ : QObject(*(new Q3DragObjectPrivate), dragSource)
+{
+ setObjectName(QLatin1String(name));
+}
+
+/*! \internal */
+Q3DragObject::Q3DragObject(Q3DragObjectPrivate &dd, QWidget *dragSource)
+ : QObject(dd, dragSource)
+{
+}
+
+/*!
+ Destroys the drag object, canceling any drag and drop operation in
+ which it is involved.
+*/
+
+Q3DragObject::~Q3DragObject()
+{
+}
+
+#ifndef QT_NO_DRAGANDDROP
+/*!
+ Set the pixmap, \a pm, to display while dragging the object. The
+ platform-specific implementation will use this where it can - so
+ provide a small masked pixmap, and do not assume that the user
+ will actually see it. For example, cursors on Windows 95 are of
+ limited size.
+
+ The \a hotspot is the point on (or off) the pixmap that should be
+ under the cursor as it is dragged. It is relative to the top-left
+ pixel of the pixmap.
+
+ \warning We have seen problems with drag cursors on different
+ graphics hardware and driver software on Windows. Setting the
+ graphics acceleration in the display settings down one tick solved
+ the problems in all cases.
+*/
+void Q3DragObject::setPixmap(QPixmap pm, const QPoint& hotspot)
+{
+ Q_D(Q3DragObject);
+ d->pixmap = pm;
+ d->hot = hotspot;
+#if 0
+ QDragManager *manager = QDragManager::self();
+ if (manager && manager->object == d->data)
+ manager->updatePixmap();
+#endif
+}
+
+/*!
+ \overload
+
+ Uses a hotspot that positions the pixmap below and to the right of
+ the mouse pointer. This allows the user to clearly see the point
+ on the window where they are dragging the data.
+*/
+void Q3DragObject::setPixmap(QPixmap pm)
+{
+ setPixmap(pm,QPoint(-10, -10));
+}
+
+/*!
+ Returns the currently set pixmap, or a null pixmap if none is set.
+
+ \sa QPixmap::isNull()
+*/
+QPixmap Q3DragObject::pixmap() const
+{
+ return d_func()->pixmap;
+}
+
+/*!
+ Returns the currently set pixmap hotspot.
+
+ \sa setPixmap()
+*/
+QPoint Q3DragObject::pixmapHotSpot() const
+{
+ return d_func()->hot;
+}
+
+/*!
+ Starts a drag operation using the contents of this object, using
+ DragDefault mode.
+
+ The function returns true if the caller should delete the original
+ copy of the dragged data (but see target()); otherwise returns
+ false.
+
+ If the drag contains \e references to information (e.g. file names
+ in a Q3UriDrag are references) then the return value should always
+ be ignored, as the target is expected to directly manipulate the
+ content referred to by the drag object. On X11 the return value should
+ always be correct anyway, but on Windows this is not necessarily
+ the case; e.g. the file manager starts a background process to
+ move files, so the source \e{must not} delete the files!
+
+ Note that on Windows the drag operation will start a blocking modal
+ event loop that will not dispatch any QTimers.
+*/
+bool Q3DragObject::drag()
+{
+ return drag(DragDefault);
+}
+
+/*!
+ After the drag completes, this function will return the QWidget
+ which received the drop, or 0 if the data was dropped on another
+ application.
+
+ This can be useful for detecting the case where drag and drop is
+ to and from the same widget.
+*/
+QWidget *Q3DragObject::target()
+{
+ return last_target;
+}
+
+/*!
+ Starts a drag operation using the contents of this object, using
+ \c DragMove mode. Be sure to read the constraints described in
+ drag().
+
+ Returns true if the data was dragged as a \e move, indicating that
+ the caller should remove the original source of the data (the drag
+ object must continue to have a copy); otherwise returns false.
+
+ \sa drag() dragCopy() dragLink()
+*/
+bool Q3DragObject::dragMove()
+{
+ return drag(DragMove);
+}
+
+
+/*!
+ Starts a drag operation using the contents of this object, using
+ \c DragCopy mode. Be sure to read the constraints described in
+ drag().
+
+ \sa drag() dragMove() dragLink()
+*/
+void Q3DragObject::dragCopy()
+{
+ (void)drag(DragCopy);
+}
+
+/*!
+ Starts a drag operation using the contents of this object, using
+ \c DragLink mode. Be sure to read the constraints described in
+ drag().
+
+ \sa drag() dragCopy() dragMove()
+*/
+void Q3DragObject::dragLink()
+{
+ (void)drag(DragLink);
+}
+
+
+/*!
+ \enum Q3DragObject::DragMode
+
+ This enum describes the possible drag modes.
+
+ \value DragDefault The mode is determined heuristically.
+ \value DragCopy The data is copied.
+ \value DragMove The data is moved.
+ \value DragLink The data is linked.
+ \value DragCopyOrMove The user chooses the mode by using the
+ \key{Shift} key to switch from the default
+ copy mode to move mode.
+*/
+
+
+/*!
+ \overload
+ Starts a drag operation using the contents of this object.
+
+ At this point, the object becomes owned by Qt, not the
+ application. You should not delete the drag object or anything it
+ references. The actual transfer of data to the target application
+ will be done during future event processing - after that time the
+ drag object will be deleted.
+
+ Returns true if the dragged data was dragged as a \e move,
+ indicating that the caller should remove the original source of
+ the data (the drag object must continue to have a copy); otherwise
+ returns false.
+
+ The \a mode specifies the drag mode (see
+ \l{Q3DragObject::DragMode}.) Normally one of the simpler drag(),
+ dragMove(), or dragCopy() functions would be used instead.
+*/
+bool Q3DragObject::drag(DragMode mode)
+{
+ Q_D(Q3DragObject);
+ QDragMime *data = new QDragMime(this);
+ int i = 0;
+ const char *fmt;
+ while ((fmt = format(i))) {
+ data->setData(QLatin1String(fmt), encodedData(fmt));
+ ++i;
+ }
+
+ QDrag *drag = new QDrag(qobject_cast<QWidget *>(parent()));
+ drag->setMimeData(data);
+ drag->setPixmap(d->pixmap);
+ drag->setHotSpot(d->hot);
+
+ Qt::DropActions allowedOps;
+ Qt::DropAction defaultOp = Qt::IgnoreAction;
+ switch(mode) {
+ default:
+ case DragDefault:
+ case DragCopyOrMove:
+ allowedOps = Qt::CopyAction|Qt::MoveAction;
+ defaultOp = Qt::IgnoreAction;
+ break;
+ case DragCopy:
+ allowedOps = Qt::CopyAction;
+ defaultOp = Qt::CopyAction;
+ break;
+ case DragMove:
+ allowedOps = Qt::MoveAction;
+ defaultOp = Qt::MoveAction;
+ break;
+ case DragLink:
+ allowedOps = Qt::LinkAction;
+ defaultOp = Qt::LinkAction;
+ break;
+ }
+ bool retval = (drag->exec(allowedOps, defaultOp) == Qt::MoveAction);
+ last_target = drag->target();
+
+ return retval;
+}
+
+#endif
+
+
+/*!
+ Returns a pointer to the widget where this object originated (the drag
+ source).
+*/
+
+QWidget * Q3DragObject::source()
+{
+ if (parent() && parent()->isWidgetType())
+ return (QWidget *)parent();
+ else
+ return 0;
+}
+
+
+/*!
+ \class Q3DragObject
+
+ \brief The Q3DragObject class encapsulates MIME-based data
+ transfer.
+
+ \compat
+
+ Q3DragObject is the base class for all data that needs to be
+ transferred between and within applications, both for drag and
+ drop and for the clipboard.
+
+ See the \link dnd.html Drag and drop documentation\endlink for an
+ overview of how to provide drag and drop in your application.
+
+ See the QClipboard documentation for an overview of how to provide
+ cut and paste in your application.
+
+ The drag() function is used to start a drag operation. You can
+ specify the \l DragMode in the call or use one of the convenience
+ functions dragCopy(), dragMove(), or dragLink(). The drag source
+ where the data originated is retrieved with source(). If the data
+ was dropped on a widget within the application, target() will
+ return a pointer to that widget. Specify the pixmap to display
+ during the drag with setPixmap().
+*/
+
+static
+void stripws(QByteArray& s)
+{
+ int f;
+ while ((f = s.indexOf(' ')) >= 0)
+ s.remove(f,1);
+}
+
+/*!
+ \class Q3TextDrag
+
+ \brief The Q3TextDrag class is a drag and drop object for
+ transferring plain and Unicode text.
+
+ \compat
+
+ Plain text is passed in a QString which may contain multiple lines
+ (i.e. may contain newline characters). The drag target will receive
+ the newlines according to the runtime environment, e.g. LF on Unix,
+ and CRLF on Windows.
+
+ Qt provides no built-in mechanism for delivering only a single-line.
+
+ For more information about drag and drop, see the Q3DragObject class
+ and the \link dnd.html drag and drop documentation\endlink.
+*/
+
+
+/*!
+ Constructs a text drag object with the given \a name, and sets its data
+ to \a text. The \a dragSource is the widget that the drag operation started
+ from.
+*/
+
+Q3TextDrag::Q3TextDrag(const QString &text, QWidget * dragSource, const char * name)
+ : Q3DragObject(*new Q3TextDragPrivate, dragSource)
+{
+ setObjectName(QLatin1String(name));
+ setText(text);
+}
+
+
+/*!
+ Constructs a default text drag object with the given \a name.
+ The \a dragSource is the widget that the drag operation started from.
+*/
+
+Q3TextDrag::Q3TextDrag(QWidget * dragSource, const char * name)
+ : Q3DragObject(*(new Q3TextDragPrivate), dragSource)
+{
+ setObjectName(QLatin1String(name));
+}
+
+/*! \internal */
+Q3TextDrag::Q3TextDrag(Q3TextDragPrivate &dd, QWidget *dragSource)
+ : Q3DragObject(dd, dragSource)
+{
+
+}
+
+/*!
+ Destroys the text drag object.
+*/
+Q3TextDrag::~Q3TextDrag()
+{
+
+}
+
+/*!
+ \fn void Q3TextDrag::setSubtype(const QString &subtype)
+
+ Sets the MIME \a subtype of the text being dragged. The default subtype
+ is "plain", so the default MIME type of the text is "text/plain".
+ You might use this to declare that the text is "text/html" by calling
+ setSubtype("html").
+*/
+void Q3TextDrag::setSubtype(const QString & st)
+{
+ d_func()->setSubType(st);
+}
+
+/*!
+ Sets the \a text to be dragged. You will need to call this if you did
+ not pass the text during construction.
+*/
+void Q3TextDrag::setText(const QString &text)
+{
+ d_func()->txt = text;
+}
+
+
+/*!
+ \reimp
+*/
+const char * Q3TextDrag::format(int i) const
+{
+ if (i > 0)
+ return 0;
+ return d_func()->fmt.constData();
+}
+
+QTextCodec* qt_findcharset(const QByteArray& mimetype)
+{
+ int i=mimetype.indexOf("charset=");
+ if (i >= 0) {
+ QByteArray cs = mimetype.mid(i+8);
+ stripws(cs);
+ i = cs.indexOf(';');
+ if (i >= 0)
+ cs = cs.left(i);
+ // win98 often has charset=utf16, and we need to get the correct codec for
+ // it to be able to get Unicode text drops.
+ if (cs == "utf16")
+ cs = "ISO-10646-UCS-2";
+ // May return 0 if unknown charset
+ return QTextCodec::codecForName(cs);
+ }
+ // no charset=, use locale
+ return QTextCodec::codecForName("utf-8");
+}
+
+static QTextCodec *codecForHTML(const QByteArray &ba)
+{
+ // determine charset
+ int mib = 0;
+ int pos;
+ QTextCodec *c = 0;
+
+ if (ba.size() > 1 && (((uchar)ba[0] == 0xfe && (uchar)ba[1] == 0xff)
+ || ((uchar)ba[0] == 0xff && (uchar)ba[1] == 0xfe))) {
+ mib = 1015; // utf16
+ } else if (ba.size() > 2
+ && (uchar)ba[0] == 0xef
+ && (uchar)ba[1] == 0xbb
+ && (uchar)ba[2] == 0xbf) {
+ mib = 106; // utf-8
+ } else {
+ pos = 0;
+ while ((pos = ba.indexOf('<', pos)) != -1) {
+ int end = ba.indexOf('>', pos+1);
+ if (end == -1)
+ break;
+ const QString str(QString::fromLatin1(ba.mid(pos, end-pos)));
+ if (str.contains(QLatin1String("meta http-equiv="), Qt::CaseInsensitive)) {
+ pos = str.indexOf(QLatin1String("charset="), 0, Qt::CaseInsensitive) + int(strlen("charset="));
+ if (pos != -1) {
+ int pos2 = ba.indexOf('\"', pos+1);
+ QByteArray cs = ba.mid(pos, pos2-pos);
+ c = QTextCodec::codecForName(cs);
+ if (c)
+ return c;
+ }
+ }
+ pos = end;
+ }
+ }
+ if (mib)
+ c = QTextCodec::codecForMib(mib);
+
+ return c;
+}
+
+static
+QTextCodec* findcodec(const QMimeSource* e)
+{
+ QTextCodec* r = 0;
+ const char* f;
+ int i;
+ for (i=0; (f=e->format(i)); i++) {
+ bool html = !qstrnicmp(f, "text/html", 9);
+ if (html)
+ r = codecForHTML(e->encodedData(f));
+ if (!r)
+ r = qt_findcharset(QByteArray(f).toLower());
+ if (r)
+ return r;
+ }
+ return 0;
+}
+
+
+
+/*!
+ \reimp
+*/
+QByteArray Q3TextDrag::encodedData(const char* mime) const
+{
+ Q_D(const Q3TextDrag);
+ if (mime != d->fmt)
+ return QByteArray();
+ return d->txt.toUtf8();
+}
+
+/*!
+ \fn bool Q3TextDrag::canDecode(const QMimeSource *source)
+
+ Returns true if the information in the MIME \a source can be decoded
+ into a QString; otherwise returns false.
+
+ \sa decode()
+*/
+bool Q3TextDrag::canDecode(const QMimeSource* e)
+{
+ const char* f;
+ for (int i=0; (f=e->format(i)); i++) {
+ if (0==qstrnicmp(f,"text/",5)) {
+ return findcodec(e) != 0;
+ }
+ }
+ return false;
+}
+
+/*!
+ \fn bool Q3TextDrag::decode(const QMimeSource *source, QString &string, QString &subtype)
+
+ \overload
+
+ Attempts to decode the dropped information in the MIME \a source into
+ the \a string given.
+ Returns true if successful; otherwise returns false. If \a subtype
+ is null, any text subtype is accepted; otherwise only the
+ specified \a subtype is accepted.
+
+ \sa canDecode()
+*/
+bool Q3TextDrag::decode(const QMimeSource* e, QString& str, QString& subtype)
+{
+ if(!e)
+ return false;
+
+ const char* mime;
+ for (int i=0; (mime = e->format(i)); i++) {
+ if (0==qstrnicmp(mime,"text/",5)) {
+ QByteArray m(mime);
+ m = m.toLower();
+ int semi = m.indexOf(';');
+ if (semi < 0)
+ semi = m.length();
+ QString foundst(QString::fromLatin1(m.mid(5,semi-5)));
+ if (subtype.isNull() || foundst == subtype) {
+ bool html = !qstrnicmp(mime, "text/html", 9);
+ QTextCodec* codec = 0;
+ if (html)
+ // search for the charset tag in the HTML
+ codec = codecForHTML(e->encodedData(mime));
+ if (!codec)
+ codec = qt_findcharset(m);
+ if (codec) {
+ QByteArray payload;
+
+ payload = e->encodedData(mime);
+ if (payload.size()) {
+ int l;
+ if (codec->mibEnum() != 1015) {
+ // length is at NUL or payload.size()
+ l = 0;
+ while (l < (int)payload.size() && payload[l])
+ l++;
+ } else {
+ l = payload.size();
+ }
+
+ str = codec->toUnicode(payload,l);
+
+ if (subtype.isNull())
+ subtype = foundst;
+
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+/*!
+ \fn bool Q3TextDrag::decode(const QMimeSource *source, QString &string)
+
+ Attempts to decode the dropped information in the MIME \a source into
+ the \a string given.
+ Returns true if successful; otherwise returns false.
+
+ \sa canDecode()
+*/
+bool Q3TextDrag::decode(const QMimeSource* e, QString& str)
+{
+ QString st;
+ return decode(e, str, st);
+}
+
+
+/*
+ Q3ImageDrag could use an internal MIME type for communicating QPixmaps
+ and QImages rather than always converting to raw data. This is available
+ for that purpose and others. It is not currently used.
+*/
+
+/*!
+ \class Q3ImageDrag
+
+ \brief The Q3ImageDrag class provides a drag and drop object for
+ transferring images.
+
+ \compat
+
+ Images are offered to the receiving application in multiple
+ formats, determined by Qt's output formats.
+*/
+
+/*!
+ Constructs an image drag object with the given \a name, and sets its
+ data to \a image. The \a dragSource is the widget that the drag operation
+ started from.
+*/
+
+Q3ImageDrag::Q3ImageDrag(QImage image,
+ QWidget * dragSource, const char * name)
+ : Q3DragObject(*(new Q3ImageDragPrivate), dragSource)
+{
+ setObjectName(QLatin1String(name));
+ setImage(image);
+}
+
+/*!
+ Constructs a default image drag object with the given \a name.
+ The \a dragSource is the widget that the drag operation started from.
+*/
+
+Q3ImageDrag::Q3ImageDrag(QWidget * dragSource, const char * name)
+ : Q3DragObject(*(new Q3ImageDragPrivate), dragSource)
+{
+ setObjectName(QLatin1String(name));
+}
+
+/*! \internal */
+Q3ImageDrag::Q3ImageDrag(Q3ImageDragPrivate &dd, QWidget *dragSource)
+ : Q3DragObject(dd, dragSource)
+{
+}
+
+/*!
+ Destroys the image drag object.
+*/
+
+Q3ImageDrag::~Q3ImageDrag()
+{
+ // nothing
+}
+
+
+/*!
+ Sets the \a image to be dragged. You will need to call this if you did
+ not pass the image during construction.
+*/
+void Q3ImageDrag::setImage(QImage image)
+{
+ Q_D(Q3ImageDrag);
+ d->img = image;
+ QList<QByteArray> formats = QImageWriter::supportedImageFormats();
+ formats.removeAll("PBM"); // remove non-raw PPM
+ if (image.depth()!=32) {
+ // BMP better than PPM for paletted images
+ if (formats.removeAll("BMP")) // move to front
+ formats.insert(0,"BMP");
+ }
+ // PNG is best of all
+ if (formats.removeAll("PNG")) // move to front
+ formats.insert(0,"PNG");
+
+ for(int i = 0; i < formats.count(); i++) {
+ QByteArray format("image/");
+ format += formats.at(i);
+ format = format.toLower();
+ if (format == "image/pbmraw")
+ format = "image/ppm";
+ d->ofmts.append(format);
+ }
+ d->ofmts.append("application/x-qt-image");
+}
+
+/*!
+ \reimp
+*/
+const char * Q3ImageDrag::format(int i) const
+{
+ Q_D(const Q3ImageDrag);
+ return i < d->ofmts.count() ? d->ofmts.at(i).data() : 0;
+}
+
+/*!
+ \reimp
+*/
+QByteArray Q3ImageDrag::encodedData(const char* fmt) const
+{
+ Q_D(const Q3ImageDrag);
+ QString imgFormat(fmt);
+ if (imgFormat == QLatin1String("application/x-qt-image"))
+ imgFormat = QLatin1String("image/PNG");
+
+ if (imgFormat.startsWith("image/")){
+ QByteArray f(imgFormat.mid(6).toAscii());
+ QByteArray dat;
+ QBuffer w(&dat);
+ w.open(QIODevice::WriteOnly);
+ QImageWriter writer(&w, f.toUpper());
+ if (!writer.write(d->img))
+ return QByteArray();
+ w.close();
+ return dat;
+ } else {
+ return QByteArray();
+ }
+}
+
+/*!
+ \fn bool Q3ImageDrag::canDecode(const QMimeSource *source)
+
+ Returns true if the information in the MIME \a source can be decoded
+ into an image; otherwise returns false.
+
+ \sa decode()
+*/
+bool Q3ImageDrag::canDecode(const QMimeSource* e)
+{
+ return e->provides("application/x-qt-image");
+}
+
+/*!
+ \fn bool Q3ImageDrag::decode(const QMimeSource *source, QImage &image)
+
+ Decode the dropped information in the MIME \a source into the \a image.
+ Returns true if successful; otherwise returns false.
+
+ \sa canDecode()
+*/
+bool Q3ImageDrag::decode(const QMimeSource* e, QImage& img)
+{
+ if (!e)
+ return false;
+
+ QByteArray payload = e->encodedData("application/x-qt-image");
+ if (payload.isEmpty())
+ return false;
+
+ img.loadFromData(payload);
+ if (img.isNull())
+ return false;
+
+ return true;
+}
+
+/*!
+ \fn bool Q3ImageDrag::decode(const QMimeSource *source, QPixmap &pixmap)
+
+ \overload
+
+ Decodes the dropped information in the MIME \a source into the \a pixmap.
+ Returns true if successful; otherwise returns false.
+
+ This is a convenience function that converts the information to a QPixmap
+ via a QImage.
+
+ \sa canDecode()
+*/
+bool Q3ImageDrag::decode(const QMimeSource* e, QPixmap& pm)
+{
+ if (!e)
+ return false;
+
+ QImage img;
+ // We avoid dither, since the image probably came from this display
+ if (decode(e, img)) {
+ pm = QPixmap::fromImage(img, Qt::AvoidDither);
+ if (pm.isNull())
+ return false;
+
+ return true;
+ }
+ return false;
+}
+
+
+
+
+/*!
+ \class Q3StoredDrag
+ \brief The Q3StoredDrag class provides a simple stored-value drag object for arbitrary MIME data.
+
+ \compat
+
+ When a block of data has only one representation, you can use a
+ Q3StoredDrag to hold it.
+
+ For more information about drag and drop, see the Q3DragObject
+ class and the \link dnd.html drag and drop documentation\endlink.
+*/
+
+/*!
+ Constructs a Q3StoredDrag. The \a dragSource and \a name are passed
+ to the Q3DragObject constructor, and the format is set to \a
+ mimeType.
+
+ The data will be unset. Use setEncodedData() to set it.
+*/
+Q3StoredDrag::Q3StoredDrag(const char* mimeType, QWidget * dragSource, const char * name) :
+ Q3DragObject(*new Q3StoredDragPrivate, dragSource)
+{
+ Q_D(Q3StoredDrag);
+ setObjectName(QLatin1String(name));
+ d->fmt = qstrdup(mimeType);
+}
+
+/*! \internal */
+Q3StoredDrag::Q3StoredDrag(Q3StoredDragPrivate &dd, const char* mimeType, QWidget * dragSource)
+ : Q3DragObject(dd, dragSource)
+{
+ d_func()->fmt = qstrdup(mimeType);
+}
+
+/*!
+ Destroys the drag object.
+*/
+Q3StoredDrag::~Q3StoredDrag()
+{
+ delete [] (char*)d_func()->fmt;
+}
+
+/*!
+ \reimp
+*/
+const char * Q3StoredDrag::format(int i) const
+{
+ if (i==0)
+ return d_func()->fmt;
+ else
+ return 0;
+}
+
+
+/*!
+ \fn void Q3StoredDrag::setEncodedData(const QByteArray &data)
+
+ Sets the encoded \a data of this drag object. The encoded data is
+ delivered to drop sites; it must be in a strictly defined and portable
+ format.
+
+ The drag object can't be dropped (by the user) until this function
+ has been called.
+*/
+
+void Q3StoredDrag::setEncodedData(const QByteArray & encodedData)
+{
+ d_func()->enc = encodedData;
+}
+
+/*!
+ \fn QByteArray Q3StoredDrag::encodedData(const char *format) const
+
+ Returns the stored data in the \a format given.
+
+ \sa setEncodedData()
+*/
+QByteArray Q3StoredDrag::encodedData(const char* m) const
+{
+ if (!qstricmp(m, d_func()->fmt))
+ return d_func()->enc;
+ else
+ return QByteArray();
+}
+
+
+/*!
+ \class Q3UriDrag
+ \brief The Q3UriDrag class provides a drag object for a list of URI references.
+
+ \compat
+
+ URIs are a useful way to refer to files that may be distributed
+ across multiple machines. A URI will often refer to a file on a
+ machine local to both the drag source and the drop target, so the
+ URI can be equivalent to passing a file name but is more
+ extensible.
+
+ Use URIs in Unicode form so that the user can comfortably edit and
+ view them. For use in HTTP or other protocols, use the correctly
+ escaped ASCII form.
+
+ You can convert a list of file names to file URIs using
+ setFileNames(), or into human-readable form with setUnicodeUris().
+
+ Static functions are provided to convert between filenames and
+ URIs; e.g. uriToLocalFile() and localFileToUri(). Static functions
+ are also provided to convert URIs to and from human-readable form;
+ e.g. uriToUnicodeUri() and unicodeUriToUri().
+ You can also decode URIs from a MIME source into a list with
+ decodeLocalFiles() and decodeToUnicodeUris().
+*/
+
+/*!
+ Constructs an object to drag the list of \a uris.
+ The \a dragSource and \a name are passed to the Q3StoredDrag constructor.
+
+ Note that URIs are always in escaped UTF8 encoding.
+*/
+Q3UriDrag::Q3UriDrag(const Q3StrList &uris, QWidget * dragSource, const char * name) :
+ Q3StoredDrag("text/uri-list", dragSource)
+{
+ setObjectName(QLatin1String(name));
+ setUris(uris);
+}
+
+/*!
+ Constructs an object to drag with the given \a name.
+ You must call setUris() before you start the drag().
+ Both the \a dragSource and the \a name are passed to the Q3StoredDrag
+ constructor.
+*/
+Q3UriDrag::Q3UriDrag(QWidget * dragSource, const char * name) :
+ Q3StoredDrag("text/uri-list", dragSource)
+{
+ setObjectName(QLatin1String(name));
+}
+#endif
+
+/*!
+ Destroys the URI drag object.
+*/
+Q3UriDrag::~Q3UriDrag()
+{
+}
+
+/*!
+ \fn void Q3UriDrag::setUris(const QList<QByteArray> &list)
+
+ Changes the \a list of URIs to be dragged.
+
+ Note that URIs are always in escaped UTF8 encoding.
+*/
+void Q3UriDrag::setUris(const QList<QByteArray> &uris)
+{
+ QByteArray a;
+ int c = 0;
+ int i;
+ int count = uris.count();
+ for (i = 0; i < count; ++i)
+ c += uris.at(i).size() + 2; //length + \r\n
+ a.reserve(c+1);
+ for (i = 0; i < count; ++i) {
+ a.append(uris.at(i));
+ a.append("\r\n");
+ }
+ a[c] = 0;
+ setEncodedData(a);
+}
+
+
+/*!
+ \fn bool Q3UriDrag::canDecode(const QMimeSource *source)
+
+ Returns true if decode() can decode the MIME \a source; otherwise
+ returns false.
+*/
+bool Q3UriDrag::canDecode(const QMimeSource* e)
+{
+ return e->provides("text/uri-list");
+}
+
+/*!
+ \fn bool Q3UriDrag::decode(const QMimeSource* source, Q3StrList& list)
+
+ Decodes URIs from the MIME \a source, placing the result in the \a list.
+ The list is cleared before any items are inserted.
+
+ Returns true if the MIME \a source contained a valid list of URIs;
+ otherwise returns false.
+*/
+bool Q3UriDrag::decode(const QMimeSource* e, Q3StrList& l)
+{
+ QByteArray payload = e->encodedData("text/uri-list");
+ if (payload.size()) {
+ l.clear();
+ l.setAutoDelete(true);
+ uint c=0;
+ const char* data = payload.data();
+ while ((int)c < payload.size() && data[c]) {
+ uint f = c;
+ // Find line end
+ while ((int)c < payload.size() && data[c] && data[c]!='\r'
+ && data[c] != '\n')
+ c++;
+ Q3CString s(data+f,c-f+1);
+ if (s[0] != '#') // non-comment?
+ l.append(s);
+ // Skip junk
+ while ((int)c < payload.size() && data[c] &&
+ (data[c]=='\n' || data[c]=='\r'))
+ c++;
+ }
+ return true;
+ }
+ return false;
+}
+
+static uint htod(int h)
+{
+ if (isdigit(h))
+ return h - '0';
+ return tolower(h) - 'a' + 10;
+}
+
+/*!
+ \fn Q3UriDrag::setFilenames(const QStringList &list)
+
+ \obsolete
+
+ Sets the filename's in the drag object to those in the given \a
+ list.
+
+ Use setFileNames() instead.
+*/
+
+/*!
+ \fn void Q3UriDrag::setFileNames(const QStringList &filenames)
+
+ Sets the URIs to be local file URIs equivalent to the \a filenames.
+
+ \sa localFileToUri(), setUris()
+*/
+void Q3UriDrag::setFileNames(const QStringList & fnames)
+{
+ QList<QByteArray> uris;
+ for (QStringList::ConstIterator i = fnames.begin();
+ i != fnames.end(); ++i) {
+ QByteArray fileUri = localFileToUri(*i);
+ if (!fileUri.isEmpty())
+ uris.append(fileUri);
+ }
+
+ setUris(uris);
+}
+
+/*!
+ \fn void Q3UriDrag::setFileNames(const QString &name)
+ \fn void Q3UriDrag::setFilenames(const QString &name)
+
+ Same as setFileNames(QStringList(\a name)).
+*/
+
+/*!
+ \fn void Q3UriDrag::setUnicodeUris(const QStringList &list)
+
+ Sets the URIs in the \a list to be Unicode URIs (only useful for
+ displaying to humans).
+
+ \sa localFileToUri(), setUris()
+*/
+void Q3UriDrag::setUnicodeUris(const QStringList & uuris)
+{
+ QList<QByteArray> uris;
+ for (int i = 0; i < uuris.count(); ++i)
+ uris.append(unicodeUriToUri(uuris.at(i)));
+ setUris(uris);
+}
+
+/*!
+ \fn QByteArray Q3UriDrag::unicodeUriToUri(const QString &string)
+
+ Returns the URI equivalent of the Unicode URI given in the \a string
+ (only useful for displaying to humans).
+
+ \sa uriToLocalFile()
+*/
+QByteArray Q3UriDrag::unicodeUriToUri(const QString& uuri)
+{
+ QByteArray utf8 = uuri.toUtf8();
+ QByteArray escutf8;
+ int n = utf8.length();
+ bool isFile = uuri.startsWith(QLatin1String("file://"));
+ for (int i=0; i<n; i++) {
+ if ((utf8[i] >= 'a' && utf8[i] <= 'z')
+ || utf8[i] == '/'
+ || (utf8[i] >= '0' && utf8[i] <= '9')
+ || (utf8[i] >= 'A' && utf8[i] <= 'Z')
+
+ || utf8[i] == '-' || utf8[i] == '_'
+ || utf8[i] == '.' || utf8[i] == '!'
+ || utf8[i] == '~' || utf8[i] == '*'
+ || utf8[i] == '(' || utf8[i] == ')'
+ || utf8[i] == '\''
+
+ // Allow this through, so that all URI-references work.
+ || (!isFile && utf8[i] == '#')
+
+ || utf8[i] == ';'
+ || utf8[i] == '?' || utf8[i] == ':'
+ || utf8[i] == '@' || utf8[i] == '&'
+ || utf8[i] == '=' || utf8[i] == '+'
+ || utf8[i] == '$' || utf8[i] == ',')
+ {
+ escutf8 += utf8[i];
+ } else {
+ // Everything else is escaped as %HH
+ QString s;
+ s.sprintf("%%%02x",(uchar)utf8[i]);
+ escutf8 += s.latin1();
+ }
+ }
+ return escutf8;
+}
+
+/*!
+ Returns the URI equivalent to the absolute local \a filename.
+
+ \sa uriToLocalFile()
+*/
+QByteArray Q3UriDrag::localFileToUri(const QString& filename)
+{
+ QString r = filename;
+
+ //check that it is an absolute file
+ if (QDir::isRelativePath(r))
+ return QByteArray();
+#ifdef Q_WS_WIN
+
+
+ bool hasHost = false;
+ // convert form network path
+ if (r.left(2) == QLatin1String("\\\\") || r.left(2) == QLatin1String("//")) {
+ r.remove(0, 2);
+ hasHost = true;
+ }
+
+ // Slosh -> Slash
+ int slosh;
+ while ((slosh=r.indexOf(QLatin1Char('\\'))) >= 0) {
+ r[slosh] = QLatin1Char('/');
+ }
+
+ // Drive
+ if (r[0] != QLatin1Char('/') && !hasHost)
+ r.insert(0,QLatin1Char('/'));
+
+#endif
+#if defined (Q_WS_X11) && 0
+ // URL without the hostname is considered to be errorneous by XDnD.
+ // See: http://www.newplanetsoftware.com/xdnd/dragging_files.html
+ // This feature is not active because this would break dnd between old and new qt apps.
+ char hostname[257];
+ if (gethostname(hostname, 255) == 0) {
+ hostname[256] = '\0';
+ r.prepend(QString::fromLatin1(hostname));
+ }
+#endif
+ return unicodeUriToUri(QString(QLatin1String("file://") + r));
+}
+
+/*!
+ \fn QString Q3UriDrag::uriToUnicodeUri(const char *string)
+
+ Returns the Unicode URI (only useful for displaying to humans)
+ equivalent of the URI given in the \a string.
+
+ Note that URIs are always in escaped UTF8 encoding.
+
+ \sa localFileToUri()
+*/
+QString Q3UriDrag::uriToUnicodeUri(const char* uri)
+{
+ QByteArray utf8;
+
+ while (*uri) {
+ switch (*uri) {
+ case '%': {
+ uint ch = (uchar) uri[1];
+ if (ch && uri[2]) {
+ ch = htod(ch) * 16 + htod((uchar) uri[2]);
+ utf8 += (char) ch;
+ uri += 2;
+ }
+ }
+ break;
+ default:
+ utf8 += *uri;
+ }
+ ++uri;
+ }
+
+ return QString::fromUtf8(utf8);
+}
+
+/*!
+ \fn QString Q3UriDrag::uriToLocalFile(const char *string)
+
+ Returns the name of a local file equivalent to the URI given in the
+ \a string, or an empty string if it does not refer to a local file.
+
+ Note that URIs are always in escaped UTF8 encoding.
+
+ \sa localFileToUri()
+*/
+QString Q3UriDrag::uriToLocalFile(const char* uri)
+{
+ QString file;
+
+ if (!uri)
+ return file;
+ if (0==qstrnicmp(uri,"file:/",6)) // It is a local file uri
+ uri += 6;
+ else if (QString(QLatin1String(uri)).indexOf(QLatin1String(":/")) != -1) // It is a different scheme uri
+ return file;
+
+ bool local = uri[0] != '/' || (uri[0] != '\0' && uri[1] == '/');
+#ifdef Q_WS_X11
+ // do we have a hostname?
+ if (!local && uri[0] == '/' && uri[2] != '/') {
+ // then move the pointer to after the 'hostname/' part of the uri
+ const char* hostname_end = strchr(uri+1, '/');
+ if (hostname_end != NULL) {
+ char hostname[257];
+ if (gethostname(hostname, 255) == 0) {
+ hostname[256] = '\0';
+ if (qstrncmp(uri+1, hostname, hostname_end - (uri+1)) == 0) {
+ uri = hostname_end + 1; // point after the slash
+ local = true;
+ }
+ }
+ }
+ }
+#endif
+ if (local) {
+ file = uriToUnicodeUri(uri);
+ if (uri[1] == '/') {
+ file.remove((uint)0,1);
+ } else {
+ file.insert(0, QLatin1Char('/'));
+ }
+#ifdef Q_WS_WIN
+ if (file.length() > 2 && file[0] == QLatin1Char('/') && file[2] == QLatin1Char('|')) {
+ file[2] = QLatin1Char(':');
+ file.remove(0,1);
+ } else if (file.length() > 2 && file[0] == QLatin1Char('/') && file[1].isLetter() && file[2] == QLatin1Char(':')) {
+ file.remove(0, 1);
+ }
+ // Leave slash as slashes.
+#endif
+ }
+#ifdef Q_WS_WIN
+ else {
+ file = uriToUnicodeUri(uri);
+ // convert to network path
+ file.insert(1, QLatin1Char('/')); // leave as forward slashes
+ }
+#endif
+
+ return file;
+}
+
+/*!
+ \fn bool Q3UriDrag::decodeLocalFiles(const QMimeSource *source, QStringList &list)
+
+ Decodes URIs from the MIME \a source, converting them to local filenames
+ where possible, and places them in the \a list (which is first cleared).
+
+ Returns true if the MIME \a source contained a valid list of URIs;
+ otherwise returns false. The list will be empty if no URIs referred to
+ local files.
+*/
+bool Q3UriDrag::decodeLocalFiles(const QMimeSource* e, QStringList& l)
+{
+ Q3StrList u;
+ if (!decode(e, u))
+ return false;
+
+ l.clear();
+ for (uint i = 0; i < u.count(); ++i) {
+ QString lf = uriToLocalFile(u.at(i));
+ if (!lf.isEmpty())
+ l.append(lf);
+ }
+ return true;
+}
+
+/*!
+ \fn bool Q3UriDrag::decodeToUnicodeUris(const QMimeSource *source, QStringList &list)
+
+ Decodes URIs from the MIME \a source, converting them to Unicode URIs
+ (only useful for displaying to humans), and places them in the \a list
+ (which is first cleared).
+
+ Returns true if the MIME \a source contained a valid list of URIs;
+ otherwise returns false.
+*/
+bool Q3UriDrag::decodeToUnicodeUris(const QMimeSource* e, QStringList& l)
+{
+ Q3StrList u;
+ if (!decode(e, u))
+ return false;
+
+ l.clear();
+ for (uint i = 0; i < u.count(); ++i)
+ l.append(uriToUnicodeUri(u.at(i)));
+
+ return true;
+}
+
+/*!
+ \class Q3ColorDrag
+
+ \brief The Q3ColorDrag class provides a drag and drop object for
+ transferring colors between widgets.
+
+ \compat
+
+ This class provides a drag object which can be used to transfer data
+ about colors for drag and drop and in the clipboard. For example, it
+ is used in QColorDialog.
+
+ The color is set in the constructor but can be changed with
+ setColor().
+
+ For more information about drag and drop, see the Q3DragObject class
+ and the \link dnd.html drag and drop documentation\endlink.
+*/
+
+/*!
+ Constructs a color drag object with the given \a col. Passes \a
+ dragsource and \a name to the Q3StoredDrag constructor.
+*/
+
+Q3ColorDrag::Q3ColorDrag(const QColor &col, QWidget *dragsource, const char *name)
+ : Q3StoredDrag("application/x-color", dragsource)
+{
+ setObjectName(QLatin1String(name));
+ setColor(col);
+}
+
+/*!
+ Constructs a color drag object with a white color. Passes \a
+ dragsource and \a name to the Q3StoredDrag constructor.
+*/
+
+Q3ColorDrag::Q3ColorDrag(QWidget *dragsource, const char *name)
+ : Q3StoredDrag("application/x-color", dragsource)
+{
+ setObjectName(QLatin1String(name));
+ setColor(Qt::white);
+}
+
+/*!
+ \fn void Q3ColorDrag::setColor(const QColor &color)
+
+ Sets the \a color of the color drag.
+*/
+
+void Q3ColorDrag::setColor(const QColor &col)
+{
+ short r = (col.red() << 8) | col.red();
+ short g = (col.green() << 8) | col.green();
+ short b = (col.blue() << 8) | col.blue();
+
+ // make sure we transmit data in network order
+ r = htons(r);
+ g = htons(g);
+ b = htons(b);
+
+ ushort rgba[4] = {
+ r, g, b,
+ 0xffff // Alpha not supported yet.
+ };
+ QByteArray data;
+ data.resize(sizeof(rgba));
+ memcpy(data.data(), rgba, sizeof(rgba));
+ setEncodedData(data);
+}
+
+/*!
+ \fn bool Q3ColorDrag::canDecode(QMimeSource *source)
+
+ Returns true if the color drag object can decode the MIME \a source;
+ otherwise returns false.
+*/
+
+bool Q3ColorDrag::canDecode(QMimeSource *e)
+{
+ return e->provides("application/x-color");
+}
+
+/*!
+ \fn bool Q3ColorDrag::decode(QMimeSource *source, QColor &color)
+
+ Decodes the MIME \a source, and sets the decoded values to the
+ given \a color. Returns true if the decoding is successful.
+ Returns false if the size of the encoded data is not the
+ expected size.
+*/
+
+bool Q3ColorDrag::decode(QMimeSource *e, QColor &col)
+{
+ QByteArray data = e->encodedData("application/x-color");
+ ushort rgba[4];
+ if (data.size() != sizeof(rgba))
+ return false;
+
+ memcpy(rgba, data.constData(), sizeof(rgba));
+
+ short r = rgba[0];
+ short g = rgba[1];
+ short b = rgba[2];
+ short a = rgba[3];
+
+ // data is in network order
+ r = ntohs(r);
+ g = ntohs(g);
+ b = ntohs(b);
+ a = ntohs(a);
+
+ r = (r >> 8) & 0xff;
+ g = (g >> 8) & 0xff;
+ b = (b >> 8) & 0xff;
+ a = (a >> 8) & 0xff;
+
+ col.setRgb(r, g, b, a);
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qt3support/other/q3dragobject.h b/src/qt3support/other/q3dragobject.h
new file mode 100644
index 0000000..10645c8
--- /dev/null
+++ b/src/qt3support/other/q3dragobject.h
@@ -0,0 +1,218 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3DRAGOBJECT_H
+#define Q3DRAGOBJECT_H
+
+#include <QtCore/qobject.h>
+#include <QtGui/qcolor.h>
+#include <QtGui/qmime.h>
+#include <QtGui/qimage.h>
+#include <Qt3Support/q3strlist.h>
+#include <QtCore/qlist.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3SupportLight)
+
+class QWidget;
+class Q3TextDragPrivate;
+class Q3DragObjectPrivate;
+class Q3StoredDragPrivate;
+class Q3ImageDragPrivate;
+class Q3ImageDrag;
+class Q3TextDrag;
+class Q3StrList;
+class QImage;
+class QPixmap;
+
+class Q_COMPAT_EXPORT Q3DragObject : public QObject, public QMimeSource {
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(Q3DragObject)
+public:
+ Q3DragObject(QWidget * dragSource = 0, const char *name = 0);
+ virtual ~Q3DragObject();
+
+ bool drag();
+ bool dragMove();
+ void dragCopy();
+ void dragLink();
+
+ virtual void setPixmap(QPixmap);
+ virtual void setPixmap(QPixmap, const QPoint& hotspot);
+ QPixmap pixmap() const;
+ QPoint pixmapHotSpot() const;
+
+ QWidget * source();
+ static QWidget * target();
+
+ enum DragMode { DragDefault, DragCopy, DragMove, DragLink, DragCopyOrMove };
+
+protected:
+ Q3DragObject(Q3DragObjectPrivate &, QWidget *dragSource = 0);
+ virtual bool drag(DragMode);
+
+private:
+ friend class QDragMime;
+ Q_DISABLE_COPY(Q3DragObject)
+};
+
+class Q_COMPAT_EXPORT Q3StoredDrag: public Q3DragObject {
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(Q3StoredDrag)
+public:
+ Q3StoredDrag(const char *mimeType, QWidget *dragSource = 0, const char *name = 0);
+ ~Q3StoredDrag();
+
+ virtual void setEncodedData(const QByteArray &);
+
+ const char * format(int i) const;
+ virtual QByteArray encodedData(const char*) const;
+
+protected:
+ Q3StoredDrag(Q3StoredDragPrivate &, const char *mimeType, QWidget *dragSource = 0);
+
+private:
+ Q_DISABLE_COPY(Q3StoredDrag)
+};
+
+class Q_COMPAT_EXPORT Q3TextDrag: public Q3DragObject {
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(Q3TextDrag)
+public:
+ Q3TextDrag(const QString &, QWidget *dragSource = 0, const char *name = 0);
+ Q3TextDrag(QWidget * dragSource = 0, const char * name = 0);
+ ~Q3TextDrag();
+
+ virtual void setText(const QString &);
+ virtual void setSubtype(const QString &);
+
+ const char * format(int i) const;
+ virtual QByteArray encodedData(const char*) const;
+
+ static bool canDecode(const QMimeSource* e);
+ static bool decode(const QMimeSource* e, QString& s);
+ static bool decode(const QMimeSource* e, QString& s, QString& subtype);
+
+protected:
+ Q3TextDrag(Q3TextDragPrivate &, QWidget * dragSource = 0);
+
+private:
+ Q_DISABLE_COPY(Q3TextDrag)
+};
+
+class Q_COMPAT_EXPORT Q3ImageDrag: public Q3DragObject {
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(Q3ImageDrag)
+public:
+ Q3ImageDrag(QImage image, QWidget * dragSource = 0, const char * name = 0);
+ Q3ImageDrag(QWidget * dragSource = 0, const char * name = 0);
+ ~Q3ImageDrag();
+
+ virtual void setImage(QImage image);
+
+ const char * format(int i) const;
+ virtual QByteArray encodedData(const char*) const;
+
+ static bool canDecode(const QMimeSource* e);
+ static bool decode(const QMimeSource* e, QImage& i);
+ static bool decode(const QMimeSource* e, QPixmap& i);
+
+protected:
+ Q3ImageDrag(Q3ImageDragPrivate &, QWidget * dragSource = 0);
+
+private:
+ Q_DISABLE_COPY(Q3ImageDrag)
+};
+
+
+class Q_COMPAT_EXPORT Q3UriDrag: public Q3StoredDrag {
+ Q_OBJECT
+
+public:
+ Q3UriDrag(const Q3StrList &uris, QWidget * dragSource = 0, const char * name = 0);
+ Q3UriDrag(QWidget * dragSource = 0, const char * name = 0);
+ ~Q3UriDrag();
+
+ void setFileNames(const QStringList & fnames);
+ inline void setFileNames(const QString & fname) { setFileNames(QStringList(fname)); }
+ void setFilenames(const QStringList & fnames) { setFileNames(fnames); }
+ inline void setFilenames(const QString & fname) { setFileNames(QStringList(fname)); }
+ void setUnicodeUris(const QStringList & uuris);
+ virtual void setUris(const QList<QByteArray> &uris);
+
+ static QString uriToLocalFile(const char*);
+ static QByteArray localFileToUri(const QString&);
+ static QString uriToUnicodeUri(const char*);
+ static QByteArray unicodeUriToUri(const QString&);
+ static bool canDecode(const QMimeSource* e);
+ static bool decode(const QMimeSource* e, Q3StrList& i);
+ static bool decodeToUnicodeUris(const QMimeSource* e, QStringList& i);
+ static bool decodeLocalFiles(const QMimeSource* e, QStringList& i);
+
+private:
+ Q_DISABLE_COPY(Q3UriDrag)
+};
+
+class Q_COMPAT_EXPORT Q3ColorDrag : public Q3StoredDrag
+{
+ Q_OBJECT
+ QColor color;
+
+public:
+ Q3ColorDrag(const QColor &col, QWidget *dragsource = 0, const char *name = 0);
+ Q3ColorDrag(QWidget * dragSource = 0, const char * name = 0);
+ void setColor(const QColor &col);
+
+ static bool canDecode(QMimeSource *);
+ static bool decode(QMimeSource *, QColor &col);
+
+private:
+ Q_DISABLE_COPY(Q3ColorDrag)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // Q3DRAGOBJECT_H
diff --git a/src/qt3support/other/q3dropsite.cpp b/src/qt3support/other/q3dropsite.cpp
new file mode 100644
index 0000000..ef4ae29
--- /dev/null
+++ b/src/qt3support/other/q3dropsite.cpp
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3dropsite.h"
+
+#ifndef QT_NO_DRAGANDDROP
+
+#include "qwidget.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class Q3DropSite
+ \brief The Q3DropSite class provides nothing and does nothing.
+
+ \compat
+
+ It was used in Qt 1.x to do some drag and drop; that has since been
+ folded into QWidget.
+
+ \sa Q3DragObject, Q3TextDrag, Q3ImageDrag
+*/
+
+/*!
+ Constructs a Q3DropSite to handle events for the widget \a self.
+
+ Pass \c this as the \a self parameter.
+ This enables dropping by calling QWidget::setAcceptDrops(true).
+*/
+Q3DropSite::Q3DropSite(QWidget* self)
+{
+ self->setAcceptDrops(true);
+}
+
+/*!
+ Destroys the drop site.
+*/
+Q3DropSite::~Q3DropSite()
+{
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DRAGANDDROP
diff --git a/src/qt3support/other/q3dropsite.h b/src/qt3support/other/q3dropsite.h
new file mode 100644
index 0000000..211a6a9
--- /dev/null
+++ b/src/qt3support/other/q3dropsite.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3DROPSITE_H
+#define Q3DROPSITE_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3SupportLight)
+
+class QWidget;
+
+class Q_COMPAT_EXPORT Q3DropSite {
+public:
+ Q3DropSite(QWidget* parent);
+ virtual ~Q3DropSite();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDROPSITE_H
diff --git a/src/qt3support/other/q3gridlayout.h b/src/qt3support/other/q3gridlayout.h
new file mode 100644
index 0000000..521920d
--- /dev/null
+++ b/src/qt3support/other/q3gridlayout.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3GRIDLAYOUT_H
+#define Q3GRIDLAYOUT_H
+
+#include <QtGui/qboxlayout.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3SupportLight)
+
+class Q3GridLayout : public QGridLayout
+{
+public:
+ inline explicit Q3GridLayout(QWidget *parent)
+ : QGridLayout(parent) { setMargin(0); setSpacing(0); }
+
+ inline Q3GridLayout(QWidget *parent, int nRows, int nCols = 1, int margin = 0,
+ int spacing = -1, const char *name = 0)
+ : QGridLayout(parent, nRows, nCols, margin, spacing, name) {}
+
+ inline Q3GridLayout(int nRows, int nCols = 1, int spacing = -1, const char *name = 0)
+ : QGridLayout(nRows, nCols, spacing, name) {}
+
+ inline Q3GridLayout(QLayout *parentLayout, int nRows =1, int nCols = 1, int spacing = -1,
+ const char *name = 0)
+ : QGridLayout(parentLayout, nRows, nCols, spacing, name) {}
+
+private:
+ Q_DISABLE_COPY(Q3GridLayout)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // Q3GRIDLAYOUT_H
diff --git a/src/qt3support/other/q3membuf.cpp b/src/qt3support/other/q3membuf.cpp
new file mode 100644
index 0000000..4305bb7
--- /dev/null
+++ b/src/qt3support/other/q3membuf.cpp
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3membuf_p.h"
+
+QT_BEGIN_NAMESPACE
+
+// *******************************************************************
+// QMembuf declaration and implementation
+// *******************************************************************
+
+/* \internal
+ This class implements an efficient buffering of data that is often used by
+ asynchronous IO classes like QSocket, QHttp and QProcess.
+*/
+
+Q3Membuf::Q3Membuf() : _size(0), _index(0)
+{
+}
+
+Q3Membuf::~Q3Membuf()
+{
+ while (!buf.isEmpty())
+ delete buf.takeFirst();
+}
+
+/*! \internal
+ This function consumes \a nbytes bytes of data from the
+ buffer and copies it into \a sink. If \a sink is a 0 pointer
+ the data goes into the nirvana.
+*/
+bool Q3Membuf::consumeBytes(Q_ULONG nbytes, char *sink)
+{
+ if (nbytes <= 0 || (qint64)nbytes > _size)
+ return false;
+ _size -= nbytes;
+ while (!buf.isEmpty()) {
+ QByteArray *a = buf.first();
+ if ((int)(_index + nbytes) >= a->size()) {
+ // Here we skip the whole byte array and get the next later
+ int len = a->size() - _index;
+ if (sink) {
+ memcpy(sink, a->constData()+_index, len);
+ sink += len;
+ }
+ nbytes -= len;
+ buf.removeFirst();
+ delete a;
+ _index = 0;
+ if (nbytes == 0)
+ break;
+ } else {
+ // Here we skip only a part of the first byte array
+ if (sink)
+ memcpy(sink, a->constData()+_index, nbytes);
+ _index += nbytes;
+ break;
+ }
+ }
+ return true;
+}
+
+/*! \internal
+ Scans for any occurrence of '\n' in the buffer. If \a store
+ is not 0 the text up to the first '\n' (or terminating 0) is
+ written to \a store, and a terminating 0 is appended to \a store
+ if necessary. Returns true if a '\n' was found; otherwise returns
+ false.
+*/
+bool Q3Membuf::scanNewline(QByteArray *store)
+{
+ if (_size == 0)
+ return false;
+ int i = 0; // index into 'store'
+ QByteArray *a = 0;
+ char *p;
+ int n;
+ bool retval = false;
+ for (int j = 0; j < buf.size(); ++j) {
+ a = buf.at(j);
+ p = a->data();
+ n = a->size();
+ if (!j) {
+ // first buffer
+ p += _index;
+ n -= _index;
+ }
+ if (store) {
+ while (n-- > 0) {
+ *(store->data()+i) = *p;
+ if (++i == (int)store->size())
+ store->resize(store->size() < 256
+ ? 1024 : store->size()*4);
+ if (*p == '\n') {
+ retval = true;
+ goto end;
+ }
+ p++;
+ }
+ } else {
+ while (n-- > 0) {
+ if(*p == '\n')
+ return true;
+ p++;
+ }
+ }
+ }
+ end:
+ if (store)
+ store->resize(i);
+ return retval;
+}
+
+int Q3Membuf::ungetch(int ch)
+{
+ if (buf.isEmpty() || _index==0) {
+ // we need a new QByteArray
+ QByteArray *ba = new QByteArray;
+ ba->resize(1);
+ buf.prepend(ba);
+ _size++;
+ (*ba)[0] = ch;
+ } else {
+ // we can reuse a place in the buffer
+ QByteArray *ba = buf.first();
+ _index--;
+ _size++;
+ (*ba)[(int)_index] = ch;
+ }
+ return ch;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qt3support/other/q3membuf_p.h b/src/qt3support/other/q3membuf_p.h
new file mode 100644
index 0000000..29a74f9
--- /dev/null
+++ b/src/qt3support/other/q3membuf_p.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3MEMBUF_P_H
+#define Q3MEMBUF_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of a number of Qt sources files. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "QtCore/qbytearray.h"
+#include "QtCore/qlist.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q_COMPAT_EXPORT Q3Membuf
+{
+public:
+ Q3Membuf();
+ ~Q3Membuf();
+
+ void append(QByteArray *ba);
+ void clear();
+
+ bool consumeBytes(Q_ULONG nbytes, char *sink);
+ QByteArray readAll();
+ bool scanNewline(QByteArray *store);
+ bool canReadLine() const;
+
+ int ungetch(int ch);
+
+ qint64 size() const;
+
+private:
+
+ QList<QByteArray *> buf;
+ qint64 _size;
+ qint64 _index;
+};
+
+inline void Q3Membuf::append(QByteArray *ba)
+{ buf.append(ba); _size += ba->size(); }
+
+inline void Q3Membuf::clear()
+{ qDeleteAll(buf); buf.clear(); _size=0; _index=0; }
+
+inline QByteArray Q3Membuf::readAll()
+{ QByteArray ba; ba.resize(_size); consumeBytes(_size,ba.data()); return ba; }
+
+inline bool Q3Membuf::canReadLine() const
+{ return const_cast<Q3Membuf*>(this)->scanNewline(0); }
+
+inline qint64 Q3Membuf::size() const
+{ return _size; }
+
+QT_END_NAMESPACE
+
+#endif // Q3MEMBUF_P_H
diff --git a/src/qt3support/other/q3mimefactory.cpp b/src/qt3support/other/q3mimefactory.cpp
new file mode 100644
index 0000000..3fc3f61
--- /dev/null
+++ b/src/qt3support/other/q3mimefactory.cpp
@@ -0,0 +1,546 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3mimefactory.h"
+
+#ifndef QT_NO_MIMEFACTORY
+
+#include "qmap.h"
+#include "qmime.h"
+#include "qstringlist.h"
+#include "qfileinfo.h"
+#include "qdir.h"
+#include "q3dragobject.h"
+#include "qpixmap.h"
+#include "qimagereader.h"
+#include "q3cleanuphandler.h"
+#include "private/qtextimagehandler_p.h"
+
+QT_BEGIN_NAMESPACE
+
+static Q3MimeSourceFactory* defaultfactory = 0;
+static Q3SingleCleanupHandler<Q3MimeSourceFactory> qmime_cleanup_factory;
+
+class Q3MimeSourceFactoryData {
+public:
+ Q3MimeSourceFactoryData() :
+ last(0)
+ {
+ }
+
+ ~Q3MimeSourceFactoryData()
+ {
+ QMap<QString, QMimeSource*>::Iterator it = stored.begin();
+ while (it != stored.end()) {
+ delete *it;
+ ++it;
+ }
+ delete last;
+ }
+
+ QMap<QString, QMimeSource*> stored;
+ QMap<QString, QString> extensions;
+ QStringList path;
+ QMimeSource* last;
+ QList<Q3MimeSourceFactory*> factories;
+};
+
+static QImage richTextImageLoader(const QString &name, const QString &context)
+{
+ QImage img;
+
+ const QMimeSource *src = Q3MimeSourceFactory::defaultFactory()->data(name, context);
+ if (src && Q3ImageDrag::decode(src, img))
+ return img;
+
+ return QImage();
+}
+
+/*!
+ \class Q3MimeSourceFactory
+ \brief The Q3MimeSourceFactory class is an extensible provider of mime-typed data.
+
+ \compat
+
+ A Q3MimeSourceFactory provides an abstract interface to a
+ collection of information. Each piece of information is
+ represented by a QMimeSource object which can be examined and
+ converted to concrete data types by functions such as
+ Q3ImageDrag::canDecode() and Q3ImageDrag::decode().
+
+ The base Q3MimeSourceFactory can be used in two ways: as an
+ abstraction of a collection of files or as specifically stored
+ data. For it to access files, call setFilePath() before accessing
+ data. For stored data, call setData() for each item (there are
+ also convenience functions, e.g. setText(), setImage() and
+ setPixmap(), that simply call setData() with appropriate
+ parameters).
+
+ The rich text widgets, QTextEdit and QTextBrowser, use
+ Q3MimeSourceFactory to resolve references such as images or links
+ within rich text documents. They either access the default factory
+ (see \l{defaultFactory()}) or their own. Other classes that are
+ capable of displaying rich text (such as QLabel, QWhatsThis or
+ QMessageBox) always use the default factory.
+
+ A factory can also be used as a container to store data associated
+ with a name. This technique is useful whenever rich text contains
+ images that are stored in the program itself, not loaded from the
+ hard disk. Your program may, for example, define some image data
+ as:
+ \snippet doc/src/snippets/code/src_qt3support_other_q3mimefactory.cpp 0
+
+ To be able to use this image within some rich text, for example
+ inside a QLabel, you must create a QImage from the raw data and
+ insert it into the factory with a unique name:
+ \snippet doc/src/snippets/code/src_qt3support_other_q3mimefactory.cpp 1
+
+ Now you can create a rich text QLabel with
+
+ \snippet doc/src/snippets/code/src_qt3support_other_q3mimefactory.cpp 2
+
+ When no longer needed, you can clear the data from the factory:
+
+ \snippet doc/src/snippets/code/src_qt3support_other_q3mimefactory.cpp 3
+*/
+
+
+/*!
+ Constructs a Q3MimeSourceFactory that has no file path and no
+ stored content.
+*/
+Q3MimeSourceFactory::Q3MimeSourceFactory() :
+ d(new Q3MimeSourceFactoryData)
+{
+ addFilePath(QLatin1String(":/qt/q3mimesourcefactory/")); //to get from the resources
+ // add some reasonable defaults
+ setExtensionType(QLatin1String("htm"), "text/html;charset=iso8859-1");
+ setExtensionType(QLatin1String("html"), "text/html;charset=iso8859-1");
+ setExtensionType(QLatin1String("txt"), "text/plain");
+ setExtensionType(QLatin1String("xml"), "text/xml;charset=UTF-8");
+ setExtensionType(QLatin1String("jpg"), "image/jpeg"); // support misspelled jpeg files
+}
+
+/*!
+ Destroys the Q3MimeSourceFactory, deleting all stored content.
+*/
+Q3MimeSourceFactory::~Q3MimeSourceFactory()
+{
+ if (defaultFactory() == this)
+ defaultfactory = 0;
+ delete d;
+}
+
+QMimeSource* Q3MimeSourceFactory::dataInternal(const QString& abs_name, const QMap<QString, QString> &extensions) const
+{
+ QMimeSource* r = 0;
+ QStringList attempted_names(abs_name);
+ QFileInfo fi(abs_name);
+ if (fi.isReadable()) {
+ // get the right mimetype
+ QString e = fi.extension(false);
+ QByteArray mimetype("application/octet-stream");
+ if (extensions.contains(e))
+ mimetype = extensions[e].latin1();
+ if (!QImageReader::imageFormat(abs_name).isEmpty())
+ mimetype = "application/x-qt-image";
+
+ QFile f(abs_name);
+ if (f.open(QIODevice::ReadOnly) && f.size()) {
+ QByteArray ba;
+ ba.resize(f.size());
+ f.readBlock(ba.data(), ba.size());
+ Q3StoredDrag* sr = new Q3StoredDrag(mimetype);
+ sr->setEncodedData(ba);
+ delete d->last;
+ d->last = r = sr;
+ }
+ }
+
+ // we didn't find the mime-source, so ask the default factory for
+ // the mime-source (this one will iterate over all installed ones)
+ //
+ // this looks dangerous, as this dataInternal() function will be
+ // called again when the default factory loops over all installed
+ // factories (including this), but the static bool looping in
+ // data() avoids endless recursions
+ if (!r && this != defaultFactory())
+ r = (QMimeSource*)defaultFactory()->data(abs_name);
+
+ return r;
+}
+
+
+/*!
+ Returns a reference to the data associated with \a abs_name. The
+ return value remains valid only until the next data() or setData()
+ call, so you should immediately decode the result.
+
+ If there is no data associated with \a abs_name in the factory's
+ store, the factory tries to access the local filesystem. If \a
+ abs_name isn't an absolute file name, the factory will search for
+ it in all defined paths (see \l{setFilePath()}).
+
+ The factory understands all the image formats supported by
+ QImageReader. Any other mime types are determined by the file name
+ extension. The default settings are
+ \snippet doc/src/snippets/code/src_qt3support_other_q3mimefactory.cpp 4
+ The effect of these is that file names ending in "txt" will be
+ treated as text encoded in the local encoding; those ending in
+ "xml" will be treated as text encoded in Unicode UTF-8 encoding.
+ The text/html type is treated specially, since the encoding can be
+ specified in the html file itself. "html" or "htm" will be treated
+ as text encoded in the encoding specified by the html meta tag, if
+ none could be found, the charset of the mime type will be used.
+ The text subtype ("html", "plain", or "xml") does not affect the
+ factory, but users of the factory may behave differently. We
+ recommend creating "xml" files where practical. These files can be
+ viewed regardless of the runtime encoding and can encode any
+ Unicode characters without resorting to encoding definitions
+ inside the file.
+
+ Any file data that is not recognized will be retrieved as a
+ QMimeSource providing the "application/octet-stream" mime type,
+ meaning uninterpreted binary data.
+
+ You can add further extensions or change existing ones with
+ subsequent calls to setExtensionType(). If the extension mechanism
+ is not sufficient for your problem domain, you can inherit
+ Q3MimeSourceFactory and reimplement this function to perform some
+ more specialized mime-type detection. The same applies if you want
+ to use the mime source factory to access URL referenced data over
+ a network.
+*/
+const QMimeSource *Q3MimeSourceFactory::data(const QString& abs_name) const
+{
+ if (d->stored.contains(abs_name))
+ return d->stored[abs_name];
+
+ const QMimeSource *r = 0;
+ if (abs_name.isEmpty())
+ return r;
+ QStringList::Iterator it;
+ if (abs_name[0] == QLatin1Char('/')
+#ifdef Q_WS_WIN
+ || (abs_name[0].isLetter() && abs_name[1] == QLatin1Char(':')) || abs_name.startsWith(QLatin1String("\\\\"))
+#endif
+ )
+ {
+ // handle absolute file names directly
+ r = dataInternal(abs_name, d->extensions);
+ }
+ else { // check list of paths
+ for (it = d->path.begin(); !r && it != d->path.end(); ++it) {
+ QString filename = *it;
+ if (filename[(int)filename.length()-1] != QLatin1Char('/'))
+ filename += QLatin1Char('/');
+ filename += abs_name;
+ r = dataInternal(filename, d->extensions);
+ }
+ }
+
+ static bool looping = false;
+ if (!r && this == defaultFactory()) {
+ // we found no mime-source and we are the default factory, so
+ // we know all the other installed mime-source factories, so
+ // ask them
+ if (!looping) {
+ // to avoid endless recustions, don't enter the loop below
+ // if data() got called from within the loop below
+ looping = true;
+ for (int i = 0; i < d->factories.size(); ++i) {
+ const Q3MimeSourceFactory *f = d->factories.at(i);
+ if (f == this)
+ continue;
+ r = static_cast<const QMimeSource *>(f->data(abs_name));
+ if (r) {
+ looping = false;
+ return r;
+ }
+ }
+ looping = false;
+ }
+ } else if (!r) {
+ // we are not the default mime-source factory, so ask the
+ // default one for the mime-source, as this one will loop over
+ // all installed mime-source factories and ask these
+ r = static_cast<const QMimeSource *>(defaultFactory()->data(abs_name));
+ }
+ return r;
+}
+
+/*!
+ \fn void Q3MimeSourceFactory::setFilePath(const QStringList &path)
+ \fn void Q3MimeSourceFactory::setFilePath(const QString &path)
+
+ Sets the list of directories that will be searched when named data
+ is requested to those given in the string list \a path.
+
+ \sa filePath()
+*/
+void Q3MimeSourceFactory::setFilePath(const QStringList& path)
+{
+ d->path = path;
+}
+
+/*!
+ Returns the currently set search paths.
+*/
+QStringList Q3MimeSourceFactory::filePath() const
+{
+ return d->path;
+}
+
+/*!
+ Adds another search path, \a p to the existing search paths.
+
+ \sa setFilePath()
+*/
+void Q3MimeSourceFactory::addFilePath(const QString& p)
+{
+ d->path += p;
+}
+
+/*!
+ Sets the mime-type to be associated with the file name extension,
+ \a ext to \a mimetype. This determines the mime-type for files
+ found via the paths set by setFilePath().
+*/
+void Q3MimeSourceFactory::setExtensionType(const QString& ext, const char* mimetype)
+{
+ d->extensions.insert(ext, QLatin1String(mimetype));
+}
+
+/*!
+ Converts the absolute or relative data item name \a
+ abs_or_rel_name to an absolute name, interpreted within the
+ context (path) of the data item named \a context (this must be an
+ absolute name).
+*/
+QString Q3MimeSourceFactory::makeAbsolute(const QString& abs_or_rel_name, const QString& context) const
+{
+ if (context.isNull() ||
+ !(context[0] == QLatin1Char('/')
+#ifdef Q_WS_WIN
+ || (context[0].isLetter() && context[1] == QLatin1Char(':'))
+#endif
+ ))
+ return abs_or_rel_name;
+ if (abs_or_rel_name.isEmpty())
+ return context;
+ QFileInfo c(context);
+ if (!c.isDir()) {
+ QFileInfo r(c.dir(true), abs_or_rel_name);
+ return r.absFilePath();
+ } else {
+ QDir d(context);
+ QFileInfo r(d, abs_or_rel_name);
+ return r.absFilePath();
+ }
+}
+
+/*!
+ \overload
+ A convenience function. See data(const QString& abs_name). The
+ file name is given in \a abs_or_rel_name and the path is in \a
+ context.
+*/
+const QMimeSource* Q3MimeSourceFactory::data(const QString& abs_or_rel_name, const QString& context) const
+{
+ const QMimeSource* r = data(makeAbsolute(abs_or_rel_name,context));
+ if (!r && !d->path.isEmpty())
+ r = data(abs_or_rel_name);
+ return r;
+}
+
+
+/*!
+ Sets \a text to be the data item associated with the absolute name
+ \a abs_name.
+
+ Equivalent to setData(abs_name, new Q3TextDrag(text)).
+*/
+void Q3MimeSourceFactory::setText(const QString& abs_name, const QString& text)
+{
+ setData(abs_name, new Q3TextDrag(text));
+}
+
+/*!
+ Sets \a image to be the data item associated with the absolute
+ name \a abs_name.
+
+ Equivalent to setData(abs_name, new Q3ImageDrag(image)).
+*/
+void Q3MimeSourceFactory::setImage(const QString& abs_name, const QImage& image)
+{
+ setData(abs_name, new Q3ImageDrag(image));
+}
+
+/*!
+ Sets \a pixmap to be the data item associated with the absolute
+ name \a abs_name.
+*/
+void Q3MimeSourceFactory::setPixmap(const QString& abs_name, const QPixmap& pixmap)
+{
+ setData(abs_name, new Q3ImageDrag(pixmap.convertToImage()));
+}
+
+/*!
+ Sets \a data to be the data item associated with
+ the absolute name \a abs_name. Note that the ownership of \a data is
+ transferred to the factory: do not delete or access the pointer after
+ passing it to this function.
+
+ Passing 0 for data removes previously stored data.
+*/
+void Q3MimeSourceFactory::setData(const QString& abs_name, QMimeSource* data)
+{
+ if (d->stored.contains(abs_name))
+ delete d->stored[abs_name];
+ d->stored.insert(abs_name,data);
+}
+
+
+/*!
+ Returns the application-wide default mime source factory. This
+ factory is used by rich text rendering classes such as
+ QSimpleRichText, QWhatsThis and QMessageBox to resolve named
+ references within rich text documents. It serves also as the
+ initial factory for the more complex render widgets, QTextEdit and
+ QTextBrowser.
+
+ \sa setDefaultFactory()
+*/
+Q3MimeSourceFactory* Q3MimeSourceFactory::defaultFactory()
+{
+ if (!defaultfactory)
+ {
+ defaultfactory = new Q3MimeSourceFactory();
+ qmime_cleanup_factory.set(&defaultfactory);
+ QTextImageHandler::externalLoader = richTextImageLoader;
+ }
+ return defaultfactory;
+}
+
+/*!
+ Sets the default \a factory, destroying any previously set mime
+ source provider. The ownership of the factory is transferred to
+ Qt.
+
+ \sa defaultFactory()
+*/
+void Q3MimeSourceFactory::setDefaultFactory(Q3MimeSourceFactory* factory)
+{
+ if (!defaultfactory)
+ qmime_cleanup_factory.set(&defaultfactory);
+ else if (defaultfactory != factory)
+ delete defaultfactory;
+ defaultfactory = factory;
+}
+
+/*!
+ Sets the defaultFactory() to 0 and returns the previous one.
+*/
+
+Q3MimeSourceFactory* Q3MimeSourceFactory::takeDefaultFactory()
+{
+ Q3MimeSourceFactory *f = defaultfactory;
+ defaultfactory = 0;
+ return f;
+}
+
+/*!
+ Adds the Q3MimeSourceFactory \a f to the list of available
+ mimesource factories. If the defaultFactory() can't resolve a
+ data() it iterates over the list of installed mimesource factories
+ until the data can be resolved.
+
+ \sa removeFactory()
+*/
+
+void Q3MimeSourceFactory::addFactory(Q3MimeSourceFactory *f)
+{
+ Q3MimeSourceFactory::defaultFactory()->d->factories.append(f);
+}
+
+/*!
+ Removes the mimesource factory \a f from the list of available
+ mimesource factories.
+
+ \sa addFactory()
+*/
+
+void Q3MimeSourceFactory::removeFactory(Q3MimeSourceFactory *f)
+{
+ Q3MimeSourceFactory::defaultFactory()->d->factories.removeAll(f);
+}
+
+QPixmap qPixmapFromMimeSource(const QString &abs_name)
+{
+ const QMimeSource *m = Q3MimeSourceFactory::defaultFactory()->data(abs_name);
+ if (!m) {
+ if (QFile::exists(abs_name))
+ return QPixmap(abs_name);
+ if (!abs_name.isEmpty())
+ qWarning("QPixmap::fromMimeSource: Cannot find pixmap \"%s\" in the mime source factory",
+ abs_name.latin1());
+ return QPixmap();
+ }
+ QPixmap pix;
+ Q3ImageDrag::decode(m, pix);
+ return pix;
+}
+
+QImage qImageFromMimeSource(const QString &abs_name)
+{
+ const QMimeSource *m = Q3MimeSourceFactory::defaultFactory()->data(abs_name);
+ if (!m) {
+ qWarning("QImage::fromMimeSource: Cannot find image \"%s\" in the mime source factory", abs_name.latin1());
+ return QImage();
+ }
+ QImage img;
+ Q3ImageDrag::decode(m, img);
+ return img;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_MIMEFACTORY
diff --git a/src/qt3support/other/q3mimefactory.h b/src/qt3support/other/q3mimefactory.h
new file mode 100644
index 0000000..e21f63b
--- /dev/null
+++ b/src/qt3support/other/q3mimefactory.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3MIMEFACTORY_H
+#define Q3MIMEFACTORY_H
+
+#include <QtGui/qwindowdefs.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qmap.h>
+#include <QtGui/qpixmap.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3SupportLight)
+
+#ifndef QT_NO_MIMEFACTORY
+
+class QStringList;
+class QMimeSource;
+class Q3MimeSourceFactoryData;
+
+class Q_COMPAT_EXPORT Q3MimeSourceFactory {
+public:
+ Q3MimeSourceFactory();
+ virtual ~Q3MimeSourceFactory();
+
+ static Q3MimeSourceFactory* defaultFactory();
+ static void setDefaultFactory(Q3MimeSourceFactory*);
+ static Q3MimeSourceFactory* takeDefaultFactory();
+ static void addFactory(Q3MimeSourceFactory *f);
+ static void removeFactory(Q3MimeSourceFactory *f);
+
+ virtual const QMimeSource* data(const QString& abs_name) const;
+ virtual QString makeAbsolute(const QString& abs_or_rel_name, const QString& context) const;
+ const QMimeSource* data(const QString& abs_or_rel_name, const QString& context) const;
+
+ virtual void setText(const QString& abs_name, const QString& text);
+ virtual void setImage(const QString& abs_name, const QImage& im);
+ virtual void setPixmap(const QString& abs_name, const QPixmap& pm);
+ virtual void setData(const QString& abs_name, QMimeSource* data);
+ virtual void setFilePath(const QStringList&);
+ inline void setFilePath(const QString &path) { setFilePath(QStringList(path)); }
+ virtual QStringList filePath() const;
+ void addFilePath(const QString&);
+ virtual void setExtensionType(const QString& ext, const char* mimetype);
+
+private:
+ QMimeSource *dataInternal(const QString& abs_name, const QMap<QString, QString> &extensions) const;
+ Q3MimeSourceFactoryData* d;
+};
+
+Q_COMPAT_EXPORT QPixmap qPixmapFromMimeSource(const QString &abs_name);
+
+Q_COMPAT_EXPORT QImage qImageFromMimeSource(const QString &abs_name);
+
+#endif // QT_NO_MIMEFACTORY
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // Q3MIMEFACTORY_H
diff --git a/src/qt3support/other/q3polygonscanner.cpp b/src/qt3support/other/q3polygonscanner.cpp
new file mode 100644
index 0000000..da1af1e
--- /dev/null
+++ b/src/qt3support/other/q3polygonscanner.cpp
@@ -0,0 +1,939 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3polygonscanner.h"
+#include "q3pointarray.h"
+#include <stdlib.h>
+
+QT_BEGIN_NAMESPACE
+
+// Based on Xserver code miFillGeneralPoly...
+/*
+ *
+ * Written by Brian Kelleher; Oct. 1985
+ *
+ * Routine to fill a polygon. Two fill rules are
+ * supported: frWINDING and frEVENODD.
+ *
+ * See fillpoly.h for a complete description of the algorithm.
+ */
+
+/*
+ * These are the data structures needed to scan
+ * convert regions. Two different scan conversion
+ * methods are available -- the even-odd method, and
+ * the winding number method.
+ * The even-odd rule states that a point is inside
+ * the polygon if a ray drawn from that point in any
+ * direction will pass through an odd number of
+ * path segments.
+ * By the winding number rule, a point is decided
+ * to be inside the polygon if a ray drawn from that
+ * point in any direction passes through a different
+ * number of clockwise and counterclockwise path
+ * segments.
+ *
+ * These data structures are adapted somewhat from
+ * the algorithm in (Foley/Van Dam) for scan converting
+ * polygons.
+ * The basic algorithm is to start at the top (smallest y)
+ * of the polygon, stepping down to the bottom of
+ * the polygon by incrementing the y coordinate. We
+ * keep a list of edges which the current scanline crosses,
+ * sorted by x. This list is called the Active Edge Table (AET)
+ * As we change the y-coordinate, we update each entry in
+ * in the active edge table to reflect the edges new xcoord.
+ * This list must be sorted at each scanline in case
+ * two edges intersect.
+ * We also keep a data structure known as the Edge Table (ET),
+ * which keeps track of all the edges which the current
+ * scanline has not yet reached. The ET is basically a
+ * list of ScanLineList structures containing a list of
+ * edges which are entered at a given scanline. There is one
+ * ScanLineList per scanline at which an edge is entered.
+ * When we enter a new edge, we move it from the ET to the AET.
+ *
+ * From the AET, we can implement the even-odd rule as in
+ * (Foley/Van Dam).
+ * The winding number rule is a little trickier. We also
+ * keep the EdgeTableEntries in the AET linked by the
+ * nextWETE (winding EdgeTableEntry) link. This allows
+ * the edges to be linked just as before for updating
+ * purposes, but only uses the edges linked by the nextWETE
+ * link as edges representing spans of the polygon to
+ * drawn (as with the even-odd rule).
+ */
+
+/* $XConsortium: miscanfill.h,v 1.5 94/04/17 20:27:50 dpw Exp $ */
+/*
+
+Copyright (c) 1987 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the X Consortium.
+
+*/
+
+
+/*
+ * scanfill.h
+ *
+ * Written by Brian Kelleher; Jan 1985
+ *
+ * This file contains a few macros to help track
+ * the edge of a filled object. The object is assumed
+ * to be filled in scanline order, and thus the
+ * algorithm used is an extension of Bresenham's line
+ * drawing algorithm which assumes that y is always the
+ * major axis.
+ * Since these pieces of code are the same for any filled shape,
+ * it is more convenient to gather the library in one
+ * place, but since these pieces of code are also in
+ * the inner loops of output primitives, procedure call
+ * overhead is out of the question.
+ * See the author for a derivation if needed.
+ */
+
+/*
+ * In scan converting polygons, we want to choose those pixels
+ * which are inside the polygon. Thus, we add .5 to the starting
+ * x coordinate for both left and right edges. Now we choose the
+ * first pixel which is inside the pgon for the left edge and the
+ * first pixel which is outside the pgon for the right edge.
+ * Draw the left pixel, but not the right.
+ *
+ * How to add .5 to the starting x coordinate:
+ * If the edge is moving to the right, then subtract dy from the
+ * error term from the general form of the algorithm.
+ * If the edge is moving to the left, then add dy to the error term.
+ *
+ * The reason for the difference between edges moving to the left
+ * and edges moving to the right is simple: If an edge is moving
+ * to the right, then we want the algorithm to flip immediately.
+ * If it is moving to the left, then we don't want it to flip until
+ * we traverse an entire pixel.
+ */
+#define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
+ int dx; /* local storage */ \
+\
+ /* \
+ * if the edge is horizontal, then it is ignored \
+ * and assumed not to be processed. Otherwise, do this stuff. \
+ */ \
+ if ((dy) != 0) { \
+ xStart = (x1); \
+ dx = (x2) - xStart; \
+ if (dx < 0) { \
+ m = dx / (dy); \
+ m1 = m - 1; \
+ incr1 = -2 * dx + 2 * (dy) * m1; \
+ incr2 = -2 * dx + 2 * (dy) * m; \
+ d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
+ } else { \
+ m = dx / (dy); \
+ m1 = m + 1; \
+ incr1 = 2 * dx - 2 * (dy) * m1; \
+ incr2 = 2 * dx - 2 * (dy) * m; \
+ d = -2 * m * (dy) + 2 * dx; \
+ } \
+ } \
+}
+
+#define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
+ if (m1 > 0) { \
+ if (d > 0) { \
+ minval += m1; \
+ d += incr1; \
+ } \
+ else { \
+ minval += m; \
+ d += incr2; \
+ } \
+ } else {\
+ if (d >= 0) { \
+ minval += m1; \
+ d += incr1; \
+ } \
+ else { \
+ minval += m; \
+ d += incr2; \
+ } \
+ } \
+}
+
+
+/*
+ * This structure contains all of the information needed
+ * to run the bresenham algorithm.
+ * The variables may be hardcoded into the declarations
+ * instead of using this structure to make use of
+ * register declarations.
+ */
+typedef struct {
+ int minor; /* minor axis */
+ int d; /* decision variable */
+ int m, m1; /* slope and slope+1 */
+ int incr1, incr2; /* error increments */
+} BRESINFO;
+
+
+#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
+ BRESINITPGON(dmaj, min1, min2, bres.minor, bres.d, \
+ bres.m, bres.m1, bres.incr1, bres.incr2)
+
+#define BRESINCRPGONSTRUCT(bres) \
+ BRESINCRPGON(bres.d, bres.minor, bres.m, bres.m1, bres.incr1, bres.incr2)
+
+
+typedef struct _EdgeTableEntry {
+ int ymax; /* ycoord at which we exit this edge. */
+ BRESINFO bres; /* Bresenham info to run the edge */
+ struct _EdgeTableEntry *next; /* next in the list */
+ struct _EdgeTableEntry *back; /* for insertion sort */
+ struct _EdgeTableEntry *nextWETE; /* for winding num rule */
+ int ClockWise; /* flag for winding number rule */
+} EdgeTableEntry;
+
+
+typedef struct _ScanLineList{
+ int scanline; /* the scanline represented */
+ EdgeTableEntry *edgelist; /* header node */
+ struct _ScanLineList *next; /* next in the list */
+} ScanLineList;
+
+
+typedef struct {
+ int ymax; /* ymax for the polygon */
+ int ymin; /* ymin for the polygon */
+ ScanLineList scanlines; /* header node */
+} EdgeTable;
+
+
+/*
+ * Here is a struct to help with storage allocation
+ * so we can allocate a big chunk at a time, and then take
+ * pieces from this heap when we need to.
+ */
+#define SLLSPERBLOCK 25
+
+typedef struct _ScanLineListBlock {
+ ScanLineList SLLs[SLLSPERBLOCK];
+ struct _ScanLineListBlock *next;
+} ScanLineListBlock;
+
+/*
+ * number of points to buffer before sending them off
+ * to scanlines() : Must be an even number
+ */
+#define NUMPTSTOBUFFER 200
+
+/*
+ *
+ * a few macros for the inner loops of the fill code where
+ * performance considerations don't allow a procedure call.
+ *
+ * Evaluate the given edge at the given scanline.
+ * If the edge has expired, then we leave it and fix up
+ * the active edge table; otherwise, we increment the
+ * x value to be ready for the next scanline.
+ * The winding number rule is in effect, so we must notify
+ * the caller when the edge has been removed so he
+ * can reorder the Winding Active Edge Table.
+ */
+#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
+ if (pAET->ymax == y) { /* leaving this edge */ \
+ pPrevAET->next = pAET->next; \
+ pAET = pPrevAET->next; \
+ fixWAET = 1; \
+ if (pAET) \
+ pAET->back = pPrevAET; \
+ } \
+ else { \
+ BRESINCRPGONSTRUCT(pAET->bres); \
+ pPrevAET = pAET; \
+ pAET = pAET->next; \
+ } \
+}
+
+
+/*
+ * Evaluate the given edge at the given scanline.
+ * If the edge has expired, then we leave it and fix up
+ * the active edge table; otherwise, we increment the
+ * x value to be ready for the next scanline.
+ * The even-odd rule is in effect.
+ */
+#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
+ if (pAET->ymax == y) { /* leaving this edge */ \
+ pPrevAET->next = pAET->next; \
+ pAET = pPrevAET->next; \
+ if (pAET) \
+ pAET->back = pPrevAET; \
+ } \
+ else { \
+ BRESINCRPGONSTRUCT(pAET->bres) \
+ pPrevAET = pAET; \
+ pAET = pAET->next; \
+ } \
+}
+
+/***********************************************************
+
+Copyright (c) 1987 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#define MAXINT 0x7fffffff
+#define MININT -MAXINT
+
+/*
+ * fillUtils.c
+ *
+ * Written by Brian Kelleher; Oct. 1985
+ *
+ * This module contains all of the utility functions
+ * needed to scan convert a polygon.
+ *
+ */
+/*
+ * InsertEdgeInET
+ *
+ * Insert the given edge into the edge table.
+ * First we must find the correct bucket in the
+ * Edge table, then find the right slot in the
+ * bucket. Finally, we can insert it.
+ *
+ */
+static bool
+miInsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE,
+ int scanline, ScanLineListBlock **SLLBlock, int *iSLLBlock)
+{
+ register EdgeTableEntry *start, *prev;
+ register ScanLineList *pSLL, *pPrevSLL;
+ ScanLineListBlock *tmpSLLBlock;
+
+ /*
+ * find the right bucket to put the edge into
+ */
+ pPrevSLL = &ET->scanlines;
+ pSLL = pPrevSLL->next;
+ while (pSLL && (pSLL->scanline < scanline))
+ {
+ pPrevSLL = pSLL;
+ pSLL = pSLL->next;
+ }
+
+ /*
+ * reassign pSLL (pointer to ScanLineList) if necessary
+ */
+ if ((!pSLL) || (pSLL->scanline > scanline))
+ {
+ if (*iSLLBlock > SLLSPERBLOCK-1)
+ {
+ tmpSLLBlock =
+ (ScanLineListBlock *)malloc(sizeof(ScanLineListBlock));
+ if (!tmpSLLBlock)
+ return false;
+ (*SLLBlock)->next = tmpSLLBlock;
+ tmpSLLBlock->next = 0;
+ *SLLBlock = tmpSLLBlock;
+ *iSLLBlock = 0;
+ }
+ pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
+
+ pSLL->next = pPrevSLL->next;
+ pSLL->edgelist = 0;
+ pPrevSLL->next = pSLL;
+ }
+ pSLL->scanline = scanline;
+
+ /*
+ * now insert the edge in the right bucket
+ */
+ prev = 0;
+ start = pSLL->edgelist;
+ while (start && (start->bres.minor < ETE->bres.minor))
+ {
+ prev = start;
+ start = start->next;
+ }
+ ETE->next = start;
+
+ if (prev)
+ prev->next = ETE;
+ else
+ pSLL->edgelist = ETE;
+ return true;
+}
+
+/*
+ * CreateEdgeTable
+ *
+ * This routine creates the edge table for
+ * scan converting polygons.
+ * The Edge Table (ET) looks like:
+ *
+ * EdgeTable
+ * --------
+ * | ymax | ScanLineLists
+ * |scanline|-->------------>-------------->...
+ * -------- |scanline| |scanline|
+ * |edgelist| |edgelist|
+ * --------- ---------
+ * | |
+ * | |
+ * V V
+ * list of ETEs list of ETEs
+ *
+ * where ETE is an EdgeTableEntry data structure,
+ * and there is one ScanLineList per scanline at
+ * which an edge is initially entered.
+ *
+ */
+
+typedef struct {
+#if defined(Q_OS_MAC)
+ int y, x;
+#else
+ int x, y;
+#endif
+
+} DDXPointRec, *DDXPointPtr;
+
+/*
+ * Clean up our act.
+ */
+static void
+miFreeStorage(ScanLineListBlock *pSLLBlock)
+{
+ register ScanLineListBlock *tmpSLLBlock;
+
+ while (pSLLBlock)
+ {
+ tmpSLLBlock = pSLLBlock->next;
+ free(pSLLBlock);
+ pSLLBlock = tmpSLLBlock;
+ }
+}
+
+static bool
+miCreateETandAET(int count, DDXPointPtr pts, EdgeTable *ET,
+ EdgeTableEntry *AET, EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock)
+{
+ register DDXPointPtr top, bottom;
+ register DDXPointPtr PrevPt, CurrPt;
+ int iSLLBlock = 0;
+
+ int dy;
+
+ if (count < 2) return true;
+
+ /*
+ * initialize the Active Edge Table
+ */
+ AET->next = 0;
+ AET->back = 0;
+ AET->nextWETE = 0;
+ AET->bres.minor = MININT;
+
+ /*
+ * initialize the Edge Table.
+ */
+ ET->scanlines.next = 0;
+ ET->ymax = MININT;
+ ET->ymin = MAXINT;
+ pSLLBlock->next = 0;
+
+ PrevPt = &pts[count-1];
+
+ /*
+ * for each vertex in the array of points.
+ * In this loop we are dealing with two vertices at
+ * a time -- these make up one edge of the polygon.
+ */
+ while (count--)
+ {
+ CurrPt = pts++;
+
+ /*
+ * find out which point is above and which is below.
+ */
+ if (PrevPt->y > CurrPt->y)
+ {
+ bottom = PrevPt, top = CurrPt;
+ pETEs->ClockWise = 0;
+ }
+ else
+ {
+ bottom = CurrPt, top = PrevPt;
+ pETEs->ClockWise = 1;
+ }
+
+ /*
+ * don't add horizontal edges to the Edge table.
+ */
+ if (bottom->y != top->y)
+ {
+ pETEs->ymax = bottom->y-1; /* -1 so we don't get last scanline */
+
+ /*
+ * initialize integer edge algorithm
+ */
+ dy = bottom->y - top->y;
+ BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres)
+
+ if (!miInsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock))
+ {
+ miFreeStorage(pSLLBlock->next);
+ return false;
+ }
+
+ ET->ymax = qMax(ET->ymax, PrevPt->y);
+ ET->ymin = qMin(ET->ymin, PrevPt->y);
+ pETEs++;
+ }
+
+ PrevPt = CurrPt;
+ }
+ return true;
+}
+
+/*
+ * loadAET
+ *
+ * This routine moves EdgeTableEntries from the
+ * EdgeTable into the Active Edge Table,
+ * leaving them sorted by smaller x coordinate.
+ *
+ */
+
+static void
+miloadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs)
+{
+ register EdgeTableEntry *pPrevAET;
+ register EdgeTableEntry *tmp;
+
+ pPrevAET = AET;
+ AET = AET->next;
+ while (ETEs)
+ {
+ while (AET && (AET->bres.minor < ETEs->bres.minor))
+ {
+ pPrevAET = AET;
+ AET = AET->next;
+ }
+ tmp = ETEs->next;
+ ETEs->next = AET;
+ if (AET)
+ AET->back = ETEs;
+ ETEs->back = pPrevAET;
+ pPrevAET->next = ETEs;
+ pPrevAET = ETEs;
+
+ ETEs = tmp;
+ }
+}
+
+/*
+ * computeWAET
+ *
+ * This routine links the AET by the
+ * nextWETE (winding EdgeTableEntry) link for
+ * use by the winding number rule. The final
+ * Active Edge Table (AET) might look something
+ * like:
+ *
+ * AET
+ * ---------- --------- ---------
+ * |ymax | |ymax | |ymax |
+ * | ... | |... | |... |
+ * |next |->|next |->|next |->...
+ * |nextWETE| |nextWETE| |nextWETE|
+ * --------- --------- ^--------
+ * | | |
+ * V-------------------> V---> ...
+ *
+ */
+static void
+micomputeWAET(EdgeTableEntry *AET)
+{
+ register EdgeTableEntry *pWETE;
+ register int inside = 1;
+ register int isInside = 0;
+
+ AET->nextWETE = 0;
+ pWETE = AET;
+ AET = AET->next;
+ while (AET)
+ {
+ if (AET->ClockWise)
+ isInside++;
+ else
+ isInside--;
+
+ if ((!inside && !isInside) ||
+ (inside && isInside))
+ {
+ pWETE->nextWETE = AET;
+ pWETE = AET;
+ inside = !inside;
+ }
+ AET = AET->next;
+ }
+ pWETE->nextWETE = 0;
+}
+
+/*
+ * InsertionSort
+ *
+ * Just a simple insertion sort using
+ * pointers and back pointers to sort the Active
+ * Edge Table.
+ *
+ */
+
+static int
+miInsertionSort(EdgeTableEntry *AET)
+{
+ register EdgeTableEntry *pETEchase;
+ register EdgeTableEntry *pETEinsert;
+ register EdgeTableEntry *pETEchaseBackTMP;
+ register int changed = 0;
+
+ AET = AET->next;
+ while (AET)
+ {
+ pETEinsert = AET;
+ pETEchase = AET;
+ while (pETEchase->back->bres.minor > AET->bres.minor)
+ pETEchase = pETEchase->back;
+
+ AET = AET->next;
+ if (pETEchase != pETEinsert)
+ {
+ pETEchaseBackTMP = pETEchase->back;
+ pETEinsert->back->next = AET;
+ if (AET)
+ AET->back = pETEinsert->back;
+ pETEinsert->next = pETEchase;
+ pETEchase->back->next = pETEinsert;
+ pETEchase->back = pETEinsert;
+ pETEinsert->back = pETEchaseBackTMP;
+ changed = 1;
+ }
+ }
+ return changed;
+}
+
+/*!
+ \overload
+*/
+void Q3PolygonScanner::scan(const Q3PointArray& pa, bool winding, int index, int npoints)
+{
+ scan(pa, winding, index, npoints, true);
+}
+
+/*!
+ \overload
+
+ If \a stitchable is false, the right and bottom edges of the
+ polygon are included. This causes adjacent polygons to overlap.
+*/
+void Q3PolygonScanner::scan(const Q3PointArray& pa, bool winding, int index, int npoints, bool stitchable)
+{
+ scan(pa, winding, index, npoints,
+ stitchable ? Edge(Left+Top) : Edge(Left+Right+Top+Bottom));
+}
+
+/*!
+ Calls processSpans() for all scanlines of the polygon defined by
+ \a npoints starting at \a index in \a pa.
+
+ If \a winding is true, the Winding algorithm rather than the
+ Odd-Even rule is used.
+
+ The \a edges is any bitwise combination of:
+ \list
+ \i Q3PolygonScanner::Left
+ \i Q3PolygonScanner::Right
+ \i Q3PolygonScanner::Top
+ \i Q3PolygonScanner::Bottom
+ \endlist
+ \a edges determines which edges are included.
+
+ \warning The edges feature does not work properly.
+
+*/
+void Q3PolygonScanner::scan(const Q3PointArray& pa, bool winding, int index, int npoints, Edge edges)
+{
+
+
+ DDXPointPtr ptsIn = (DDXPointPtr)pa.data();
+ ptsIn += index;
+ register EdgeTableEntry *pAET; /* the Active Edge Table */
+ register int y; /* the current scanline */
+ register int nPts = 0; /* number of pts in buffer */
+ register EdgeTableEntry *pWETE; /* Winding Edge Table */
+ register ScanLineList *pSLL; /* Current ScanLineList */
+ register DDXPointPtr ptsOut; /* ptr to output buffers */
+ int *width;
+ DDXPointRec FirstPoint[NUMPTSTOBUFFER]; /* the output buffers */
+ int FirstWidth[NUMPTSTOBUFFER];
+ EdgeTableEntry *pPrevAET; /* previous AET entry */
+ EdgeTable ET; /* Edge Table header node */
+ EdgeTableEntry AET; /* Active ET header node */
+ EdgeTableEntry *pETEs; /* Edge Table Entries buff */
+ ScanLineListBlock SLLBlock; /* header for ScanLineList */
+ int fixWAET = 0;
+ int edge_l = (edges & Left) ? 1 : 0;
+ int edge_r = (edges & Right) ? 1 : 0;
+ int edge_t = 1; //#### (edges & Top) ? 1 : 0;
+ int edge_b = (edges & Bottom) ? 1 : 0;
+
+ if (npoints == -1)
+ npoints = pa.size();
+
+ if (npoints < 3)
+ return;
+
+ if(!(pETEs = (EdgeTableEntry *)
+ malloc(sizeof(EdgeTableEntry) * npoints)))
+ return;
+ ptsOut = FirstPoint;
+ width = FirstWidth;
+ if (!miCreateETandAET(npoints, ptsIn, &ET, &AET, pETEs, &SLLBlock))
+ {
+ free(pETEs);
+ return;
+ }
+ pSLL = ET.scanlines.next;
+
+ if (!winding)
+ {
+ /*
+ * for each scanline
+ */
+ for (y = ET.ymin+1-edge_t; y < ET.ymax+edge_b; y++)
+ {
+ /*
+ * Add a new edge to the active edge table when we
+ * get to the next edge.
+ */
+ if (pSLL && y == pSLL->scanline)
+ {
+ miloadAET(&AET, pSLL->edgelist);
+ pSLL = pSLL->next;
+ }
+ pPrevAET = &AET;
+ pAET = AET.next;
+
+ /*
+ * for each active edge
+ */
+ while (pAET)
+ {
+ ptsOut->x = pAET->bres.minor + 1 - edge_l;
+ ptsOut++->y = y;
+ *width++ = pAET->next->bres.minor - pAET->bres.minor
+ - 1 + edge_l + edge_r;
+ nPts++;
+
+ /*
+ * send out the buffer when its full
+ */
+ if (nPts == NUMPTSTOBUFFER)
+ {
+ processSpans(nPts, (QPoint*)FirstPoint, FirstWidth);
+ ptsOut = FirstPoint;
+ width = FirstWidth;
+ nPts = 0;
+ }
+ EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
+ EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
+ }
+ miInsertionSort(&AET);
+ }
+ }
+ else /* default to WindingNumber */
+ {
+ /*
+ * for each scanline
+ */
+ for (y = ET.ymin+1-edge_t; y < ET.ymax+edge_b; y++)
+ {
+ /*
+ * Add a new edge to the active edge table when we
+ * get to the next edge.
+ */
+ if (pSLL && y == pSLL->scanline)
+ {
+ miloadAET(&AET, pSLL->edgelist);
+ micomputeWAET(&AET);
+ pSLL = pSLL->next;
+ }
+ pPrevAET = &AET;
+ pAET = AET.next;
+ pWETE = pAET;
+
+ /*
+ * for each active edge
+ */
+ while (pAET)
+ {
+ /*
+ * if the next edge in the active edge table is
+ * also the next edge in the winding active edge
+ * table.
+ */
+ if (pWETE == pAET)
+ {
+ ptsOut->x = pAET->bres.minor + 1 - edge_l;
+ ptsOut++->y = y;
+ *width++ = pAET->nextWETE->bres.minor - pAET->bres.minor - 1 + edge_l + edge_r;
+ nPts++;
+
+ /*
+ * send out the buffer
+ */
+ if (nPts == NUMPTSTOBUFFER)
+ {
+ processSpans(nPts, (QPoint*)FirstPoint, FirstWidth);
+ ptsOut = FirstPoint;
+ width = FirstWidth;
+ nPts = 0;
+ }
+
+ pWETE = pWETE->nextWETE;
+ while (pWETE != pAET) {
+ EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET)
+ }
+ pWETE = pWETE->nextWETE;
+ }
+ EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET)
+ }
+
+ /*
+ * reevaluate the Winding active edge table if we
+ * just had to resort it or if we just exited an edge.
+ */
+ if (miInsertionSort(&AET) || fixWAET)
+ {
+ micomputeWAET(&AET);
+ fixWAET = 0;
+ }
+ }
+ }
+
+ /*
+ * Get any spans that we missed by buffering
+ */
+
+
+ processSpans(nPts, (QPoint*)FirstPoint, FirstWidth);
+ free(pETEs);
+ miFreeStorage(SLLBlock.next);
+}
+/***** END OF X11-based CODE *****/
+
+QT_END_NAMESPACE
diff --git a/src/qt3support/other/q3polygonscanner.h b/src/qt3support/other/q3polygonscanner.h
new file mode 100644
index 0000000..7071825
--- /dev/null
+++ b/src/qt3support/other/q3polygonscanner.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3POLYGONSCANNER_H
+#define Q3POLYGONSCANNER_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3SupportLight)
+
+class Q3PointArray;
+class QPoint;
+
+class Q_COMPAT_EXPORT Q3PolygonScanner {
+public:
+ virtual ~Q3PolygonScanner() {}
+ void scan(const Q3PointArray& pa, bool winding, int index=0, int npoints=-1);
+ void scan(const Q3PointArray& pa, bool winding, int index, int npoints, bool stitchable);
+ enum Edge { Left=1, Right=2, Top=4, Bottom=8 };
+ void scan(const Q3PointArray& pa, bool winding, int index, int npoints, Edge edges);
+ virtual void processSpans(int n, QPoint* point, int* width)=0;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // Q3POLYGONSCANNER_H
diff --git a/src/qt3support/other/q3process.cpp b/src/qt3support/other/q3process.cpp
new file mode 100644
index 0000000..6eac812
--- /dev/null
+++ b/src/qt3support/other/q3process.cpp
@@ -0,0 +1,927 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3process.h"
+
+#ifndef QT_NO_PROCESS
+
+#include "qapplication.h"
+#include "private/q3membuf_p.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+QT_BEGIN_NAMESPACE
+
+//#define QT_Q3PROCESS_DEBUG
+
+
+/*!
+ \class Q3Process
+
+ \brief The Q3Process class is used to start external programs and
+ to communicate with them.
+
+ \compat
+
+ You can write to the started program's standard input, and can
+ read the program's standard output and standard error. You can
+ pass command line arguments to the program either in the
+ constructor or with setArguments() or addArgument(). The program's
+ working directory can be set with setWorkingDirectory(). If you
+ need to set up environment variables pass them to the start() or
+ launch() functions (see below). The processExited() signal is
+ emitted if the program exits. The program's exit status is
+ available from exitStatus(), although you could simply call
+ normalExit() to see if the program terminated normally.
+
+ There are two different ways to start a process. If you just want
+ to run a program, optionally passing data to its standard input at
+ the beginning, use one of the launch() functions. If you want full
+ control of the program's standard input (especially if you don't
+ know all the data you want to send to standard input at the
+ beginning), use the start() function.
+
+ If you use start() you can write to the program's standard input
+ using writeToStdin() and you can close the standard input with
+ closeStdin(). The wroteToStdin() signal is emitted if the data
+ sent to standard input has been written. You can read from the
+ program's standard output using readStdout() or readLineStdout().
+ These functions return an empty QByteArray if there is no data to
+ read. The readyReadStdout() signal is emitted when there is data
+ available to be read from standard output. Standard error has a
+ set of functions that correspond to the standard output functions,
+ i.e. readStderr(), readLineStderr() and readyReadStderr().
+
+ If you use one of the launch() functions the data you pass will be
+ sent to the program's standard input which will be closed once all
+ the data has been written. You should \e not use writeToStdin() or
+ closeStdin() if you use launch(). If you need to send data to the
+ program's standard input after it has started running use start()
+ instead of launch().
+
+ Both start() and launch() can accept a string list of strings each
+ of which has the format, key=value, where the keys are the names
+ of environment variables.
+
+ You can test to see if a program is running with isRunning(). The
+ program's process identifier is available from
+ processIdentifier(). If you want to terminate a running program
+ use tryTerminate(), but note that the program may ignore this. If
+ you \e really want to terminate the program, without it having any
+ chance to clean up, you can use kill().
+
+ Although you may need quotes for a file named on the command line
+ (e.g. if it contains spaces) you shouldn't use extra quotes for
+ arguments passed to addArgument() or setArguments().
+
+ The readyReadStdout() signal is emitted when there is new data on
+ standard output. This happens asynchronously: you don't know if
+ more data will arrive later.
+
+ In the above example you could connect the processExited() signal
+ to the slot UicManager::readFromStdout() instead. If you do so,
+ you will be certain that all the data is available when the slot
+ is called. On the other hand, you must wait until the process has
+ finished before doing any processing.
+
+ Note that if you are expecting a lot of output from the process,
+ you may hit platform-dependent limits to the pipe buffer size. The
+ solution is to make sure you connect to the output, e.g. the
+ readyReadStdout() and readyReadStderr() signals and read the data
+ as soon as it becomes available.
+
+ Please note that Q3Process does not emulate a shell. This means that
+ Q3Process does not do any expansion of arguments: a '*' is passed as a '*'
+ to the program and is \e not replaced by all the files, a '$HOME' is also
+ passed literally and is \e not replaced by the environment variable HOME
+ and the special characters for IO redirection ('>', '|', etc.) are also
+ passed literally and do \e not have the special meaning as they have in a
+ shell.
+
+ Also note that Q3Process does not emulate a terminal. This means that
+ certain programs which need direct terminal control, do not work as
+ expected with Q3Process. Such programs include console email programs (like
+ pine and mutt) but also programs which require the user to enter a password
+ (like su and ssh).
+
+ \section1 Notes for Windows users
+
+ Some Windows commands, for example, \c dir, are not provided by
+ separate applications, but by the command interpreter.
+ If you attempt to use Q3Process to execute these commands directly
+ it won't work. One possible solution is to execute the command
+ interpreter itself (\c cmd.exe on some Windows systems), and ask
+ the interpreter to execute the desired command.
+
+ Under Windows there are certain problems starting 16-bit applications
+ and capturing their output. Microsoft recommends using an intermediate
+ application to start 16-bit applications.
+
+ \sa Q3Socket
+*/
+
+/*!
+ \enum Q3Process::Communication
+
+ This enum type defines the communication channels connected to the
+ process.
+
+ \value Stdin Data can be written to the process's standard input.
+
+ \value Stdout Data can be read from the process's standard
+ output.
+
+ \value Stderr Data can be read from the process's standard error.
+
+ \value DupStderr Both the process's standard error output \e and
+ its standard output are written to its standard output. (Like
+ Unix's dup2().) This means that nothing is sent to the standard
+ error output. This is especially useful if your application
+ requires that the output on standard output and on standard error
+ must be read in the same order that they are produced. This is a
+ flag, so to activate it you must pass \c{Stdout|Stderr|DupStderr},
+ or \c{Stdin|Stdout|Stderr|DupStderr} if you want to provide input,
+ to the setCommunication() call.
+
+ \sa setCommunication() communication()
+*/
+
+/*!
+ Constructs a Q3Process object. The \a parent and \a name parameters
+ are passed to the QObject constructor.
+
+ \sa setArguments() addArgument() start()
+*/
+Q3Process::Q3Process( QObject *parent, const char *name )
+ : QObject( parent, name ), ioRedirection( false ), notifyOnExit( false ),
+ wroteToStdinConnected( false ),
+ readStdoutCalled( false ), readStderrCalled( false ),
+ comms( Stdin|Stdout|Stderr )
+{
+ init();
+}
+
+/*!
+ Constructs a Q3Process with \a arg0 as the command to be executed.
+ The \a parent and \a name parameters are passed to the QObject
+ constructor.
+
+ The process is not started. You must call start() or launch() to
+ start the process.
+
+ \sa setArguments() addArgument() start()
+*/
+Q3Process::Q3Process( const QString& arg0, QObject *parent, const char *name )
+ : QObject( parent, name ), ioRedirection( false ), notifyOnExit( false ),
+ wroteToStdinConnected( false ),
+ readStdoutCalled( false ), readStderrCalled( false ),
+ comms( Stdin|Stdout|Stderr )
+{
+ init();
+ addArgument( arg0 );
+}
+
+/*!
+ Constructs a Q3Process with \a args as the arguments of the
+ process. The first element in the list is the command to be
+ executed. The other elements in the list are the arguments to this
+ command. The \a parent and \a name parameters are passed to the
+ QObject constructor.
+
+ The process is not started. You must call start() or launch() to
+ start the process.
+
+ \sa setArguments() addArgument() start()
+*/
+Q3Process::Q3Process( const QStringList& args, QObject *parent, const char *name )
+ : QObject( parent, name ), ioRedirection( false ), notifyOnExit( false ),
+ wroteToStdinConnected( false ),
+ readStdoutCalled( false ), readStderrCalled( false ),
+ comms( Stdin|Stdout|Stderr )
+{
+ init();
+ setArguments( args );
+}
+
+/*!
+ \fn Q3Process::~Q3Process()
+
+ Destroys the instance.
+
+ If the process is running, it is <b>not</b> terminated! The
+ standard input, standard output and standard error of the process
+ are closed.
+
+ You can connect the destroyed() signal to the kill() slot, if you
+ want the process to be terminated automatically when the instance
+ is destroyed.
+
+ \sa tryTerminate() kill()
+*/
+
+/*!
+ Returns the list of arguments that are set for the process.
+ Arguments can be specified with the constructor or with the
+ functions setArguments() and addArgument().
+
+ Note that if you want to iterate over the list, you should iterate
+ over a copy, e.g.
+ \snippet doc/src/snippets/code/src_qt3support_other_q3process.cpp 0
+
+ \sa setArguments() addArgument()
+*/
+QStringList Q3Process::arguments() const
+{
+ return _arguments;
+}
+
+/*!
+ Clears the list of arguments that are set for the process.
+
+ \sa setArguments() addArgument()
+*/
+void Q3Process::clearArguments()
+{
+ _arguments.clear();
+}
+
+/*!
+ Sets \a args as the arguments for the process. The first element
+ in the list is the command to be executed. The other elements in
+ the list are the arguments to the command. Any previous arguments
+ are deleted.
+
+ Q3Process does not perform argument substitutions; for example, if you
+ specify "*" or "$DISPLAY", these values are passed to the process
+ literally. If you want to have the same behavior as the shell
+ provides, you must do the substitutions yourself; i.e. instead of
+ specifying a "*" you must specify the list of all the filenames in
+ the current directory, and instead of "$DISPLAY" you must specify
+ the value of the environment variable \c DISPLAY.
+
+ Note for Windows users. The standard Windows shells, e.g. \c
+ command.com and \c cmd.exe, do not perform file globbing, i.e.
+ they do not convert a "*" on the command line into a list of files
+ in the current directory. For this reason most Windows
+ applications implement their own file globbing, and as a result of
+ this, specifying an argument of "*" for a Windows application is
+ likely to result in the application performing a file glob and
+ ending up with a list of filenames.
+
+ \sa arguments() addArgument()
+*/
+void Q3Process::setArguments( const QStringList& args )
+{
+ _arguments = args;
+}
+
+/*!
+ Adds \a arg to the end of the list of arguments.
+
+ The first element in the list of arguments is the command to be
+ executed; the following elements are the command's arguments.
+
+ \sa arguments() setArguments()
+*/
+void Q3Process::addArgument( const QString& arg )
+{
+ _arguments.append( arg );
+}
+
+#ifndef QT_NO_DIR
+/*!
+ Returns the working directory that was set with
+ setWorkingDirectory(), or the current directory if none has been
+ explicitly set.
+
+ \sa setWorkingDirectory() QDir::current()
+*/
+QDir Q3Process::workingDirectory() const
+{
+ return workingDir;
+}
+
+/*!
+ Sets \a dir as the working directory for processes. This does not
+ affect running processes; only processes that are started
+ afterwards are affected.
+
+ Setting the working directory is especially useful for processes
+ that try to access files with relative paths.
+
+ \sa workingDirectory() start()
+*/
+void Q3Process::setWorkingDirectory( const QDir& dir )
+{
+ workingDir = dir;
+}
+#endif //QT_NO_DIR
+
+/*!
+ Returns the communication required with the process, i.e. some
+ combination of the \c Communication flags.
+
+ \sa setCommunication()
+*/
+int Q3Process::communication() const
+{
+ return comms;
+}
+
+/*!
+ Sets \a commFlags as the communication required with the process.
+
+ \a commFlags is a bitwise OR of the flags defined by the \c
+ Communication enum.
+
+ The default is \c{Stdin|Stdout|Stderr}.
+
+ \sa communication()
+*/
+void Q3Process::setCommunication( int commFlags )
+{
+ comms = commFlags;
+}
+
+/*!
+ Returns true if the process has exited normally; otherwise returns
+ false. This implies that this function returns false if the
+ process is still running.
+
+ \sa isRunning() exitStatus() processExited()
+*/
+bool Q3Process::normalExit() const
+{
+ // isRunning() has the side effect that it determines the exit status!
+ if ( isRunning() )
+ return false;
+ else
+ return exitNormal;
+}
+
+/*!
+ Returns the exit status of the process or 0 if the process is
+ still running. This function returns immediately and does not wait
+ until the process is finished.
+
+ If normalExit() is false (e.g. if the program was killed or
+ crashed), this function returns 0, so you should check the return
+ value of normalExit() before relying on this value.
+
+ \sa normalExit() processExited()
+*/
+int Q3Process::exitStatus() const
+{
+ // isRunning() has the side effect that it determines the exit status!
+ if ( isRunning() )
+ return 0;
+ else
+ return exitStat;
+}
+
+
+/*!
+ Reads the data that the process has written to standard output.
+ When new data is written to standard output, the class emits the
+ signal readyReadStdout().
+
+ If there is no data to read, this function returns a QByteArray of
+ size 0: it does not wait until there is something to read.
+
+ \sa readyReadStdout() readLineStdout() readStderr() writeToStdin()
+*/
+QByteArray Q3Process::readStdout()
+{
+ if ( readStdoutCalled ) {
+ return QByteArray();
+ }
+ readStdoutCalled = true;
+ Q3Membuf *buf = membufStdout();
+ readStdoutCalled = false;
+
+ return buf->readAll();
+}
+
+/*!
+ Reads the data that the process has written to standard error.
+ When new data is written to standard error, the class emits the
+ signal readyReadStderr().
+
+ If there is no data to read, this function returns a QByteArray of
+ size 0: it does not wait until there is something to read.
+
+ \sa readyReadStderr() readLineStderr() readStdout() writeToStdin()
+*/
+QByteArray Q3Process::readStderr()
+{
+ if ( readStderrCalled ) {
+ return QByteArray();
+ }
+ readStderrCalled = true;
+ Q3Membuf *buf = membufStderr();
+ readStderrCalled = false;
+
+ return buf->readAll();
+}
+
+/*!
+ Reads a line of text from standard output, excluding any trailing
+ newline or carriage return characters, and returns it. Returns
+ an empty string if canReadLineStdout() returns false.
+
+ By default, the text is interpreted to be in Latin-1 encoding. If you need
+ other codecs, you can set a different codec with
+ QTextCodec::setCodecForCStrings().
+
+ \sa canReadLineStdout() readyReadStdout() readStdout() readLineStderr()
+*/
+QString Q3Process::readLineStdout()
+{
+ QByteArray a( 256 );
+ Q3Membuf *buf = membufStdout();
+ if ( !buf->scanNewline( &a ) ) {
+ if ( !canReadLineStdout() )
+ return QString();
+
+ if ( !buf->scanNewline( &a ) )
+ return QString( QLatin1String(buf->readAll()) );
+ }
+
+ uint size = a.size();
+ buf->consumeBytes( size, 0 );
+
+ // get rid of terminating \n or \r\n
+ if ( size>0 && a.at( size - 1 ) == '\n' ) {
+ if ( size>1 && a.at( size - 2 ) == '\r' )
+ a.chop(2);
+ else
+ a.chop(1);
+ }
+ return QString(QString::fromLatin1(a.constData()));
+}
+
+/*!
+ Reads a line of text from standard error, excluding any trailing
+ newline or carriage return characters and returns it. Returns
+ an empty string if canReadLineStderr() returns false.
+
+ By default, the text is interpreted to be in Latin-1 encoding. If you need
+ other codecs, you can set a different codec with
+ QTextCodec::setCodecForCStrings().
+
+ \sa canReadLineStderr() readyReadStderr() readStderr() readLineStdout()
+*/
+QString Q3Process::readLineStderr()
+{
+ QByteArray a( 256 );
+ Q3Membuf *buf = membufStderr();
+ if ( !buf->scanNewline( &a ) ) {
+ if ( !canReadLineStderr() )
+ return QString();
+
+ if ( !buf->scanNewline( &a ) )
+ return QString( QString::fromLatin1( buf->readAll().constData() ) );
+ }
+
+ uint size = a.size();
+ buf->consumeBytes( size, 0 );
+
+ // get rid of terminating \n or \r\n
+ if ( size>0 && a.at( size - 1 ) == '\n' ) {
+ if ( size>1 && a.at( size - 2 ) == '\r' )
+ a.chop(2);
+ else
+ a.chop(1);
+ }
+ return QString( QString::fromLatin1( a.constData() ) );
+}
+
+/*!
+ \fn bool Q3Process::start( QStringList *env )
+
+ Tries to run a process for the command and arguments that were
+ specified with setArguments(), addArgument() or that were
+ specified in the constructor. The command is searched for in the
+ path for executable programs; you can also use an absolute path in
+ the command itself.
+
+ If \a env is null, then the process is started with the same
+ environment as the starting process. If \a env is non-null, then
+ the values in the stringlist are interpreted as environment
+ setttings of the form \c {key=value} and the process is started in
+ these environment settings. For convenience, there is a small
+ exception to this rule: under Unix, if \a env does not contain any
+ settings for the environment variable \c LD_LIBRARY_PATH, then
+ this variable is inherited from the starting process; under
+ Windows the same applies for the environment variable \c PATH.
+
+ Returns true if the process could be started; otherwise returns
+ false.
+
+ You can write data to the process's standard input with
+ writeToStdin(). You can close standard input with closeStdin() and
+ you can terminate the process with tryTerminate(), or with kill().
+
+ You can call this function even if you've used this instance to
+ create a another process which is still running. In such cases,
+ Q3Process closes the old process's standard input and deletes
+ pending data, i.e., you lose all control over the old process, but
+ the old process is not terminated. This applies also if the
+ process could not be started. (On operating systems that have
+ zombie processes, Qt will also wait() on the old process.)
+
+ \sa launch() closeStdin()
+*/
+
+/*!
+ \fn void Q3Process::tryTerminate() const
+
+ Asks the process to terminate. Processes can ignore this if they
+ wish. If you want to be certain that the process really
+ terminates, you can use kill() instead.
+
+ The slot returns immediately: it does not wait until the process
+ has finished. When the process terminates, the processExited()
+ signal is emitted.
+
+ \sa kill() processExited()
+*/
+
+/*!
+ \fn void Q3Process::kill() const
+
+ Terminates the process. This is not a safe way to end a process
+ since the process will not be able to do any cleanup.
+ tryTerminate() is safer, but processes can ignore a
+ tryTerminate().
+
+ The nice way to end a process and to be sure that it is finished,
+ is to do something like this:
+ \snippet doc/src/snippets/code/src_qt3support_other_q3process_unix.cpp 0
+
+ This tries to terminate the process the nice way. If the process
+ is still running after 5 seconds, it terminates the process the
+ hard way. The timeout should be chosen depending on the time the
+ process needs to do all its cleanup: use a higher value if the
+ process is likely to do a lot of computation or I/O on cleanup.
+
+ The slot returns immediately: it does not wait until the process
+ has finished. When the process terminates, the processExited()
+ signal is emitted.
+
+ \sa tryTerminate() processExited()
+*/
+
+/*!
+ \fn bool Q3Process::isRunning() const
+
+ Returns true if the process is running; otherwise returns false.
+
+ \sa normalExit() exitStatus() processExited()
+*/
+
+/*!
+ \fn bool Q3Process::canReadLineStdout() const
+
+ Returns true if it's possible to read an entire line of text from
+ standard output at this time; otherwise returns false.
+
+ \sa readLineStdout() canReadLineStderr()
+*/
+
+/*!
+ \fn bool Q3Process::canReadLineStderr() const
+
+ Returns true if it's possible to read an entire line of text from
+ standard error at this time; otherwise returns false.
+
+ \sa readLineStderr() canReadLineStdout()
+*/
+
+/*!
+ \fn void Q3Process::writeToStdin( const QByteArray& buf )
+
+ Writes the data \a buf to the process's standard input. The
+ process may or may not read this data.
+
+ This function returns immediately; the Q3Process class might write
+ the data at a later point (you must enter the event loop for this
+ to occur). When all the data is written to the process, the signal
+ wroteToStdin() is emitted. This does not mean that the process
+ actually read the data, since this class only detects when it was
+ able to write the data to the operating system.
+
+ \sa wroteToStdin() closeStdin() readStdout() readStderr()
+*/
+
+/*!
+ \fn void Q3Process::closeStdin()
+
+ Closes the process's standard input.
+
+ This function also deletes any pending data that has not been
+ written to standard input.
+
+ \sa wroteToStdin()
+*/
+
+/*!
+ \fn Q3Process::PID Q3Process::processIdentifier()
+
+ Returns platform dependent information about the process. This can
+ be used together with platform specific system calls.
+
+ Under Unix the return value is the PID of the process, or -1 if no
+ process belongs to this object.
+
+ Under Windows it is a pointer to the \c PROCESS_INFORMATION
+ struct, or 0 if no process is belongs to this object.
+
+ Use of this function's return value is likely to be non-portable.
+*/
+
+/*!
+ \fn void Q3Process::launchFinished()
+
+ This signal is emitted when the process was started with launch().
+ If the start was successful, this signal is emitted after all the
+ data has been written to standard input. If the start failed, then
+ this signal is emitted immediately.
+
+ This signal is especially useful if you want to know when you can
+ safely delete the Q3Process object when you are not interested in
+ reading from standard output or standard error.
+
+ \sa launch() QObject::deleteLater()
+*/
+
+/*!
+ Runs the process and writes the data \a buf to the process's
+ standard input. If all the data is written to standard input,
+ standard input is closed. The command is searched for in the path
+ for executable programs; you can also use an absolute path in the
+ command itself.
+
+ If \a env is null, then the process is started with the same
+ environment as the starting process. If \a env is non-null, then
+ the values in the string list are interpreted as environment
+ setttings of the form \c {key=value} and the process is started
+ with these environment settings. For convenience, there is a small
+ exception to this rule under Unix: if \a env does not contain any
+ settings for the environment variable \c LD_LIBRARY_PATH, then
+ this variable is inherited from the starting process.
+
+ Returns true if the process could be started; otherwise returns
+ false.
+
+ Note that you should not use the slots writeToStdin() and
+ closeStdin() on processes started with launch(), since the result
+ is not well-defined. If you need these slots, use start() instead.
+
+ The process may or may not read the \a buf data sent to its
+ standard input.
+
+ You can call this function even when a process that was started
+ with this instance is still running. Be aware that if you do this
+ the standard input of the process that was launched first will be
+ closed, with any pending data being deleted, and the process will
+ be left to run out of your control. Similarly, if the process
+ could not be started the standard input will be closed and the
+ pending data deleted. (On operating systems that have zombie
+ processes, Qt will also wait() on the old process.)
+
+ The object emits the signal launchFinished() when this function
+ call is finished. If the start was successful, this signal is
+ emitted after all the data has been written to standard input. If
+ the start failed, then this signal is emitted immediately.
+
+ \sa start() launchFinished()
+*/
+bool Q3Process::launch( const QByteArray& buf, QStringList *env )
+{
+ if ( start( env ) ) {
+ if ( !buf.isEmpty() ) {
+ connect( this, SIGNAL(wroteToStdin()),
+ this, SLOT(closeStdinLaunch()) );
+ writeToStdin( buf );
+ } else {
+ closeStdin();
+ emit launchFinished();
+ }
+ return true;
+ } else {
+ emit launchFinished();
+ return false;
+ }
+}
+
+/*!
+ \overload
+
+ The data \a buf is written to standard input with writeToStdin()
+ using the QString::local8Bit() representation of the strings.
+*/
+bool Q3Process::launch( const QString& buf, QStringList *env )
+{
+ if ( start( env ) ) {
+ if ( !buf.isEmpty() ) {
+ connect( this, SIGNAL(wroteToStdin()),
+ this, SLOT(closeStdinLaunch()) );
+ writeToStdin( buf );
+ } else {
+ closeStdin();
+ emit launchFinished();
+ }
+ return true;
+ } else {
+ emit launchFinished();
+ return false;
+ }
+}
+
+/*
+ This private slot is used by the launch() functions to close standard input.
+*/
+void Q3Process::closeStdinLaunch()
+{
+ disconnect( this, SIGNAL(wroteToStdin()),
+ this, SLOT(closeStdinLaunch()) );
+ closeStdin();
+ emit launchFinished();
+}
+
+
+/*!
+ \fn void Q3Process::readyReadStdout()
+
+ This signal is emitted when the process has written data to
+ standard output. You can read the data with readStdout().
+
+ Note that this signal is only emitted when there is new data and
+ not when there is old, but unread data. In the slot connected to
+ this signal, you should always read everything that is available
+ at that moment to make sure that you don't lose any data.
+
+ \sa readStdout() readLineStdout() readyReadStderr()
+*/
+
+/*!
+ \fn void Q3Process::readyReadStderr()
+
+ This signal is emitted when the process has written data to
+ standard error. You can read the data with readStderr().
+
+ Note that this signal is only emitted when there is new data and
+ not when there is old, but unread data. In the slot connected to
+ this signal, you should always read everything that is available
+ at that moment to make sure that you don't lose any data.
+
+ \sa readStderr() readLineStderr() readyReadStdout()
+*/
+
+/*!
+ \fn void Q3Process::processExited()
+
+ This signal is emitted when the process has exited.
+
+ \sa isRunning() normalExit() exitStatus() start() launch()
+*/
+
+/*!
+ \fn void Q3Process::wroteToStdin()
+
+ This signal is emitted if the data sent to standard input (via
+ writeToStdin()) was actually written to the process. This does not
+ imply that the process really read the data, since this class only
+ detects when it was able to write the data to the operating
+ system. But it is now safe to close standard input without losing
+ pending data.
+
+ \sa writeToStdin() closeStdin()
+*/
+
+
+/*!
+ \overload
+
+ The string \a buf is handled as text using the
+ QString::local8Bit() representation.
+*/
+void Q3Process::writeToStdin( const QString& buf )
+{
+ QByteArray tmp = buf.local8Bit();
+ tmp.resize( buf.length() );
+ writeToStdin( tmp );
+}
+
+
+/*
+ * Under Windows the implementation is not so nice: it is not that easy to
+ * detect when one of the signals should be emitted; therefore there are some
+ * timers that query the information.
+ * To keep it a little efficient, use the timers only when they are needed.
+ * They are needed, if you are interested in the signals. So use
+ * connectNotify() and disconnectNotify() to keep track of your interest.
+ */
+/*! \reimp
+*/
+void Q3Process::connectNotify( const char * signal )
+{
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3Process::connectNotify(): signal %s has been connected", signal );
+#endif
+ if ( !ioRedirection )
+ if ( qstrcmp( signal, SIGNAL(readyReadStdout()) )==0 ||
+ qstrcmp( signal, SIGNAL(readyReadStderr()) )==0
+ ) {
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3Process::connectNotify(): set ioRedirection to true" );
+#endif
+ setIoRedirection( true );
+ return;
+ }
+ if ( !notifyOnExit && qstrcmp( signal, SIGNAL(processExited()) )==0 ) {
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3Process::connectNotify(): set notifyOnExit to true" );
+#endif
+ setNotifyOnExit( true );
+ return;
+ }
+ if ( !wroteToStdinConnected && qstrcmp( signal, SIGNAL(wroteToStdin()) )==0 ) {
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3Process::connectNotify(): set wroteToStdinConnected to true" );
+#endif
+ setWroteStdinConnected( true );
+ return;
+ }
+}
+
+/*! \reimp
+*/
+void Q3Process::disconnectNotify( const char * )
+{
+ if ( ioRedirection &&
+ receivers( SIGNAL(readyReadStdout()) ) ==0 &&
+ receivers( SIGNAL(readyReadStderr()) ) ==0
+ ) {
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3Process::disconnectNotify(): set ioRedirection to false" );
+#endif
+ setIoRedirection( false );
+ }
+ if ( notifyOnExit && receivers( SIGNAL(processExited()) ) == 0 ) {
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3Process::disconnectNotify(): set notifyOnExit to false" );
+#endif
+ setNotifyOnExit( false );
+ }
+ if ( wroteToStdinConnected && receivers( SIGNAL(wroteToStdin()) ) == 0 ) {
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3Process::disconnectNotify(): set wroteToStdinConnected to false" );
+#endif
+ setWroteStdinConnected( false );
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_PROCESS
diff --git a/src/qt3support/other/q3process.h b/src/qt3support/other/q3process.h
new file mode 100644
index 0000000..ac28390
--- /dev/null
+++ b/src/qt3support/other/q3process.h
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3PROCESS_H
+#define Q3PROCESS_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qdir.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3SupportLight)
+
+#ifndef QT_NO_PROCESS
+
+class Q3ProcessPrivate;
+class Q3Membuf;
+
+class Q_COMPAT_EXPORT Q3Process : public QObject
+{
+ Q_OBJECT
+public:
+ Q3Process( QObject *parent=0, const char *name=0 );
+ Q3Process( const QString& arg0, QObject *parent=0, const char *name=0 );
+ Q3Process( const QStringList& args, QObject *parent=0, const char *name=0 );
+ ~Q3Process();
+
+ // set and get the arguments and working directory
+ QStringList arguments() const;
+ void clearArguments();
+ virtual void setArguments( const QStringList& args );
+ virtual void addArgument( const QString& arg );
+#ifndef QT_NO_DIR
+ QDir workingDirectory() const;
+ virtual void setWorkingDirectory( const QDir& dir );
+#endif
+
+ // set and get the comms wanted
+ enum Communication { Stdin=0x01, Stdout=0x02, Stderr=0x04, DupStderr=0x08 };
+ void setCommunication( int c );
+ int communication() const;
+
+ // start the execution
+ virtual bool start( QStringList *env=0 );
+ virtual bool launch( const QString& buf, QStringList *env=0 );
+ virtual bool launch( const QByteArray& buf, QStringList *env=0 );
+
+ // inquire the status
+ bool isRunning() const;
+ bool normalExit() const;
+ int exitStatus() const;
+
+ // reading
+ virtual QByteArray readStdout();
+ virtual QByteArray readStderr();
+ bool canReadLineStdout() const;
+ bool canReadLineStderr() const;
+ virtual QString readLineStdout();
+ virtual QString readLineStderr();
+
+ // get platform dependent process information
+#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
+ typedef void* PID;
+#else
+ typedef Q_LONG PID;
+#endif
+ PID processIdentifier();
+
+ void flushStdin();
+
+Q_SIGNALS:
+ void readyReadStdout();
+ void readyReadStderr();
+ void processExited();
+ void wroteToStdin();
+ void launchFinished();
+
+public Q_SLOTS:
+ // end the execution
+ void tryTerminate() const;
+ void kill() const;
+
+ // input
+ virtual void writeToStdin( const QByteArray& buf );
+ virtual void writeToStdin( const QString& buf );
+ virtual void closeStdin();
+
+protected: // ### or private?
+ void connectNotify( const char * signal );
+ void disconnectNotify( const char * signal );
+private:
+ void setIoRedirection( bool value );
+ void setNotifyOnExit( bool value );
+ void setWroteStdinConnected( bool value );
+
+ void init();
+ void reset();
+#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
+ uint readStddev( Qt::HANDLE dev, char *buf, uint bytes );
+#endif
+ Q3Membuf* membufStdout();
+ Q3Membuf* membufStderr();
+
+private Q_SLOTS:
+ void socketRead( int fd );
+ void socketWrite( int fd );
+ void timeout();
+ void closeStdinLaunch();
+
+private:
+ Q3ProcessPrivate *d;
+#ifndef QT_NO_DIR
+ QDir workingDir;
+#endif
+ QStringList _arguments;
+
+ int exitStat; // exit status
+ bool exitNormal; // normal exit?
+ bool ioRedirection; // automatically set be (dis)connectNotify
+ bool notifyOnExit; // automatically set be (dis)connectNotify
+ bool wroteToStdinConnected; // automatically set be (dis)connectNotify
+
+ bool readStdoutCalled;
+ bool readStderrCalled;
+ int comms;
+
+ friend class Q3ProcessPrivate;
+#if defined(Q_OS_UNIX)
+ friend class Q3ProcessManager;
+ friend class QProc;
+#endif
+
+#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator=
+ Q3Process( const Q3Process & );
+ Q3Process &operator=( const Q3Process & );
+#endif
+};
+
+#endif // QT_NO_PROCESS
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // Q3PROCESS_H
diff --git a/src/qt3support/other/q3process_unix.cpp b/src/qt3support/other/q3process_unix.cpp
new file mode 100644
index 0000000..098c581
--- /dev/null
+++ b/src/qt3support/other/q3process_unix.cpp
@@ -0,0 +1,1282 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qplatformdefs.h"
+
+// Solaris redefines connect -> __xnet_connect with _XOPEN_SOURCE_EXTENDED.
+#if defined(connect)
+#undef connect
+#endif
+
+#include "q3process.h"
+
+#ifndef QT_NO_PROCESS
+
+#include "qapplication.h"
+#include "q3cstring.h"
+#include "q3ptrqueue.h"
+#include "q3ptrlist.h"
+#include "qsocketnotifier.h"
+#include "qtimer.h"
+#include "q3cleanuphandler.h"
+#include "qregexp.h"
+#include "private/q3membuf_p.h"
+#include "private/qobject_p.h"
+
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifdef __MIPSEL__
+# ifndef SOCK_DGRAM
+# define SOCK_DGRAM 1
+# endif
+# ifndef SOCK_STREAM
+# define SOCK_STREAM 2
+# endif
+#endif
+
+//#define QT_Q3PROCESS_DEBUG
+
+
+#ifdef Q_C_CALLBACKS
+extern "C" {
+#endif // Q_C_CALLBACKS
+
+ static QT_SIGNAL_RETTYPE qt_C_sigchldHnd(QT_SIGNAL_ARGS);
+
+#ifdef Q_C_CALLBACKS
+}
+#endif // Q_C_CALLBACKS
+
+
+class QProc;
+class Q3ProcessManager;
+class Q3ProcessPrivate
+{
+public:
+ Q3ProcessPrivate();
+ ~Q3ProcessPrivate();
+
+ void closeOpenSocketsForChild();
+ void newProc( pid_t pid, Q3Process *process );
+
+ Q3Membuf bufStdout;
+ Q3Membuf bufStderr;
+
+ Q3PtrQueue<QByteArray> stdinBuf;
+
+ QSocketNotifier *notifierStdin;
+ QSocketNotifier *notifierStdout;
+ QSocketNotifier *notifierStderr;
+
+ ssize_t stdinBufRead;
+ QProc *proc;
+
+ bool exitValuesCalculated;
+ bool socketReadCalled;
+
+ static Q3ProcessManager *procManager;
+};
+
+
+/***********************************************************************
+ *
+ * QProc
+ *
+ **********************************************************************/
+/*
+ The class Q3Process does not necessarily map exactly to the running
+ child processes: if the process is finished, the Q3Process class may still be
+ there; furthermore a user can use Q3Process to start more than one process.
+
+ The helper-class QProc has the semantics that one instance of this class maps
+ directly to a running child process.
+*/
+class QProc
+{
+public:
+ QProc( pid_t p, Q3Process *proc=0 ) : pid(p), process(proc)
+ {
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "QProc: Constructor for pid %d and Q3Process %p", pid, process );
+#endif
+ socketStdin = 0;
+ socketStdout = 0;
+ socketStderr = 0;
+ }
+ ~QProc()
+ {
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "QProc: Destructor for pid %d and Q3Process %p", pid, process );
+#endif
+ if ( process ) {
+ if ( process->d->notifierStdin )
+ process->d->notifierStdin->setEnabled( false );
+ if ( process->d->notifierStdout )
+ process->d->notifierStdout->setEnabled( false );
+ if ( process->d->notifierStderr )
+ process->d->notifierStderr->setEnabled( false );
+ process->d->proc = 0;
+ }
+ if( socketStdin )
+ ::close( socketStdin );
+ if( socketStdout )
+ ::close( socketStdout );
+ if( socketStderr )
+ ::close( socketStderr );
+ }
+
+ pid_t pid;
+ int socketStdin;
+ int socketStdout;
+ int socketStderr;
+ Q3Process *process;
+};
+
+/***********************************************************************
+ *
+ * Q3ProcessManager
+ *
+ **********************************************************************/
+class Q3ProcessManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ Q3ProcessManager();
+ ~Q3ProcessManager();
+
+ void append( QProc *p );
+ void remove( QProc *p );
+
+ void cleanup();
+
+public slots:
+ void removeMe();
+ void sigchldHnd( int );
+
+public:
+ struct sigaction oldactChld;
+ struct sigaction oldactPipe;
+ Q3PtrList<QProc> *procList;
+ int sigchldFd[2];
+
+private:
+ QSocketNotifier *sn;
+};
+
+static void q3process_cleanup()
+{
+ delete Q3ProcessPrivate::procManager;
+ Q3ProcessPrivate::procManager = 0;
+}
+
+#ifdef Q_OS_QNX6
+#define BAILOUT close(tmpSocket);close(socketFD[1]);return -1;
+int qnx6SocketPairReplacement (int socketFD[2]) {
+ int tmpSocket;
+ tmpSocket = socket (AF_INET, SOCK_STREAM, 0);
+ if (tmpSocket == -1)
+ return -1;
+ socketFD[1] = socket(AF_INET, SOCK_STREAM, 0);
+ if (socketFD[1] == -1) { BAILOUT };
+
+ sockaddr_in ipAddr;
+ memset(&ipAddr, 0, sizeof(ipAddr));
+ ipAddr.sin_family = AF_INET;
+ ipAddr.sin_addr.s_addr = INADDR_ANY;
+
+ int socketOptions = 1;
+ setsockopt(tmpSocket, SOL_SOCKET, SO_REUSEADDR, &socketOptions, sizeof(int));
+
+ bool found = false;
+ for (int socketIP = 2000; (socketIP < 2500) && !(found); socketIP++) {
+ ipAddr.sin_port = htons(socketIP);
+ if (bind(tmpSocket, (struct sockaddr *)&ipAddr, sizeof(ipAddr)))
+ found = true;
+ }
+
+ if (listen(tmpSocket, 5)) { BAILOUT };
+
+ // Select non-blocking mode
+ int originalFlags = fcntl(socketFD[1], F_GETFL, 0);
+ fcntl(socketFD[1], F_SETFL, originalFlags | O_NONBLOCK);
+
+ // Request connection
+ if (connect(socketFD[1], (struct sockaddr*)&ipAddr, sizeof(ipAddr)))
+ if (errno != EINPROGRESS) { BAILOUT };
+
+ // Accept connection
+ socketFD[0] = accept(tmpSocket, (struct sockaddr *)NULL, (size_t *)NULL);
+ if(socketFD[0] == -1) { BAILOUT };
+
+ // We're done
+ close(tmpSocket);
+
+ // Restore original flags , ie return to blocking
+ fcntl(socketFD[1], F_SETFL, originalFlags);
+ return 0;
+}
+#undef BAILOUT
+#endif
+
+Q3ProcessManager::Q3ProcessManager() : sn(0)
+{
+ procList = new Q3PtrList<QProc>;
+ procList->setAutoDelete( true );
+
+ // The SIGCHLD handler writes to a socket to tell the manager that
+ // something happened. This is done to get the processing in sync with the
+ // event reporting.
+#ifndef Q_OS_QNX6
+ if ( ::socketpair( AF_UNIX, SOCK_STREAM, 0, sigchldFd ) ) {
+#else
+ if ( qnx6SocketPairReplacement (sigchldFd) ) {
+#endif
+ sigchldFd[0] = 0;
+ sigchldFd[1] = 0;
+ } else {
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3ProcessManager: install socket notifier (%d)", sigchldFd[1] );
+#endif
+ sn = new QSocketNotifier( sigchldFd[1],
+ QSocketNotifier::Read, this );
+ connect( sn, SIGNAL(activated(int)),
+ this, SLOT(sigchldHnd(int)) );
+ sn->setEnabled( true );
+ }
+
+ // install a SIGCHLD handler and ignore SIGPIPE
+ struct sigaction act;
+
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3ProcessManager: install a SIGCHLD handler" );
+#endif
+ act.sa_handler = qt_C_sigchldHnd;
+ sigemptyset( &(act.sa_mask) );
+ sigaddset( &(act.sa_mask), SIGCHLD );
+ act.sa_flags = SA_NOCLDSTOP;
+#if defined(SA_RESTART)
+ act.sa_flags |= SA_RESTART;
+#endif
+ if ( sigaction( SIGCHLD, &act, &oldactChld ) != 0 )
+ qWarning( "Error installing SIGCHLD handler" );
+
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3ProcessManager: install a SIGPIPE handler (SIG_IGN)" );
+#endif
+ act.sa_handler = QT_SIGNAL_IGNORE;
+ sigemptyset( &(act.sa_mask) );
+ sigaddset( &(act.sa_mask), SIGPIPE );
+ act.sa_flags = 0;
+ if ( sigaction( SIGPIPE, &act, &oldactPipe ) != 0 )
+ qWarning( "Error installing SIGPIPE handler" );
+}
+
+Q3ProcessManager::~Q3ProcessManager()
+{
+ delete procList;
+
+ if ( sigchldFd[0] != 0 )
+ ::close( sigchldFd[0] );
+ if ( sigchldFd[1] != 0 )
+ ::close( sigchldFd[1] );
+
+ // restore SIGCHLD handler
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3ProcessManager: restore old sigchild handler" );
+#endif
+ if ( sigaction( SIGCHLD, &oldactChld, 0 ) != 0 )
+ qWarning( "Error restoring SIGCHLD handler" );
+
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3ProcessManager: restore old sigpipe handler" );
+#endif
+ if ( sigaction( SIGPIPE, &oldactPipe, 0 ) != 0 )
+ qWarning( "Error restoring SIGPIPE handler" );
+}
+
+void Q3ProcessManager::append( QProc *p )
+{
+ procList->append( p );
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3ProcessManager: append process (procList.count(): %d)", procList->count() );
+#endif
+}
+
+void Q3ProcessManager::remove( QProc *p )
+{
+ procList->remove( p );
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3ProcessManager: remove process (procList.count(): %d)", procList->count() );
+#endif
+ cleanup();
+}
+
+void Q3ProcessManager::cleanup()
+{
+ if ( procList->count() == 0 ) {
+ QTimer::singleShot( 0, this, SLOT(removeMe()) );
+ }
+}
+
+void Q3ProcessManager::removeMe()
+{
+ if ( procList->count() == 0 ) {
+ qRemovePostRoutine(q3process_cleanup);
+ Q3ProcessPrivate::procManager = 0;
+ delete this;
+ }
+}
+
+void Q3ProcessManager::sigchldHnd( int fd )
+{
+ // Disable the socket notifier to make sure that this function is not
+ // called recursively -- this can happen, if you enter the event loop in
+ // the slot connected to the processExited() signal (e.g. by showing a
+ // modal dialog) and there are more than one process which exited in the
+ // meantime.
+ if ( sn ) {
+ if ( !sn->isEnabled() )
+ return;
+ sn->setEnabled( false );
+ }
+
+ char tmp;
+ ::read( fd, &tmp, sizeof(tmp) );
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3ProcessManager::sigchldHnd()" );
+#endif
+ QProc *proc;
+ Q3Process *process;
+ bool removeProc;
+ proc = procList->first();
+ while ( proc != 0 ) {
+ removeProc = false;
+ process = proc->process;
+ if ( process != 0 ) {
+ if ( !process->isRunning() ) {
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3ProcessManager::sigchldHnd() (PID: %d): process exited (Q3Process available)", proc->pid );
+#endif
+ /*
+ Apparently, there is not consistency among different
+ operating systems on how to use FIONREAD.
+
+ FreeBSD, Linux and Solaris all expect the 3rd
+ argument to ioctl() to be an int, which is normally
+ 32-bit even on 64-bit machines.
+
+ IRIX, on the other hand, expects a size_t, which is
+ 64-bit on 64-bit machines.
+
+ So, the solution is to use size_t initialized to
+ zero to make sure all bits are set to zero,
+ preventing underflow with the FreeBSD/Linux/Solaris
+ ioctls.
+ */
+ size_t nbytes = 0;
+ // read pending data
+ if ( proc->socketStdout && ::ioctl(proc->socketStdout, FIONREAD, (char*)&nbytes)==0 && nbytes>0 ) {
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3ProcessManager::sigchldHnd() (PID: %d): reading %d bytes of pending data on stdout", proc->pid, nbytes );
+#endif
+ process->socketRead( proc->socketStdout );
+ }
+ nbytes = 0;
+ if ( proc->socketStderr && ::ioctl(proc->socketStderr, FIONREAD, (char*)&nbytes)==0 && nbytes>0 ) {
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3ProcessManager::sigchldHnd() (PID: %d): reading %d bytes of pending data on stderr", proc->pid, nbytes );
+#endif
+ process->socketRead( proc->socketStderr );
+ }
+ // close filedescriptors if open, and disable the
+ // socket notifiers
+ if ( proc->socketStdout ) {
+ ::close( proc->socketStdout );
+ proc->socketStdout = 0;
+ if (process->d->notifierStdout)
+ process->d->notifierStdout->setEnabled(false);
+ }
+ if ( proc->socketStderr ) {
+ ::close( proc->socketStderr );
+ proc->socketStderr = 0;
+ if (process->d->notifierStderr)
+ process->d->notifierStderr->setEnabled(false);
+ }
+
+ if ( process->notifyOnExit )
+ emit process->processExited();
+
+ removeProc = true;
+ }
+ } else {
+ int status;
+ if ( ::waitpid( proc->pid, &status, WNOHANG ) == proc->pid ) {
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3ProcessManager::sigchldHnd() (PID: %d): process exited (Q3Process not available)", proc->pid );
+#endif
+ removeProc = true;
+ }
+ }
+ if ( removeProc ) {
+ QProc *oldproc = proc;
+ proc = procList->next();
+ remove( oldproc );
+ } else {
+ proc = procList->next();
+ }
+ }
+ if ( sn )
+ sn->setEnabled( true );
+}
+
+QT_BEGIN_INCLUDE_NAMESPACE
+#include "q3process_unix.moc"
+QT_END_INCLUDE_NAMESPACE
+
+
+/***********************************************************************
+ *
+ * Q3ProcessPrivate
+ *
+ **********************************************************************/
+Q3ProcessManager *Q3ProcessPrivate::procManager = 0;
+
+Q3ProcessPrivate::Q3ProcessPrivate()
+{
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3ProcessPrivate: Constructor" );
+#endif
+ stdinBufRead = 0;
+
+ notifierStdin = 0;
+ notifierStdout = 0;
+ notifierStderr = 0;
+
+ exitValuesCalculated = false;
+ socketReadCalled = false;
+
+ proc = 0;
+}
+
+Q3ProcessPrivate::~Q3ProcessPrivate()
+{
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3ProcessPrivate: Destructor" );
+#endif
+
+ if ( proc != 0 ) {
+ if ( proc->socketStdin != 0 ) {
+ ::close( proc->socketStdin );
+ proc->socketStdin = 0;
+ }
+ proc->process = 0;
+ }
+
+ while ( !stdinBuf.isEmpty() ) {
+ delete stdinBuf.dequeue();
+ }
+ delete notifierStdin;
+ delete notifierStdout;
+ delete notifierStderr;
+}
+
+/*
+ Closes all open sockets in the child process that are not needed by the child
+ process. Otherwise one child may have an open socket on standard input, etc.
+ of another child.
+*/
+void Q3ProcessPrivate::closeOpenSocketsForChild()
+{
+ if ( procManager != 0 ) {
+ if ( procManager->sigchldFd[0] != 0 )
+ ::close( procManager->sigchldFd[0] );
+ if ( procManager->sigchldFd[1] != 0 )
+ ::close( procManager->sigchldFd[1] );
+
+ // close also the sockets from other Q3Process instances
+ for ( QProc *p=procManager->procList->first(); p!=0; p=procManager->procList->next() ) {
+ ::close( p->socketStdin );
+ ::close( p->socketStdout );
+ ::close( p->socketStderr );
+ }
+ }
+}
+
+void Q3ProcessPrivate::newProc( pid_t pid, Q3Process *process )
+{
+ proc = new QProc( pid, process );
+ if ( procManager == 0 ) {
+ procManager = new Q3ProcessManager;
+ qAddPostRoutine(q3process_cleanup);
+ }
+ // the Q3ProcessManager takes care of deleting the QProc instances
+ procManager->append( proc );
+}
+
+/***********************************************************************
+ *
+ * sigchld handler callback
+ *
+ **********************************************************************/
+static QT_SIGNAL_RETTYPE qt_C_sigchldHnd(QT_SIGNAL_ARGS)
+{
+ if ( Q3ProcessPrivate::procManager == 0 )
+ return;
+ if ( Q3ProcessPrivate::procManager->sigchldFd[0] == 0 )
+ return;
+
+ char a = 1;
+ ::write( Q3ProcessPrivate::procManager->sigchldFd[0], &a, sizeof(a) );
+}
+
+
+/***********************************************************************
+ *
+ * Q3Process
+ *
+ **********************************************************************/
+/*
+ This private class does basic initialization.
+*/
+void Q3Process::init()
+{
+ d = new Q3ProcessPrivate();
+ exitStat = 0;
+ exitNormal = false;
+}
+
+/*
+ This private class resets the process variables, etc. so that it can be used
+ for another process to start.
+*/
+void Q3Process::reset()
+{
+ delete d;
+ d = new Q3ProcessPrivate();
+ exitStat = 0;
+ exitNormal = false;
+ d->bufStdout.clear();
+ d->bufStderr.clear();
+}
+
+Q3Membuf* Q3Process::membufStdout()
+{
+ if ( d->proc && d->proc->socketStdout ) {
+ /*
+ Apparently, there is not consistency among different
+ operating systems on how to use FIONREAD.
+
+ FreeBSD, Linux and Solaris all expect the 3rd argument to
+ ioctl() to be an int, which is normally 32-bit even on
+ 64-bit machines.
+
+ IRIX, on the other hand, expects a size_t, which is 64-bit
+ on 64-bit machines.
+
+ So, the solution is to use size_t initialized to zero to
+ make sure all bits are set to zero, preventing underflow
+ with the FreeBSD/Linux/Solaris ioctls.
+ */
+ size_t nbytes = 0;
+ if ( ::ioctl(d->proc->socketStdout, FIONREAD, (char*)&nbytes)==0 && nbytes>0 )
+ socketRead( d->proc->socketStdout );
+ }
+ return &d->bufStdout;
+}
+
+Q3Membuf* Q3Process::membufStderr()
+{
+ if ( d->proc && d->proc->socketStderr ) {
+ /*
+ Apparently, there is not consistency among different
+ operating systems on how to use FIONREAD.
+
+ FreeBSD, Linux and Solaris all expect the 3rd argument to
+ ioctl() to be an int, which is normally 32-bit even on
+ 64-bit machines.
+
+ IRIX, on the other hand, expects a size_t, which is 64-bit
+ on 64-bit machines.
+
+ So, the solution is to use size_t initialized to zero to
+ make sure all bits are set to zero, preventing underflow
+ with the FreeBSD/Linux/Solaris ioctls.
+ */
+ size_t nbytes = 0;
+ if ( ::ioctl(d->proc->socketStderr, FIONREAD, (char*)&nbytes)==0 && nbytes>0 )
+ socketRead( d->proc->socketStderr );
+ }
+ return &d->bufStderr;
+}
+
+Q3Process::~Q3Process()
+{
+ delete d;
+}
+
+bool Q3Process::start( QStringList *env )
+{
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3Process::start()" );
+#endif
+ reset();
+
+ int sStdin[2];
+ int sStdout[2];
+ int sStderr[2];
+
+ // open sockets for piping
+#ifndef Q_OS_QNX6
+ if ( (comms & Stdin) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStdin ) == -1 ) {
+#else
+ if ( (comms & Stdin) && qnx6SocketPairReplacement(sStdin) == -1 ) {
+#endif
+ return false;
+ }
+#ifndef Q_OS_QNX6
+ if ( (comms & Stderr) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStderr ) == -1 ) {
+#else
+ if ( (comms & Stderr) && qnx6SocketPairReplacement(sStderr) == -1 ) {
+#endif
+ if ( comms & Stdin ) {
+ ::close( sStdin[0] );
+ ::close( sStdin[1] );
+ }
+ return false;
+ }
+#ifndef Q_OS_QNX6
+ if ( (comms & Stdout) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStdout ) == -1 ) {
+#else
+ if ( (comms & Stdout) && qnx6SocketPairReplacement(sStdout) == -1 ) {
+#endif
+ if ( comms & Stdin ) {
+ ::close( sStdin[0] );
+ ::close( sStdin[1] );
+ }
+ if ( comms & Stderr ) {
+ ::close( sStderr[0] );
+ ::close( sStderr[1] );
+ }
+ return false;
+ }
+
+ // the following pipe is only used to determine if the process could be
+ // started
+ int fd[2];
+ if ( pipe( fd ) < 0 ) {
+ // non critical error, go on
+ fd[0] = 0;
+ fd[1] = 0;
+ }
+
+ // construct the arguments for exec
+ Q3CString *arglistQ = new Q3CString[ _arguments.count() + 1 ];
+ const char** arglist = new const char*[ _arguments.count() + 1 ];
+ int i = 0;
+ for ( QStringList::Iterator it = _arguments.begin(); it != _arguments.end(); ++it ) {
+ arglistQ[i] = (*it).local8Bit();
+ arglist[i] = arglistQ[i];
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3Process::start(): arg %d = %s", i, arglist[i] );
+#endif
+ i++;
+ }
+#ifdef Q_OS_MACX
+ if(i) {
+ Q3CString arg_bundle = arglistQ[0];
+ QFileInfo fi(QString::fromUtf8(arg_bundle.constData()));
+ if(fi.exists() && fi.isDir() && arg_bundle.right(4) == ".app") {
+ Q3CString exe = arg_bundle;
+ int lslash = exe.findRev('/');
+ if(lslash != -1)
+ exe = exe.mid(lslash+1);
+ exe = Q3CString(arg_bundle + "/Contents/MacOS/" + exe);
+ exe = exe.left(exe.length() - 4); //chop off the .app
+ if(QFile::exists(QString::fromLatin1(exe.constData()))) {
+ arglistQ[0] = exe;
+ arglist[0] = arglistQ[0];
+ }
+ }
+ }
+#endif
+ arglist[i] = 0;
+
+ // Must make sure signal handlers are installed before exec'ing
+ // in case the process exits quickly.
+ if ( d->procManager == 0 ) {
+ d->procManager = new Q3ProcessManager;
+ qAddPostRoutine(q3process_cleanup);
+ }
+
+ // fork and exec
+ QApplication::flushX();
+ pid_t pid = fork();
+ if ( pid == 0 ) {
+ // child
+ d->closeOpenSocketsForChild();
+ if ( comms & Stdin ) {
+ ::close( sStdin[1] );
+ ::dup2( sStdin[0], STDIN_FILENO );
+ }
+ if ( comms & Stdout ) {
+ ::close( sStdout[0] );
+ ::dup2( sStdout[1], STDOUT_FILENO );
+ }
+ if ( comms & Stderr ) {
+ ::close( sStderr[0] );
+ ::dup2( sStderr[1], STDERR_FILENO );
+ }
+ if ( comms & DupStderr ) {
+ ::dup2( STDOUT_FILENO, STDERR_FILENO );
+ }
+#ifndef QT_NO_DIR
+ ::chdir( workingDir.absPath().latin1() );
+#endif
+ if ( fd[0] )
+ ::close( fd[0] );
+ if ( fd[1] )
+ ::fcntl( fd[1], F_SETFD, FD_CLOEXEC ); // close on exec shows success
+
+ if ( env == 0 ) { // inherit environment and start process
+#ifndef Q_OS_QNX4
+ ::execvp( arglist[0], (char*const*)arglist ); // ### cast not nice
+#else
+ ::execvp( arglist[0], (char const*const*)arglist ); // ### cast not nice
+#endif
+ } else { // start process with environment settins as specified in env
+ // construct the environment for exec
+ int numEntries = env->count();
+#if defined(Q_OS_MACX)
+ QString ld_library_path(QLatin1String("DYLD_LIBRARY_PATH"));
+#else
+ QString ld_library_path(QLatin1String("LD_LIBRARY_PATH"));
+#endif
+ bool setLibraryPath =
+ env->grep( QRegExp( QLatin1Char('^') + ld_library_path + QLatin1Char('=') ) ).empty() &&
+ getenv( ld_library_path.local8Bit() ) != 0;
+ if ( setLibraryPath )
+ numEntries++;
+ Q3CString *envlistQ = new Q3CString[ numEntries + 1 ];
+ const char** envlist = new const char*[ numEntries + 1 ];
+ int i = 0;
+ if ( setLibraryPath ) {
+ envlistQ[i] = QString( ld_library_path + QLatin1String("=%1") ).arg( QString::fromLocal8Bit(getenv( ld_library_path.local8Bit() )) ).local8Bit();
+ envlist[i] = envlistQ[i];
+ i++;
+ }
+ for ( QStringList::Iterator it = env->begin(); it != env->end(); ++it ) {
+ envlistQ[i] = (*it).local8Bit();
+ envlist[i] = envlistQ[i];
+ i++;
+ }
+ envlist[i] = 0;
+
+ // look for the executable in the search path
+ if ( _arguments.count()>0 && getenv("PATH")!=0 ) {
+ QString command = _arguments[0];
+ if ( !command.contains( QLatin1Char('/') ) ) {
+ QStringList pathList = QStringList::split( QLatin1Char(':'), QString::fromLocal8Bit(getenv( "PATH" )) );
+ for (QStringList::Iterator it = pathList.begin(); it != pathList.end(); ++it ) {
+ QString dir = *it;
+#if defined(Q_OS_MACX) //look in a bundle
+ if(!QFile::exists(dir + QLatin1Char('/') + command) && QFile::exists(dir + QLatin1Char('/') + command + QLatin1String(".app")))
+ dir += QLatin1Char('/') + command + QLatin1String(".app/Contents/MacOS");
+#endif
+#ifndef QT_NO_DIR
+ QFileInfo fileInfo( dir, command );
+#else
+ QFileInfo fileInfo( dir + "/" + command );
+#endif
+ if ( fileInfo.isExecutable() ) {
+#if defined(Q_OS_MACX)
+ arglistQ[0] = fileInfo.absFilePath().local8Bit();
+#else
+ arglistQ[0] = fileInfo.filePath().local8Bit();
+#endif
+ arglist[0] = arglistQ[0];
+ break;
+ }
+ }
+ }
+ }
+#ifndef Q_OS_QNX4
+ ::execve( arglist[0], (char*const*)arglist, (char*const*)envlist ); // ### casts not nice
+#else
+ ::execve( arglist[0], (char const*const*)arglist,(char const*const*)envlist ); // ### casts not nice
+#endif
+ }
+ if ( fd[1] ) {
+ char buf = 0;
+ ::write( fd[1], &buf, 1 );
+ ::close( fd[1] );
+ }
+ ::_exit( -1 );
+ } else if ( pid == -1 ) {
+ // error forking
+ goto error;
+ }
+
+ // test if exec was successful
+ if ( fd[1] )
+ ::close( fd[1] );
+ if ( fd[0] ) {
+ char buf;
+ for ( ;; ) {
+ int n = ::read( fd[0], &buf, 1 );
+ if ( n==1 ) {
+ // socket was not closed => error
+ if ( ::waitpid( pid, 0, WNOHANG ) != pid ) {
+ // The wait did not succeed yet, so try again when we get
+ // the sigchild (to avoid zombies).
+ d->newProc( pid, 0 );
+ }
+ d->proc = 0;
+ goto error;
+ } else if ( n==-1 ) {
+ if ( errno==EAGAIN || errno==EINTR )
+ // try it again
+ continue;
+ }
+ break;
+ }
+ ::close( fd[0] );
+ }
+
+ d->newProc( pid, this );
+
+ if ( comms & Stdin ) {
+ ::close( sStdin[0] );
+ d->proc->socketStdin = sStdin[1];
+
+ // Select non-blocking mode
+ int originalFlags = fcntl(d->proc->socketStdin, F_GETFL, 0);
+ fcntl(d->proc->socketStdin, F_SETFL, originalFlags | O_NONBLOCK);
+
+ d->notifierStdin = new QSocketNotifier( sStdin[1], QSocketNotifier::Write );
+ connect( d->notifierStdin, SIGNAL(activated(int)),
+ this, SLOT(socketWrite(int)) );
+ // setup notifiers for the sockets
+ if ( !d->stdinBuf.isEmpty() ) {
+ d->notifierStdin->setEnabled( true );
+ }
+ }
+ if ( comms & Stdout ) {
+ ::close( sStdout[1] );
+ d->proc->socketStdout = sStdout[0];
+ d->notifierStdout = new QSocketNotifier( sStdout[0], QSocketNotifier::Read );
+ connect( d->notifierStdout, SIGNAL(activated(int)),
+ this, SLOT(socketRead(int)) );
+ if ( ioRedirection )
+ d->notifierStdout->setEnabled( true );
+ }
+ if ( comms & Stderr ) {
+ ::close( sStderr[1] );
+ d->proc->socketStderr = sStderr[0];
+ d->notifierStderr = new QSocketNotifier( sStderr[0], QSocketNotifier::Read );
+ connect( d->notifierStderr, SIGNAL(activated(int)),
+ this, SLOT(socketRead(int)) );
+ if ( ioRedirection )
+ d->notifierStderr->setEnabled( true );
+ }
+
+ // cleanup and return
+ delete[] arglistQ;
+ delete[] arglist;
+ return true;
+
+error:
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3Process::start(): error starting process" );
+#endif
+ if ( d->procManager )
+ d->procManager->cleanup();
+ if ( comms & Stdin ) {
+ ::close( sStdin[1] );
+ ::close( sStdin[0] );
+ }
+ if ( comms & Stdout ) {
+ ::close( sStdout[0] );
+ ::close( sStdout[1] );
+ }
+ if ( comms & Stderr ) {
+ ::close( sStderr[0] );
+ ::close( sStderr[1] );
+ }
+ ::close( fd[0] );
+ ::close( fd[1] );
+ delete[] arglistQ;
+ delete[] arglist;
+ return false;
+}
+
+
+void Q3Process::tryTerminate() const
+{
+ if ( d->proc != 0 )
+ ::kill( d->proc->pid, SIGTERM );
+}
+
+void Q3Process::kill() const
+{
+ if ( d->proc != 0 )
+ ::kill( d->proc->pid, SIGKILL );
+}
+
+bool Q3Process::isRunning() const
+{
+ if ( d->exitValuesCalculated ) {
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3Process::isRunning(): false (already computed)" );
+#endif
+ return false;
+ }
+ if ( d->proc == 0 )
+ return false;
+ int status;
+ if ( ::waitpid( d->proc->pid, &status, WNOHANG ) == d->proc->pid ) {
+ // compute the exit values
+ Q3Process *that = (Q3Process*)this; // mutable
+ that->exitNormal = WIFEXITED( status ) != 0;
+ if ( exitNormal ) {
+ that->exitStat = (char)WEXITSTATUS( status );
+ }
+ d->exitValuesCalculated = true;
+
+ // On heavy processing, the socket notifier for the sigchild might not
+ // have found time to fire yet.
+ if ( d->procManager && d->procManager->sigchldFd[1] < FD_SETSIZE ) {
+ fd_set fds;
+ struct timeval tv;
+ FD_ZERO( &fds );
+ FD_SET( d->procManager->sigchldFd[1], &fds );
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ if ( ::select( d->procManager->sigchldFd[1]+1, &fds, 0, 0, &tv ) > 0 )
+ d->procManager->sigchldHnd( d->procManager->sigchldFd[1] );
+ }
+
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3Process::isRunning() (PID: %d): false", d->proc->pid );
+#endif
+ return false;
+ }
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3Process::isRunning() (PID: %d): true", d->proc->pid );
+#endif
+ return true;
+}
+
+bool Q3Process::canReadLineStdout() const
+{
+ if ( !d->proc || !d->proc->socketStdout )
+ return d->bufStdout.size() != 0;
+
+ Q3Process *that = (Q3Process*)this;
+ return that->membufStdout()->scanNewline( 0 );
+}
+
+bool Q3Process::canReadLineStderr() const
+{
+ if ( !d->proc || !d->proc->socketStderr )
+ return d->bufStderr.size() != 0;
+
+ Q3Process *that = (Q3Process*)this;
+ return that->membufStderr()->scanNewline( 0 );
+}
+
+void Q3Process::writeToStdin( const QByteArray& buf )
+{
+#if defined(QT_Q3PROCESS_DEBUG)
+// qDebug( "Q3Process::writeToStdin(): write to stdin (%d)", d->socketStdin );
+#endif
+ d->stdinBuf.enqueue( new QByteArray(buf) );
+ if ( d->notifierStdin != 0 )
+ d->notifierStdin->setEnabled( true );
+}
+
+
+void Q3Process::closeStdin()
+{
+ if ( d->proc == 0 )
+ return;
+ if ( d->proc->socketStdin !=0 ) {
+ while ( !d->stdinBuf.isEmpty() ) {
+ delete d->stdinBuf.dequeue();
+ }
+ d->notifierStdin->setEnabled(false);
+ qDeleteInEventHandler(d->notifierStdin);
+ d->notifierStdin = 0;
+ if ( ::close( d->proc->socketStdin ) != 0 ) {
+ qWarning( "Could not close stdin of child process" );
+ }
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3Process::closeStdin(): stdin (%d) closed", d->proc->socketStdin );
+#endif
+ d->proc->socketStdin = 0;
+ }
+}
+
+
+/*
+ This private slot is called when the process has outputted data to either
+ standard output or standard error.
+*/
+void Q3Process::socketRead( int fd )
+{
+ if ( d->socketReadCalled ) {
+ // the slots that are connected to the readyRead...() signals might
+ // trigger a recursive call of socketRead(). Avoid this since you get a
+ // blocking read otherwise.
+ return;
+ }
+
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3Process::socketRead(): %d", fd );
+#endif
+ if ( fd == 0 )
+ return;
+ if ( !d->proc )
+ return;
+ Q3Membuf *buffer = 0;
+ int n;
+ if ( fd == d->proc->socketStdout ) {
+ buffer = &d->bufStdout;
+ } else if ( fd == d->proc->socketStderr ) {
+ buffer = &d->bufStderr;
+ } else {
+ // this case should never happen, but just to be safe
+ return;
+ }
+#if defined(QT_Q3PROCESS_DEBUG)
+ uint oldSize = buffer->size();
+#endif
+
+ // try to read data first (if it fails, the filedescriptor was closed)
+ const int basize = 4096;
+ QByteArray *ba = new QByteArray( basize );
+ n = ::read( fd, ba->data(), basize );
+ if ( n > 0 ) {
+ ba->resize( n );
+ buffer->append( ba );
+ ba = 0;
+ } else {
+ delete ba;
+ ba = 0;
+ }
+ // eof or error?
+ if ( n == 0 || n == -1 ) {
+ if ( fd == d->proc->socketStdout ) {
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3Process::socketRead(): stdout (%d) closed", fd );
+#endif
+ d->notifierStdout->setEnabled( false );
+ qDeleteInEventHandler(d->notifierStdout);
+ d->notifierStdout = 0;
+ ::close( d->proc->socketStdout );
+ d->proc->socketStdout = 0;
+ return;
+ } else if ( fd == d->proc->socketStderr ) {
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3Process::socketRead(): stderr (%d) closed", fd );
+#endif
+ d->notifierStderr->setEnabled( false );
+ qDeleteInEventHandler(d->notifierStderr);
+ d->notifierStderr = 0;
+ ::close( d->proc->socketStderr );
+ d->proc->socketStderr = 0;
+ return;
+ }
+ }
+
+ if ( fd < FD_SETSIZE ) {
+ fd_set fds;
+ struct timeval tv;
+ FD_ZERO( &fds );
+ FD_SET( fd, &fds );
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ while ( ::select( fd+1, &fds, 0, 0, &tv ) > 0 ) {
+ // prepare for the next round
+ FD_ZERO( &fds );
+ FD_SET( fd, &fds );
+ // read data
+ ba = new QByteArray( basize );
+ n = ::read( fd, ba->data(), basize );
+ if ( n > 0 ) {
+ ba->resize( n );
+ buffer->append( ba );
+ ba = 0;
+ } else {
+ delete ba;
+ ba = 0;
+ break;
+ }
+ }
+ }
+
+ d->socketReadCalled = true;
+ if ( fd == d->proc->socketStdout ) {
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3Process::socketRead(): %d bytes read from stdout (%d)",
+ buffer->size()-oldSize, fd );
+#endif
+ emit readyReadStdout();
+ } else if ( fd == d->proc->socketStderr ) {
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3Process::socketRead(): %d bytes read from stderr (%d)",
+ buffer->size()-oldSize, fd );
+#endif
+ emit readyReadStderr();
+ }
+ d->socketReadCalled = false;
+}
+
+
+/*
+ This private slot is called when the process tries to read data from standard
+ input.
+*/
+void Q3Process::socketWrite( int fd )
+{
+ while ( fd == d->proc->socketStdin && d->proc->socketStdin != 0 ) {
+ if ( d->stdinBuf.isEmpty() ) {
+ d->notifierStdin->setEnabled( false );
+ return;
+ }
+ ssize_t ret = ::write( fd,
+ d->stdinBuf.head()->data() + d->stdinBufRead,
+ d->stdinBuf.head()->size() - d->stdinBufRead );
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3Process::socketWrite(): wrote %d bytes to stdin (%d)", ret, fd );
+#endif
+ if ( ret == -1 )
+ return;
+ d->stdinBufRead += ret;
+ if ( d->stdinBufRead == (ssize_t)d->stdinBuf.head()->size() ) {
+ d->stdinBufRead = 0;
+ delete d->stdinBuf.dequeue();
+ if ( wroteToStdinConnected && d->stdinBuf.isEmpty() )
+ emit wroteToStdin();
+ }
+ }
+}
+
+/*!
+ \internal
+ Flushes standard input. This is useful if you want to use Q3Process in a
+ synchronous manner.
+
+ This function should probably go into the public API.
+*/
+void Q3Process::flushStdin()
+{
+ if (d->proc)
+ socketWrite(d->proc->socketStdin);
+}
+
+/*
+ This private slot is only used under Windows (but moc does not know about #if
+ defined()).
+*/
+void Q3Process::timeout()
+{
+}
+
+
+/*
+ This private function is used by connectNotify() and disconnectNotify() to
+ change the value of ioRedirection (and related behaviour)
+*/
+void Q3Process::setIoRedirection( bool value )
+{
+ ioRedirection = value;
+ if ( ioRedirection ) {
+ if ( d->notifierStdout )
+ d->notifierStdout->setEnabled( true );
+ if ( d->notifierStderr )
+ d->notifierStderr->setEnabled( true );
+ } else {
+ if ( d->notifierStdout )
+ d->notifierStdout->setEnabled( false );
+ if ( d->notifierStderr )
+ d->notifierStderr->setEnabled( false );
+ }
+}
+
+/*
+ This private function is used by connectNotify() and
+ disconnectNotify() to change the value of notifyOnExit (and related
+ behaviour)
+*/
+void Q3Process::setNotifyOnExit( bool value )
+{
+ notifyOnExit = value;
+}
+
+/*
+ This private function is used by connectNotify() and disconnectNotify() to
+ change the value of wroteToStdinConnected (and related behaviour)
+*/
+void Q3Process::setWroteStdinConnected( bool value )
+{
+ wroteToStdinConnected = value;
+}
+
+/*!
+ \typedef Q3Process::PID
+ \internal
+*/
+
+Q3Process::PID Q3Process::processIdentifier()
+{
+ if ( d->proc == 0 )
+ return -1;
+ return d->proc->pid;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_PROCESS
diff --git a/src/qt3support/other/q3process_win.cpp b/src/qt3support/other/q3process_win.cpp
new file mode 100644
index 0000000..3c862ee
--- /dev/null
+++ b/src/qt3support/other/q3process_win.cpp
@@ -0,0 +1,676 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qplatformdefs.h"
+#include "q3process.h"
+
+#ifndef QT_NO_PROCESS
+
+#include "qapplication.h"
+#include "q3cstring.h"
+#include "q3ptrqueue.h"
+#include "qtimer.h"
+#include "qregexp.h"
+#include "private/q3membuf_p.h"
+#include "qt_windows.h"
+
+#ifdef Q_OS_WINCE
+#define STARTF_USESTDHANDLES 1
+#endif
+
+QT_BEGIN_NAMESPACE
+
+//#define QT_Q3PROCESS_DEBUG
+
+/***********************************************************************
+ *
+ * Q3ProcessPrivate
+ *
+ **********************************************************************/
+class Q3ProcessPrivate
+{
+public:
+ Q3ProcessPrivate( Q3Process *proc )
+ {
+ stdinBufRead = 0;
+ pipeStdin[0] = 0;
+ pipeStdin[1] = 0;
+ pipeStdout[0] = 0;
+ pipeStdout[1] = 0;
+ pipeStderr[0] = 0;
+ pipeStderr[1] = 0;
+ exitValuesCalculated = false;
+
+ lookup = new QTimer( proc );
+ qApp->connect( lookup, SIGNAL(timeout()),
+ proc, SLOT(timeout()) );
+
+ pid = 0;
+ }
+
+ ~Q3ProcessPrivate()
+ {
+ reset();
+ }
+
+ void reset()
+ {
+ while ( !stdinBuf.isEmpty() ) {
+ delete stdinBuf.dequeue();
+ }
+ closeHandles();
+ stdinBufRead = 0;
+ pipeStdin[0] = 0;
+ pipeStdin[1] = 0;
+ pipeStdout[0] = 0;
+ pipeStdout[1] = 0;
+ pipeStderr[0] = 0;
+ pipeStderr[1] = 0;
+ exitValuesCalculated = false;
+
+ deletePid();
+ }
+
+ void closeHandles()
+ {
+ if( pipeStdin[1] != 0 ) {
+ CloseHandle( pipeStdin[1] );
+ pipeStdin[1] = 0;
+ }
+ if( pipeStdout[0] != 0 ) {
+ CloseHandle( pipeStdout[0] );
+ pipeStdout[0] = 0;
+ }
+ if( pipeStderr[0] != 0 ) {
+ CloseHandle( pipeStderr[0] );
+ pipeStderr[0] = 0;
+ }
+ }
+
+ void deletePid()
+ {
+ if ( pid ) {
+ CloseHandle( pid->hProcess );
+ CloseHandle( pid->hThread );
+ delete pid;
+ pid = 0;
+ }
+ }
+
+ void newPid()
+ {
+ deletePid();
+ pid = new PROCESS_INFORMATION;
+ memset( pid, 0, sizeof(PROCESS_INFORMATION) );
+ }
+
+ Q3Membuf bufStdout;
+ Q3Membuf bufStderr;
+
+ Q3PtrQueue<QByteArray> stdinBuf;
+
+ HANDLE pipeStdin[2];
+ HANDLE pipeStdout[2];
+ HANDLE pipeStderr[2];
+ QTimer *lookup;
+
+ PROCESS_INFORMATION *pid;
+ uint stdinBufRead;
+
+ bool exitValuesCalculated;
+};
+
+
+/***********************************************************************
+ *
+ * Q3Process
+ *
+ **********************************************************************/
+void Q3Process::init()
+{
+ d = new Q3ProcessPrivate( this );
+ exitStat = 0;
+ exitNormal = false;
+}
+
+void Q3Process::reset()
+{
+ d->reset();
+ exitStat = 0;
+ exitNormal = false;
+ d->bufStdout.clear();
+ d->bufStderr.clear();
+}
+
+Q3Membuf* Q3Process::membufStdout()
+{
+ if( d->pipeStdout[0] != 0 )
+ socketRead( 1 );
+ return &d->bufStdout;
+}
+
+Q3Membuf* Q3Process::membufStderr()
+{
+ if( d->pipeStderr[0] != 0 )
+ socketRead( 2 );
+ return &d->bufStderr;
+}
+
+Q3Process::~Q3Process()
+{
+ delete d;
+}
+
+bool Q3Process::start( QStringList *env )
+{
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3Process::start()" );
+#endif
+ reset();
+
+ if ( _arguments.isEmpty() )
+ return false;
+
+ // Open the pipes. Make non-inheritable copies of input write and output
+ // read handles to avoid non-closable handles (this is done by the
+ // DuplicateHandle() call).
+ SECURITY_ATTRIBUTES secAtt = { sizeof( SECURITY_ATTRIBUTES ), NULL, TRUE };
+#ifndef Q_OS_WINCE
+ // I guess there is no stdin stdout and stderr on Q_OS_WINCE to dup
+ // CreatePipe and DupilcateHandle aren't available for Q_OS_WINCE
+ HANDLE tmpStdin, tmpStdout, tmpStderr;
+ if ( comms & Stdin ) {
+ if ( !CreatePipe( &d->pipeStdin[0], &tmpStdin, &secAtt, 0 ) ) {
+ d->closeHandles();
+ return false;
+ }
+ if ( !DuplicateHandle( GetCurrentProcess(), tmpStdin, GetCurrentProcess(), &d->pipeStdin[1], 0, FALSE, DUPLICATE_SAME_ACCESS ) ) {
+ d->closeHandles();
+ return false;
+ }
+ if ( !CloseHandle( tmpStdin ) ) {
+ d->closeHandles();
+ return false;
+ }
+ }
+ if ( comms & Stdout ) {
+ if ( !CreatePipe( &tmpStdout, &d->pipeStdout[1], &secAtt, 0 ) ) {
+ d->closeHandles();
+ return false;
+ }
+ if ( !DuplicateHandle( GetCurrentProcess(), tmpStdout, GetCurrentProcess(), &d->pipeStdout[0], 0, FALSE, DUPLICATE_SAME_ACCESS ) ) {
+ d->closeHandles();
+ return false;
+ }
+ if ( !CloseHandle( tmpStdout ) ) {
+ d->closeHandles();
+ return false;
+ }
+ }
+ if ( comms & Stderr ) {
+ if ( !CreatePipe( &tmpStderr, &d->pipeStderr[1], &secAtt, 0 ) ) {
+ d->closeHandles();
+ return false;
+ }
+ if ( !DuplicateHandle( GetCurrentProcess(), tmpStderr, GetCurrentProcess(), &d->pipeStderr[0], 0, FALSE, DUPLICATE_SAME_ACCESS ) ) {
+ d->closeHandles();
+ return false;
+ }
+ if ( !CloseHandle( tmpStderr ) ) {
+ d->closeHandles();
+ return false;
+ }
+ }
+ if ( comms & DupStderr ) {
+ CloseHandle( d->pipeStderr[1] );
+ d->pipeStderr[1] = d->pipeStdout[1];
+ }
+#endif
+
+ // construct the arguments for CreateProcess()
+ QString args;
+ QString appName;
+ QStringList::Iterator it = _arguments.begin();
+ args = *it;
+ ++it;
+ if ( args.endsWith( QLatin1String(".bat") ) && args.contains( QLatin1Char(' ') ) ) {
+ // CreateProcess() seems to have a strange semantics (see also
+ // http://www.experts-exchange.com/Programming/Programming_Platforms/Win_Prog/Q_11138647.html):
+ // If you start a batch file with spaces in the filename, the first
+ // argument to CreateProcess() must be the name of the batchfile
+ // without quotes, but the second argument must start with the same
+ // argument with quotes included. But if the same approach is used for
+ // .exe files, it doesn't work.
+ appName = args;
+ args = QLatin1Char('"') + args + QLatin1Char('"');
+ }
+ for ( ; it != _arguments.end(); ++it ) {
+ QString tmp = *it;
+ // escape a single " because the arguments will be parsed
+ tmp.replace( QLatin1String("\""), QLatin1String("\\\"") );
+ if ( tmp.isEmpty() || tmp.contains( QLatin1Char(' ') ) || tmp.contains( QLatin1Char('\t') ) ) {
+ // The argument must not end with a \ since this would be interpreted
+ // as escaping the quote -- rather put the \ behind the quote: e.g.
+ // rather use "foo"\ than "foo\"
+ QString endQuote( QLatin1String("\"") );
+ int i = tmp.length();
+ while ( i>0 && tmp.at( i-1 ) == QLatin1Char('\\') ) {
+ --i;
+ endQuote += QLatin1String("\\");
+ }
+ args += QString( QLatin1String(" \"") ) + tmp.left( i ) + endQuote;
+ } else {
+ args += QLatin1Char(' ') + tmp;
+ }
+ }
+#if defined(QT_Q3PROCESS_DEBUG)
+ qDebug( "Q3Process::start(): args [%s]", args.latin1() );
+#endif
+
+ // CreateProcess()
+ bool success;
+ d->newPid();
+#ifdef UNICODE
+ if (!(QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based)) {
+ STARTUPINFOW startupInfo = {
+ sizeof( STARTUPINFO ), 0, 0, 0,
+ (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
+ 0, 0, 0,
+ STARTF_USESTDHANDLES,
+ 0, 0, 0,
+ d->pipeStdin[0], d->pipeStdout[1], d->pipeStderr[1]
+ };
+ TCHAR *applicationName;
+ if ( appName.isNull() )
+ applicationName = 0;
+ else
+ applicationName = _wcsdup( (TCHAR*)appName.ucs2() );
+ TCHAR *commandLine = _wcsdup( (TCHAR*)args.ucs2() );
+ QByteArray envlist;
+ if ( env != 0 ) {
+ int pos = 0;
+ // add PATH if necessary (for DLL loading)
+ QByteArray path = qgetenv( "PATH" );
+ if ( env->grep( QRegExp(QLatin1String("^PATH="),FALSE) ).empty() && !path.isNull() ) {
+ QString tmp = QString( QLatin1String("PATH=%1") ).arg(QString::fromLatin1(path.constData()));
+ uint tmpSize = sizeof(TCHAR) * (tmp.length()+1);
+ envlist.resize( envlist.size() + tmpSize );
+ memcpy( envlist.data()+pos, tmp.ucs2(), tmpSize );
+ pos += tmpSize;
+ }
+ // add the user environment
+ for ( QStringList::Iterator it = env->begin(); it != env->end(); it++ ) {
+ QString tmp = *it;
+ uint tmpSize = sizeof(TCHAR) * (tmp.length()+1);
+ envlist.resize( envlist.size() + tmpSize );
+ memcpy( envlist.data()+pos, tmp.ucs2(), tmpSize );
+ pos += tmpSize;
+ }
+ // add the 2 terminating 0 (actually 4, just to be on the safe side)
+ envlist.resize( envlist.size()+4 );
+ envlist[pos++] = 0;
+ envlist[pos++] = 0;
+ envlist[pos++] = 0;
+ envlist[pos++] = 0;
+ }
+ success = CreateProcessW( applicationName, commandLine,
+ 0, 0, TRUE, ( comms==0 ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW )
+#ifndef Q_OS_WINCE
+ | CREATE_UNICODE_ENVIRONMENT
+#endif
+ , env==0 ? 0 : envlist.data(),
+ (TCHAR*)QDir::toNativeSeparators(workingDir.absPath()).ucs2(),
+ &startupInfo, d->pid );
+ free( applicationName );
+ free( commandLine );
+ } else
+#endif // UNICODE
+ {
+#ifndef Q_OS_WINCE
+ STARTUPINFOA startupInfo = { sizeof( STARTUPINFOA ), 0, 0, 0,
+ (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
+ 0, 0, 0,
+ STARTF_USESTDHANDLES,
+ 0, 0, 0,
+ d->pipeStdin[0], d->pipeStdout[1], d->pipeStderr[1]
+ };
+ QByteArray envlist;
+ if ( env != 0 ) {
+ int pos = 0;
+ // add PATH if necessary (for DLL loading)
+ QByteArray path = qgetenv( "PATH" );
+ if ( env->grep( QRegExp(QLatin1String("^PATH="),FALSE) ).empty() && !path.isNull() ) {
+ Q3CString tmp = QString( QLatin1String("PATH=%1") ).arg(QString::fromLatin1(path.constData())).local8Bit();
+ uint tmpSize = tmp.length() + 1;
+ envlist.resize( envlist.size() + tmpSize );
+ memcpy( envlist.data()+pos, tmp.data(), tmpSize );
+ pos += tmpSize;
+ }
+ // add the user environment
+ for ( QStringList::Iterator it = env->begin(); it != env->end(); it++ ) {
+ Q3CString tmp = (*it).local8Bit();
+ uint tmpSize = tmp.length() + 1;
+ envlist.resize( envlist.size() + tmpSize );
+ memcpy( envlist.data()+pos, tmp.data(), tmpSize );
+ pos += tmpSize;
+ }
+ // add the terminating 0 (actually 2, just to be on the safe side)
+ envlist.resize( envlist.size()+2 );
+ envlist[pos++] = 0;
+ envlist[pos++] = 0;
+ }
+ char *applicationName;
+ if ( appName.isNull() )
+ applicationName = 0;
+ else
+ applicationName = const_cast<char *>(appName.toLocal8Bit().data());
+ success = CreateProcessA( applicationName,
+ const_cast<char *>(args.toLocal8Bit().data()),
+ 0, 0, TRUE, comms==0 ? CREATE_NEW_CONSOLE : DETACHED_PROCESS,
+ env==0 ? 0 : envlist.data(),
+ (const char*)QDir::toNativeSeparators(workingDir.absPath()).local8Bit(),
+ &startupInfo, d->pid );
+#endif // Q_OS_WINCE
+ }
+ if ( !success ) {
+ d->deletePid();
+ return false;
+ }
+
+#ifndef Q_OS_WINCE
+ if ( comms & Stdin )
+ CloseHandle( d->pipeStdin[0] );
+ if ( comms & Stdout )
+ CloseHandle( d->pipeStdout[1] );
+ if ( (comms & Stderr) && !(comms & DupStderr) )
+ CloseHandle( d->pipeStderr[1] );
+#endif
+
+ if ( ioRedirection || notifyOnExit ) {
+ d->lookup->start( 100 );
+ }
+
+ // cleanup and return
+ return true;
+}
+
+static BOOL CALLBACK qt_terminateApp( HWND hwnd, LPARAM procId )
+{
+ DWORD procId_win;
+ GetWindowThreadProcessId( hwnd, &procId_win );
+ if( procId_win == (DWORD)procId )
+ PostMessage( hwnd, WM_CLOSE, 0, 0 );
+
+ return TRUE;
+}
+
+void Q3Process::tryTerminate() const
+{
+ if ( d->pid )
+ EnumWindows( qt_terminateApp, (LPARAM)d->pid->dwProcessId );
+}
+
+void Q3Process::kill() const
+{
+ if ( d->pid )
+ TerminateProcess( d->pid->hProcess, 0xf291 );
+}
+
+bool Q3Process::isRunning() const
+{
+ if ( !d->pid )
+ return false;
+
+ if ( WaitForSingleObject( d->pid->hProcess, 0) == WAIT_OBJECT_0 ) {
+ // there might be data to read
+ Q3Process *that = (Q3Process*)this;
+ that->socketRead( 1 ); // try stdout
+ that->socketRead( 2 ); // try stderr
+ // compute the exit values
+ if ( !d->exitValuesCalculated ) {
+ DWORD exitCode;
+ if ( GetExitCodeProcess( d->pid->hProcess, &exitCode ) ) {
+ if ( exitCode != STILL_ACTIVE ) { // this should ever be true?
+ that->exitNormal = exitCode != 0xf291;
+ that->exitStat = exitCode;
+ }
+ }
+ d->exitValuesCalculated = true;
+ }
+ d->deletePid();
+ d->closeHandles();
+ return false;
+ } else {
+ return true;
+ }
+}
+
+bool Q3Process::canReadLineStdout() const
+{
+ if( !d->pipeStdout[0] )
+ return d->bufStdout.size() != 0;
+
+ Q3Process *that = (Q3Process*)this;
+ return that->membufStdout()->scanNewline( 0 );
+}
+
+bool Q3Process::canReadLineStderr() const
+{
+ if( !d->pipeStderr[0] )
+ return d->bufStderr.size() != 0;
+
+ Q3Process *that = (Q3Process*)this;
+ return that->membufStderr()->scanNewline( 0 );
+}
+
+void Q3Process::writeToStdin( const QByteArray& buf )
+{
+ d->stdinBuf.enqueue( new QByteArray(buf) );
+ socketWrite( 0 );
+}
+
+void Q3Process::closeStdin( )
+{
+ if ( d->pipeStdin[1] != 0 ) {
+ CloseHandle( d->pipeStdin[1] );
+ d->pipeStdin[1] = 0;
+ }
+}
+
+void Q3Process::socketRead( int fd )
+{
+ // fd == 1: stdout, fd == 2: stderr
+ HANDLE dev;
+ if ( fd == 1 ) {
+ dev = d->pipeStdout[0];
+ } else if ( fd == 2 ) {
+ dev = d->pipeStderr[0];
+ } else {
+ return;
+ }
+#ifndef Q_OS_WINCE
+ // get the number of bytes that are waiting to be read
+ unsigned long i, r;
+ char dummy;
+ if ( !PeekNamedPipe( dev, &dummy, 1, &r, &i, 0 ) ) {
+ return; // ### is it worth to dig for the reason of the error?
+ }
+#else
+ unsigned long i = 1000;
+#endif
+ if ( i > 0 ) {
+ Q3Membuf *buffer;
+ if ( fd == 1 )
+ buffer = &d->bufStdout;
+ else
+ buffer = &d->bufStderr;
+
+ QByteArray *ba = new QByteArray( i );
+ uint sz = readStddev( dev, ba->data(), i );
+ if ( sz != i )
+ ba->resize( i );
+
+ if ( sz == 0 ) {
+ delete ba;
+ return;
+ }
+ buffer->append( ba );
+ if ( fd == 1 )
+ emit readyReadStdout();
+ else
+ emit readyReadStderr();
+ }
+}
+
+void Q3Process::socketWrite( int )
+{
+ DWORD written;
+ while ( !d->stdinBuf.isEmpty() && isRunning() ) {
+ if ( !WriteFile( d->pipeStdin[1],
+ d->stdinBuf.head()->data() + d->stdinBufRead,
+ qMin( 8192, int(d->stdinBuf.head()->size() - d->stdinBufRead) ),
+ &written, 0 ) ) {
+ d->lookup->start( 100 );
+ return;
+ }
+ d->stdinBufRead += written;
+ if ( d->stdinBufRead == (DWORD)d->stdinBuf.head()->size() ) {
+ d->stdinBufRead = 0;
+ delete d->stdinBuf.dequeue();
+ if ( wroteToStdinConnected && d->stdinBuf.isEmpty() )
+ emit wroteToStdin();
+ }
+ }
+}
+
+void Q3Process::flushStdin()
+{
+ socketWrite( 0 );
+}
+
+/*
+ Use a timer for polling misc. stuff.
+*/
+void Q3Process::timeout()
+{
+ // Disable the timer temporary since one of the slots that are connected to
+ // the readyRead...(), etc. signals might trigger recursion if
+ // processEvents() is called.
+ d->lookup->stop();
+
+ // try to write pending data to stdin
+ if ( !d->stdinBuf.isEmpty() )
+ socketWrite( 0 );
+
+ if ( ioRedirection ) {
+ socketRead( 1 ); // try stdout
+ socketRead( 2 ); // try stderr
+ }
+
+ if ( isRunning() ) {
+ // enable timer again, if needed
+ if ( !d->stdinBuf.isEmpty() || ioRedirection || notifyOnExit )
+ d->lookup->start( 100 );
+ } else if ( notifyOnExit ) {
+ emit processExited();
+ }
+}
+
+/*
+ read on the pipe
+*/
+uint Q3Process::readStddev( HANDLE dev, char *buf, uint bytes )
+{
+ if ( bytes > 0 ) {
+ ulong r;
+ if ( ReadFile( dev, buf, bytes, &r, 0 ) )
+ return r;
+ }
+ return 0;
+}
+
+/*
+ Used by connectNotify() and disconnectNotify() to change the value of
+ ioRedirection (and related behaviour)
+*/
+void Q3Process::setIoRedirection( bool value )
+{
+ ioRedirection = value;
+ if ( !ioRedirection && !notifyOnExit )
+ d->lookup->stop();
+ if ( ioRedirection ) {
+ if ( isRunning() )
+ d->lookup->start( 100 );
+ }
+}
+
+/*
+ Used by connectNotify() and disconnectNotify() to change the value of
+ notifyOnExit (and related behaviour)
+*/
+void Q3Process::setNotifyOnExit( bool value )
+{
+ notifyOnExit = value;
+ if ( !ioRedirection && !notifyOnExit )
+ d->lookup->stop();
+ if ( notifyOnExit ) {
+ if ( isRunning() )
+ d->lookup->start( 100 );
+ }
+}
+
+/*
+ Used by connectNotify() and disconnectNotify() to change the value of
+ wroteToStdinConnected (and related behaviour)
+*/
+void Q3Process::setWroteStdinConnected( bool value )
+{
+ wroteToStdinConnected = value;
+}
+
+Q3Process::PID Q3Process::processIdentifier()
+{
+ return d->pid;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_PROCESS
diff --git a/src/qt3support/other/qiconset.h b/src/qt3support/other/qiconset.h
new file mode 100644
index 0000000..5bfc902
--- /dev/null
+++ b/src/qt3support/other/qiconset.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qicon.h>
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3Support)
+
+QT_END_NAMESPACE
diff --git a/src/qt3support/other/qt_compat_pch.h b/src/qt3support/other/qt_compat_pch.h
new file mode 100644
index 0000000..2b03003
--- /dev/null
+++ b/src/qt3support/other/qt_compat_pch.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ * This is a precompiled header file for use in Xcode / Mac GCC /
+ * GCC >= 3.4 / VC to greatly speed the building of Qt. It may also be
+ * of use to people developing their own project, but it is probably
+ * better to define your own header. Use of this header is currently
+ * UNSUPPORTED.
+ */
+
+#if defined __cplusplus
+#include <qapplication.h>
+#include <qbitmap.h>
+#include <qcursor.h>
+#include <qdesktopwidget.h>
+#include <qevent.h>
+#include <qimage.h>
+#include <qlayout.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qstring.h>
+#include <qstyle.h>
+#include <qtimer.h>
+#include <qwidget.h>
+
+#include <stdlib.h>
+#endif