diff options
Diffstat (limited to 'tqt/kqt3.cpp')
-rw-r--r-- | tqt/kqt3.cpp | 671 |
1 files changed, 671 insertions, 0 deletions
diff --git a/tqt/kqt3.cpp b/tqt/kqt3.cpp new file mode 100644 index 0000000..962f72a --- /dev/null +++ b/tqt/kqt3.cpp @@ -0,0 +1,671 @@ +/************************************************************************ + * + * All dialogs opened are created and used modal. + * + ************************************************************************ + * (C) Craig Drummond, 2006 + ************************************************************************ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + ************************************************************************/ + +#define KTQT_OVERLOAD_NON_STATIC_FILEDIALOGS + +#define _GNU_SOURCE +#include <dlfcn.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <signal.h> +#include <sys/wait.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <pwd.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <tqstring.h> +#include <tqstringlist.h> +#include <tqwidget.h> +#include <tqapplication.h> +#ifdef KTQT_OVERLOAD_NON_STATIC_FILEDIALOGS +#include <tqcombobox.h> +#include <tqlineedit.h> +#include <tqobjectlist.h> +#define private public // HACK HACK HACK!!! +#endif +#include <tqfiledialog.h> +#include <tqthread.h> +#include <tqnamespace.h> +#include <tqeventloop.h> +#include "connect.h" +#include "config.h" +#include "mangled.h" + +static bool useKde=false; + +#define MAX_LINE_LEN 1024 +#define MAX_APP_NAME_LEN 32 + +static char * getAppNameFromPid(int pid) +{ + static char appName[MAX_APP_NAME_LEN+1]="\0"; + + int procFile=-1; + char cmdline[MAX_LINE_LEN+1]; + + sprintf(cmdline, "/proc/%d/cmdline",pid); + + if(-1!=(procFile=open(cmdline, O_RDONLY))) + { + if(read(procFile, cmdline, MAX_LINE_LEN)>7) + { + int len=strlen(cmdline), + pos=0; + + for(pos=len-1; pos>0 && cmdline[pos] && cmdline[pos]!='/'; --pos) + ; + + if(pos>=0 && pos<len) + { + strncpy(appName, &cmdline[pos ? pos+1 : 0], MAX_APP_NAME_LEN); + appName[MAX_APP_NAME_LEN]='\0'; + } + } + close(procFile); + } + + return appName; +} + +static const char * getAppName(bool useTQt=true) +{ + static const char *appName=NULL; + + if(!appName) + { + const char *a=useTQt && tqApp ? tqApp->argv()[0] : getAppNameFromPid(getpid()); + const char *slash; + + // Was the cmdline app java? if so, try to use its parent name - just in case + // its run from a shell script, etc. - e.g. as eclipse does + if(a && 0==strcmp(a, "java")) + a=getAppNameFromPid(getppid()); + + if(a && a[0]=='\0') + a=NULL; + + appName=a && (slash=strrchr(a, '/')) && '\0'!=slash[1] + ? &(slash[1]) + : a ? a : "TQtApp"; + } + + return appName; +} + +int TQApplication::exec() +{ + static bool init=false; + + if(!init) + { + connectToKDialogD(getAppName(false)); + init=true; + } + + static int (*realFunction)(void *); + + if(!realFunction) + realFunction = (int (*)(void *)) dlsym(RTLD_NEXT, KQT_QAPPLICATION_EXEC); + return (int)realFunction(this); +}; + +static TQString qt2KdeFilter(const TQString &f) +{ + TQString filter; + TQTextOStream str(&filter); + TQStringList list(TQStringList::split(";;", f)); + TQStringList::Iterator it(list.begin()), + end(list.end()); + bool first=true; + + for(; it!=end; ++it) + { + int ob=(*it).findRev('('), + cb=(*it).findRev(')'); + + if(-1!=cb && ob<cb) + { + if(first) + first=false; + else + str << '\n'; + str << (*it).mid(ob+1, (cb-ob)-1) << '|' << (*it).mid(0, ob); + } + } + + return filter; +} + +static void kde2TQtFilter(const TQString &orig, TQString *sel) +{ + if(sel) + { + TQStringList list(TQStringList::split(";;", orig)); + TQStringList::Iterator it(list.begin()), + end(list.end()); + int pos; + + for(; it!=end; ++it) + if(-1!=(pos=(*it).find(*sel)) && pos>0 && + ('('==(*it)[pos-1] || ' '==(*it)[pos-1]) && + (*it).length()>=sel->length()+pos && + (')'==(*it)[pos+sel->length()] || ' '==(*it)[pos+sel->length()])) + { + *sel=*it; + return; + } + } +} + +#ifdef KTQT_OVERLOAD_NON_STATIC_FILEDIALOGS +#ifdef KTQT_USE_TQFILEDIALOG_PRIVATE +// HACK HACK HACK!!! + +// KGtk versions <=0.9.1 used this copied TQFileDialogPrivate to access the file filters +// newer versions walk the file dialogs tqchildren... +class TQFileDialogPrivate { +public: + ~TQFileDialogPrivate(); + + TQStringList history; + + bool geometryDirty; + TQComboBox * paths; + TQComboBox * types; +}; +#endif + +static const TQString getFilters(TQFileDialog *dlg, bool scribusSave=false) +{ + TQString filter; + +#if KTQT_USE_TQFILEDIALOG_PRIVATE + if(dlg && dlg->d && dlg->d->types) + { + TQTextOStream str(&filter); + + for(int i=0; i<dlg->d->types->count(); ++i) + { + if(i) + str << ";;"; + + if(scribusSave && -1!=dlg->d->types->text(i).find("(*.sla *.sla.gz *.scd *scd.gz)")) + str << "Compressed Documents (*.sla.gz *scd.gz);;Documents (*.sla *.scd)"; + else + str << dlg->d->types->text(i); + } + } +#else + if(dlg) + { + const TQObjectList tqchildren=((TQObject *)dlg)->childrenListObject(); + + if(!tqchildren.isEmpty()) + { + TQObjectList::ConstIterator it(tqchildren.begin()), + end(tqchildren.end()); + + for(; it!=end; ++it) + if(::tqqt_cast<TQComboBox *>(*it) && 0==qstrcmp((*it)->name(), "file types")) + { + TQComboBox *types=(TQComboBox *)(*it); + TQTextOStream str(&filter); + + for(int i=0; i<types->count(); ++i) + { + if(i) + str << ";;"; + + if(scribusSave && -1!=types->text(i).find("(*.sla *.sla.gz *.scd *scd.gz)")) + str << "Compressed Documents (*.sla.gz *scd.gz);;Documents (*.sla *.scd)"; + else + str << types->text(i); + } + + break; + } + } + } +#endif + + return filter; +} + +static TQString getCurrentFileName(TQFileDialog *dlg) +{ + if(dlg) + { + const TQObjectList tqchildren=((TQObject *)dlg)->childrenListObject(); + + if(!tqchildren.isEmpty()) + { + TQObjectList::ConstIterator it(tqchildren.begin()), + end(tqchildren.end()); + + for(; it!=end; ++it) + if(::tqqt_cast<TQLineEdit *>(*it)) // && 0==qstrcmp((*it)->name(), "name/filter editor")) + return ((TQLineEdit *)(*it))->text(); + } + } + + return TQString(); +} + +static TQString getDir(const TQString &f) +{ + TQString d(f); + + int slashPos=d.findRev('/'); + + if(slashPos!=-1) + d.remove(slashPos+1, d.length()); + + return d; +} +#endif + +static bool writeString(int fd, const TQString &str) +{ + TQCString utf8(str.utf8()); + int size=utf8.length()+1; + + return writeBlock(fd, (char *)&size, 4) && writeBlock(fd, utf8.data(), size); +} + +static bool writeBool(int fd, bool b) +{ + char bv=b ? 1 : 0; + + return writeBlock(fd, (char *)&bv, 1); +} + +class KTQtDialog : public TQDialog +{ + public: + + KTQtDialog(TQWidget *parent) : TQDialog(parent, "kqt", true, WStyle_NoBorder|WX11BypassWM) + { + resize(1, 1); + setWindowOpacity(0.0); + setWindowState(WState_Minimized); + move(32768, 32768); + } + +/* void r() { TQDialog::reject(); }*/ +}; + +class KTQtThread : public TQThread +{ + public: + + KTQtThread(TQStringList &l, TQString &s, int f, KTQtDialog *dlg) : dialog(dlg), kdialogdError(false), res(l), selFilter(s), fd(f) + { } + + bool readData(TQCString &buffer, int size) + { + buffer.resize(size); + return ::readBlock(fd, buffer.data(), size); + } + + bool readString(TQString &str, int size) + { + TQCString buffer; + buffer.resize(size); + + if(!readBlock(fd, buffer.data(), size)) + return false; + + str=TQString::fromUtf8(buffer.data()); + return true; + } + + void run() + { + TQString buffer; + int num=0; + + if(readBlock(fd, (char *)&num, 4)) + { + int n; + + for(n=0; n<num && !kdialogdError; ++n) + { + int size=0; + + if(readBlock(fd, (char *)&size, 4)) + { + if(size>0) + { + if(readString(buffer, size)) + { + //buffer[size-1]='\0'; + if('/'==buffer[0]) + res.append(buffer); + else + selFilter=buffer; + } + else + kdialogdError=true; + } + } + else + kdialogdError=true; + } + } + else + kdialogdError=true; + + TQApplication::postEvent(dialog, new TQCloseEvent); + } + + KTQtDialog *dialog; + bool kdialogdError; + TQStringList &res; + TQString &selFilter; + int fd; +}; + +static bool sendMessage(TQWidget *parent, Operation op, TQStringList &res, TQString &selFilter, + const TQString &title, const TQString &p1, const TQString *p2, bool ow) +{ + if(connectToKDialogD(getAppName())) + { + char o=(char)op; + int xid=parent ? parent->tqtopLevelWidget()->winId() : tqApp->activeWindow()->winId(); + + if(writeBlock(kdialogdSocket, &o, 1) && + writeBlock(kdialogdSocket, (char *)&xid, 4) && + writeString(kdialogdSocket, title) && + writeString(kdialogdSocket, p1) && + (p2? writeString(kdialogdSocket, *p2) : true) && + (OP_FILE_SAVE==op ? writeBool(kdialogdSocket, ow) : true)) + { + KTQtDialog dlg(parent); + KTQtThread thread(res, selFilter, kdialogdSocket, &dlg); + + thread.start(); + dlg.exec(); + thread.wait(); + if(thread.kdialogdError) + { + closeConnection(); + return false; + } + return true; + } + } + + return false; +} + +static TQString getTitle(const TQString &title, Operation op) +{ + if(!title.isEmpty()) + return title; + + return "."; +} + +static bool openKdeDialog(TQWidget *widget, const TQString &title, const TQString &p1, const TQString *p2, + Operation op, TQStringList &res, TQString *selFilter, bool ow=false) +{ + TQString filter; + bool rv=sendMessage(widget, op, res, filter, getTitle(title, op), p1, p2, ow); + + // If we failed to talk to, or start kdialogd, then dont keep trying - just fall back to TQt + if(!rv) + /*useKde=false*/; + else if(selFilter) + *selFilter=filter; + + return rv; +} + +static void kqtExit() +{ + if(useKde) + closeConnection(); +} + +static bool kqtInit() +{ + static bool initialised=false; + + if(!initialised) + { + initialised=true; + useKde=NULL!=getenv("TDE_FULL_SESSION") && connectToKDialogD(getAppName()); + if(useKde) + atexit(&kqtExit); + } + + return useKde; +} + +static TQString lastDir; + +static void storeLastDir(const TQString &f) +{ + lastDir=f; + + int slashPos(lastDir.findRev('/')); + + if(slashPos!=-1) + lastDir.remove(slashPos+1, lastDir.length()); +} + +static const TQString & startDir(const TQString &d) +{ + return d.isEmpty() ? lastDir : d; +} + +TQString TQFileDialog::getOpenFileName(const TQString &initially, const TQString &filter, + TQWidget *parent, const char *name, const TQString &caption, + TQString *selectedFilter, bool resolveSymlinks) +{ + TQStringList res; + TQString f(qt2KdeFilter(filter)); + kqtInit(); + + if(openKdeDialog(parent, caption, startDir(initially), &f, OP_FILE_OPEN, res, selectedFilter)) + { + kde2TQtFilter(filter, selectedFilter); + TQString fn(res.first()); + + storeLastDir(fn); + return fn; + } + return TQString(); +} + +TQString TQFileDialog::getSaveFileName(const TQString &initially, const TQString &filter, TQWidget *parent, + const char *name, const TQString &caption, + TQString *selectedFilter, bool resolveSymlinks) +{ + TQStringList res; + TQString f(qt2KdeFilter(filter)); + kqtInit(); + + if (openKdeDialog(parent, caption, startDir(initially), &f, OP_FILE_SAVE, res, selectedFilter)) + { + kde2TQtFilter(filter, selectedFilter); + TQString fn(res.first()); + + storeLastDir(fn); + return fn; + } + return TQString(); +} + +TQString TQFileDialog::getExistingDirectory(const TQString &dir, TQWidget *parent, const char *name, + const TQString &caption, bool dirOnly, bool resolveSymlinks) +{ + TQStringList res; + TQString dummy; + + kqtInit(); + + return openKdeDialog(parent, caption, dir, NULL, OP_FOLDER, res, &dummy) + ? res.first() + : TQString(); +} + +TQStringList TQFileDialog::getOpenFileNames(const TQString &filter, const TQString &dir, TQWidget *parent, + const char *name, const TQString &caption, + TQString *selectedFilter, bool resolveSymlinks) +{ + TQStringList res; + TQString f(qt2KdeFilter(filter)); + kqtInit(); + + openKdeDialog(parent, caption, startDir(dir), &f, OP_FILE_OPEN_MULTIPLE, res, selectedFilter); + + if(res.count()) + { + kde2TQtFilter(filter, selectedFilter); + storeLastDir(res.first()); + } + return res; +} + +#ifdef KTQT_OVERLOAD_NON_STATIC_FILEDIALOGS +static TQString getFile(const TQString &f) +{ + TQString d(f); + + int slashPos=d.findRev('/'); + + if(slashPos!=-1) + d.remove(0, slashPos+1); + + return d; +} + +int TQDialog::exec() +{ + int res=TQDialog::Rejected; + + if(inherits("TQFileDialog")) + { + TQFileDialog *that=(TQFileDialog *)this; + + const TQDir *dirp=that->dir(); + TQString dir, + selectedFilter, + file, + initialDir(dirp ? dirp->absPath() : TQDir::homeDirPath()); + TQStringList files; + + if(dirp) + delete dirp; + + TQApplication::eventLoop()->processEvents(TQEventLoop::ExcludeUserInput, 1); + switch(that->mode()) + { + case TQFileDialog::Directory: + case TQFileDialog::DirectoryOnly: + dir=TQFileDialog::getExistingDirectory(initialDir, parentWidget(), NULL, + caption(), true, true); + + if(!dir.isEmpty()) + res=TQDialog::Accepted; + break; + case TQFileDialog::AnyFile: + { + TQString app(getFile(tqApp->argv()[0])), + initialFile(getCurrentFileName(that)); + + if(!initialFile.isEmpty()) + initialDir=initialDir+TQChar('/')+initialFile; + + file=TQFileDialog::getSaveFileName(initialDir, + getFilters(that, "scribus"==app || + "scribus-ng"==app), + parentWidget(), NULL, caption(), &selectedFilter, + true); + + if(!file.isEmpty()) + res=TQDialog::Accepted; + break; + } + case TQFileDialog::ExistingFile: + file=TQFileDialog::getOpenFileName(initialDir, getFilters(that), parentWidget(), + NULL, caption(), &selectedFilter, true); + + if(!file.isEmpty()) + res=TQDialog::Accepted; + break; + case TQFileDialog::ExistingFiles: + files=TQFileDialog::getOpenFileNames(getFilters(that), initialDir, parentWidget(), + NULL, caption(), &selectedFilter, true); + + if(files.count()) + res=TQDialog::Accepted; + break; + } + + if(TQDialog::Accepted==res) + { + if(file.isEmpty() && files.count()) + file=files.first(); + if(dir.isEmpty() && !file.isEmpty()) + dir=getDir(file); + if(!dir.isEmpty()) + that->setDir(dir); + if(!selectedFilter.isEmpty()) + that->setSelectedFilter(selectedFilter); + if(!file.isEmpty()) + that->setSelection(file); + + if(files.count() && that->nameEdit) + { + TQStringList::Iterator it(files.begin()), + end(files.end()); + TQString filesStr; + TQTextOStream str(&filesStr); + + for(; it!=end; ++it) + str << "\"" << (*it) << "\" "; + that->nameEdit->setText(filesStr); + } + TQApplication::eventLoop()->processEvents(TQEventLoop::ExcludeUserInput, 1); + } + } + else + { + static int (*realFunction)(void *); + + if(!realFunction) + realFunction = (int (*)(void *)) dlsym(RTLD_NEXT, KQT_QDIALOG_EXEC); + return (int)realFunction(this); + } + + return res; +} +#endif |