/************************************************************************ * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef KTQT_OVERLOAD_NON_STATIC_FILEDIALOGS #include #include #include #define private public // HACK HACK HACK!!! #endif #include #include #include #include #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 && posargv()[0] : getAppNameFromPid(getpid()); const char *slash; // Was the cmdline app java? if so, try to use its tqparent 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).tqfindRev('('), cb=(*it).tqfindRev(')'); if(-1!=cb && ob0 && ('('==(*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 tqgeometryDirty; 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; id->types->count(); ++i) { if(i) str << ";;"; if(scribusSave && -1!=dlg->d->types->text(i).tqfind("(*.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(*it) && 0==qstrcmp((*it)->name(), "file types")) { TQComboBox *types=(TQComboBox *)(*it); TQTextOStream str(&filter); for(int i=0; icount(); ++i) { if(i) str << ";;"; if(scribusSave && -1!=types->text(i).tqfind("(*.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(*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.tqfindRev('/'); 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 *tqparent) : TQDialog(tqparent, "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; n0) { 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 *tqparent, 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=tqparent ? tqparent->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(tqparent); 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("KDE_FULL_SESSION") && connectToKDialogD(getAppName()); if(useKde) atexit(&kqtExit); } return useKde; } static TQString lastDir; static void storeLastDir(const TQString &f) { lastDir=f; int slashPos(lastDir.tqfindRev('/')); 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 *tqparent, const char *name, const TQString &caption, TQString *selectedFilter, bool resolveSymlinks) { TQStringList res; TQString f(qt2KdeFilter(filter)); kqtInit(); if(openKdeDialog(tqparent, 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 *tqparent, const char *name, const TQString &caption, TQString *selectedFilter, bool resolveSymlinks) { TQStringList res; TQString f(qt2KdeFilter(filter)); kqtInit(); if (openKdeDialog(tqparent, 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 *tqparent, const char *name, const TQString &caption, bool dirOnly, bool resolveSymlinks) { TQStringList res; TQString dummy; kqtInit(); return openKdeDialog(tqparent, caption, dir, NULL, OP_FOLDER, res, &dummy) ? res.first() : TQString(); } TQStringList TQFileDialog::getOpenFileNames(const TQString &filter, const TQString &dir, TQWidget *tqparent, const char *name, const TQString &caption, TQString *selectedFilter, bool resolveSymlinks) { TQStringList res; TQString f(qt2KdeFilter(filter)); kqtInit(); openKdeDialog(tqparent, 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.tqfindRev('/'); 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, tqparentWidget(), 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), tqparentWidget(), NULL, caption(), &selectedFilter, true); if(!file.isEmpty()) res=TQDialog::Accepted; break; } case TQFileDialog::ExistingFile: file=TQFileDialog::getOpenFileName(initialDir, getFilters(that), tqparentWidget(), NULL, caption(), &selectedFilter, true); if(!file.isEmpty()) res=TQDialog::Accepted; break; case TQFileDialog::ExistingFiles: files=TQFileDialog::getOpenFileNames(getFilters(that), initialDir, tqparentWidget(), 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