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/qt4/kqt4.cpp

600 lines
16 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 KQT_OVERLOAD_NON_STATIC_FILEDIALOGS
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#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 <QtCore/QString>
#include <QtCore/QStringList>
#include <QtGui/QWidget>
#include <QtGui/QApplication>
#include <QtCore/QTextStream>
#include <QtGui/QCloseEvent>
#include <QtGui/QFileDialog>
#include <QtCore/QThread>
#include <QtCore/Qt>
#include <QtCore/QEventLoop>
#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 useQt=true)
{
static const char *appName=NULL;
if(!appName)
{
const char *a=useQt && QCoreApplication::arguments().count()
? QCoreApplication::arguments()[0].toLatin1().constData() : getAppNameFromPid(getpid());
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 : "Qt4App";
}
return appName;
}
int QApplication::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();
};
static QString qt2KdeFilter(const QString &f)
{
QString filter;
QTextStream str(&filter, QIODevice::WriteOnly);
QStringList list(f.split(";;"));
QStringList::Iterator it(list.begin()),
end(list.end());
bool first=true;
for(; it!=end; ++it)
{
int ob=(*it).lastIndexOf('('),
cb=(*it).lastIndexOf(')');
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 kde2QtFilter(const QString &orig, QString *sel)
{
if(sel)
{
QStringList list(orig.split(";;"));
QStringList::Iterator it(list.begin()),
end(list.end());
int pos;
for(; it!=end; ++it)
if(-1!=(pos=(*it).indexOf(*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 KQT_OVERLOAD_NON_STATIC_FILEDIALOGS
static const QString getFilters(QFileDialog *dlg, bool scribusSave=false)
{
QString filter;
if(dlg)
{
QStringList filters(dlg->filters());
QStringList::ConstIterator it(filters.begin()),
end(filters.end());
bool first(true);
QTextStream str(&filter, QIODevice::WriteOnly);
for(; it!=end; ++it)
{
if(!first)
str << ";;";
if(scribusSave && -1!=(*it).indexOf("(*.sla *.sla.gz *.scd *scd.gz)"))
str << "Compressed Documents (*.sla.gz *scd.gz);;Documents (*.sla *.scd)";
else
str << (*it);
first=false;
}
}
return filter;
}
static QString getDir(const QString &f)
{
QString d(f);
int slashPos=d.lastIndexOf('/');
if(slashPos!=-1)
d.remove(slashPos+1, d.length());
return d;
}
#endif
static bool writeString(int fd, const QString &str)
{
QByteArray utf8(str.toUtf8());
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 KQtDialog : public QDialog
{
public:
KQtDialog(QWidget *parent) : QDialog(parent, Qt::FramelessWindowHint|Qt::X11BypassWindowManagerHint)
{
setModal(true);
resize(1, 1);
setWindowOpacity(0);
setWindowState(Qt::WindowMinimized);
move(32768, 32768);
}
/* void r() { QDialog::reject(); }*/
};
class KQtThread : public QThread
{
public:
KQtThread(QStringList &l, QString &s, int f, KQtDialog *dlg) : dialog(dlg), kdialogdError(false), res(l), selFilter(s), fd(f)
{ }
bool readData(QByteArray &buffer, int size)
{
buffer.resize(size);
return ::readBlock(fd, buffer.data(), size);
}
bool readString(QString &str, int size)
{
QByteArray buffer;
buffer.resize(size);
if(!readBlock(fd, buffer.data(), size))
return false;
str=QString::fromUtf8(buffer.data());
return true;
}
void run()
{
QString 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;
QCoreApplication::postEvent(dialog, new QCloseEvent);
}
KQtDialog *dialog;
bool kdialogdError;
QStringList &res;
QString &selFilter;
int fd;
};
static bool sendMessage(QWidget *parent, Operation op, QStringList &res, QString &selFilter,
const QString &title, const QString &p1, const QString *p2, bool ow)
{
if(connectToKDialogD(getAppName()))
{
char o=(char)op;
int xid=parent ? parent->topLevelWidget()->winId() : qApp->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))
{
KQtDialog dlg(parent);
KQtThread thread(res, selFilter, kdialogdSocket, &dlg);
thread.start();
dlg.exec();
thread.wait();
if(thread.kdialogdError)
{
closeConnection();
return false;
}
return true;
}
}
return false;
}
static QString getTitle(const QString &title, Operation op)
{
if(!title.isEmpty())
return title;
return ".";
}
static bool openKdeDialog(QWidget *widget, const QString &title, const QString &p1, const QString *p2,
Operation op, QStringList &res, QString *selFilter, bool ow=false)
{
QString 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 Qt
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 QString lastDir;
static void storeLastDir(const QString &f)
{
lastDir=f;
int slashPos(lastDir.lastIndexOf('/'));
if(slashPos!=-1)
lastDir.remove(slashPos+1, lastDir.length());
}
static const QString & startDir(const QString &d)
{
return d.isEmpty() ? lastDir : d;
}
QString QFileDialog::getOpenFileName(QWidget *parent, const QString &caption,
const QString &dir, const QString &filter,
QString *selectedFilter, Options options)
{
QStringList res;
QString f(qt2KdeFilter(filter));
kqtInit();
if(openKdeDialog(parent, caption, startDir(dir), &f, OP_FILE_OPEN, res, selectedFilter) && res.count())
{
kde2QtFilter(filter, selectedFilter);
QString fn(res.first());
storeLastDir(fn);
return fn;
}
return QString();
}
QString QFileDialog::getSaveFileName(QWidget *parent, const QString &caption,
const QString &dir, const QString &filter,
QString *selectedFilter, Options options)
{
QStringList res;
QString f(qt2KdeFilter(filter));
kqtInit();
if (openKdeDialog(parent, caption, startDir(dir), &f, OP_FILE_SAVE, res, selectedFilter) && res.count())
{
kde2QtFilter(filter, selectedFilter);
QString fn(res.first());
storeLastDir(fn);
return fn;
}
return QString();
}
QString QFileDialog::getExistingDirectory(QWidget *parent, const QString &caption,
const QString &dir, Options options)
{
QStringList res;
QString dummy;
kqtInit();
return openKdeDialog(parent, caption, dir, NULL, OP_FOLDER, res, &dummy) && res.count()
? res.first()
: QString();
}
QStringList QFileDialog::getOpenFileNames(QWidget *parent, const QString &caption,
const QString &dir, const QString &filter,
QString *selectedFilter, Options options)
{
QStringList res;
QString f(qt2KdeFilter(filter));
kqtInit();
openKdeDialog(parent, caption, startDir(dir), &f, OP_FILE_OPEN_MULTIPLE, res, selectedFilter);
if(res.count())
{
kde2QtFilter(filter, selectedFilter);
storeLastDir(res.first());
}
return res;
}
#ifdef KQT_OVERLOAD_NON_STATIC_FILEDIALOGS
static QString getFile(const QString &f)
{
QString d(f);
int slashPos=d.lastIndexOf('/');
if(slashPos!=-1)
d.remove(0, slashPos+1);
return d;
}
int QDialog::exec()
{
int res=QDialog::Rejected;
if(inherits("QFileDialog"))
{
QFileDialog *that=(QFileDialog *)this;
QDir directory(that->directory());
QString dir,
selectedFilter,
file;
QStringList files;
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
switch(that->fileMode())
{
case QFileDialog::Directory:
case QFileDialog::DirectoryOnly:
dir=QFileDialog::getExistingDirectory(parentWidget(), windowTitle(), directory.absolutePath(), 0);
if(!dir.isEmpty())
res=QDialog::Accepted;
break;
case QFileDialog::AnyFile:
{
QString app(getFile(qApp->argv()[0])),
initial(directory.absolutePath());
/*
TODO!!!
initialFile(getCurrentFileName(that));
if(!initialFile.isEmpty())
initial=initial+QLatin1Char('/')+initialFile;
*/
file=QFileDialog::getSaveFileName(parentWidget(), windowTitle(), initial,
getFilters(that, "scribus"==app ||
"scribus-ng"==app), &selectedFilter, 0);
if(!file.isEmpty())
res=QDialog::Accepted;
break;
}
case QFileDialog::ExistingFile:
file=QFileDialog::getOpenFileName(parentWidget(), windowTitle(), directory.absolutePath(),
getFilters(that), &selectedFilter, 0);
if(!file.isEmpty())
res=QDialog::Accepted;
break;
case QFileDialog::ExistingFiles:
files=QFileDialog::getOpenFileNames(parentWidget(), windowTitle(), directory.absolutePath(),
getFilters(that), &selectedFilter, 0);
if(files.count())
res=QDialog::Accepted;
break;
}
if(QDialog::Accepted==res)
{
if(file.isEmpty() && files.count())
file=files.first();
if(dir.isEmpty() && !file.isEmpty())
dir=getDir(file);
if(!dir.isEmpty())
that->setDirectory(dir);
if(!selectedFilter.isEmpty())
that->selectFilter(selectedFilter);
if(!file.isEmpty())
that->selectFile(getFile(file));
if(files.count())
{
QStringList::ConstIterator it(files.begin()),
end(files.end());
for(; it!=end; ++it)
that->selectFile(getFile(*it));
}
}
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
}
else
{
static int (*realFunction)(void *);
if(!realFunction)
realFunction = (int (*)(void *)) dlsym(RTLD_NEXT, KQT_QDIALOG_EXEC);
return (int)realFunction(this);
}
return res;
}
#endif