You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kgtk-qt3/tqt/kqt3.cpp

672 lines
18 KiB

/************************************************************************
*
* 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 children...
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 children=((TQObject *)dlg)->childrenListObject();
if(!children.isEmpty())
{
TQObjectList::ConstIterator it(children.begin()),
end(children.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 children=((TQObject *)dlg)->childrenListObject();
if(!children.isEmpty())
{
TQObjectList::ConstIterator it(children.begin()),
end(children.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->topLevelWidget()->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