Revision 1 (by moose, 2006/03/06 10:35:57) Initial Import
#include <QPixmap>
#include <QStringList>
#include <QTcpServer>
#include <QTcpSocket>

#include <QTextStream>

#include "SciQApp.h"
#include "SciQMW.h"
#include "SciQSettingsDialog.h"
#include "SciQDockWindow.h"
#include "SciQDockWindowFactory.h"

#include "SciQUtil.h"

#include "SciQX11TrayIcon.h"

#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>

#define LISTENPORT 12343
/*
Ok, wow, this needs to be changed to use a unix socket or something similar, possibly shared mem.
also, flock() could be handy.
*/

SciQApp::SciQApp(int &argc, char **argv) : QApplication(argc, argv), qs(this)
{
	QApplication::setOrganizationName("StrangeSoft");
	QApplication::setOrganizationDomain("strangesoft.net");
	QApplication::setApplicationName("SciQ");

	initResourcePath();

	qDebug("%s: init", __PRETTY_FUNCTION__);

#if 0
	sigset_t set, oset;
	switch (fork()) {
		case -1:
			/* Something bad happened */
			exit(1);
		case 0:
			qDebug("in child!\n");
			/* We're in the child */
			break;
		default:
			/* Allow SIGTERM from child to wake us up */
			sigdelset(&set, SIGTERM);
			sigsuspend(&set);
			::exit(0);
	}

	qDebug("before setsid!\n");

	if (setsid() == -1)
		::_exit(2);

	signal(SIGCHLD,SIG_IGN); /* ignore child */
	signal(SIGTSTP,SIG_IGN); /* ignore tty signals */
	signal(SIGTTOU,SIG_IGN);
	signal(SIGTTIN,SIG_IGN);
#endif

	qDebug("Create TcpSocket!");
	sock = new QTcpSocket(this);
	connect(sock, SIGNAL(connected()), this, SLOT(connected()));
	sock->connectToHost(QHostAddress::LocalHost, LISTENPORT);
	if(sock->waitForConnected(1000))
		::exit(0);

	qDebug("Create TcpServer!");
	sess = new QTcpServer(this);
	if(!sess->listen(QHostAddress::LocalHost, LISTENPORT)) {
		qDebug("failed to startup session server");
		::exit(0);
	}
	connect(sess, SIGNAL(newConnection()), this, SLOT(newConnection()));

	qDebug("%s: continue.", __PRETTY_FUNCTION__);

	instance = this; // hack ::)

	mw = new SciQMW();
	//mw->QObject::setParent(this);
	mw->show();

	sd = ::SciQSettingsDialog::getInstance();

	//tray = new SciQX11TrayIcon(mw);
	//tray->show();
}

SciQApp::~SciQApp()
{
	//tray->hide();
	delete mw;
	instance = 0;
}

QIcon SciQApp::getIcon(QString name)
{
	return findResource<QPixmap>(QString("images/%1.png").arg(name));
}

void SciQApp::newConnection()
{
	QTcpSocket *nsock = sess->nextPendingConnection();
	QTextStream txt(nsock);
	int avail = nsock->bytesAvailable();

	qDebug("%s", __PRETTY_FUNCTION__);

	nsock->waitForReadyRead();
	//if(avail) {
		QString line = txt.readLine();
		if(line != "SciQ4") {
			qDebug("invalid connection sequence: '%s'", qPrintable(line));
			nsock->abort();
			return;
		}
		qDebug("got: '%s'", qPrintable(line));
//	}

	txt << "SciQ4" << endl;
	nsock->waitForBytesWritten();

	nsock->waitForReadyRead();

	int len = 0;
	txt >> len;

	for(int i=0; i<len; ++i) {
		if(nsock->isValid())
			nsock->waitForReadyRead();
		QString str = txt.readLine();
		printf("got: '%s'/'%s'", qPrintable(str), qPrintable(str.section(QString(1, QChar('\0')), 1, -1)));
	}
	nsock->close();
}

void SciQApp::connected()
{
	qDebug("%s", __PRETTY_FUNCTION__);
	QTextStream txt(sock);
	txt << "SciQ4" << endl;
	sock->waitForBytesWritten();
	sock->waitForReadyRead();

	QString line = txt.readLine();
	if(line != "SciQ4") {
		qDebug("invalid connect reply sequence: '%s'", qPrintable(line));
		sock->abort();
		return;
	}

	qDebug("got: '%s'", qPrintable(line));

	txt << argc()-1;
	sock->waitForBytesWritten();
	qDebug("writing %i elements", argc()-1);
	if(argc() > 1) {
		char **av = argv();
		for(int i=1; i<argc(); ++i) {
			QChar ch[5] = { 'O', 'P', 'E', 'N', '\0' };
			txt << QString(ch, 5);
			txt << av[i] << endl;
			if(sock->isValid())
				sock->waitForBytesWritten();
		}
	}

	sock->close();

	::exit(0);
}

SciQApp *SciQApp::getInstance(int argc, char **argv)
{
	if(!instance) {
		if(!argv) {
			argv = _argv;
			argc = _argc;
		} else {
			_argv = argv;
			_argc = argc;
		}

		instance = new SciQApp(argc, argv);
		qDebug("!instance: %p", instance);
	}

	return instance;
}

SciQDockWindow *SciQApp::getDockWindowInstance(QString &s, SciQMWBase *mw)
{
	SciQDockWindowFactory *dwf = 0;
	SciQDockWindow *dw = 0;

	if(dockhash.contains(s)) {
		dwf = dockhash.value(s);
		dw = dwf->createInstance(mw);
	}

	return dw;
}

QString SciQApp::Sequence(QString o) {
	static QHash<QString, int> map;
	int num = map[o];

	QString seq = o + QString().sprintf("%i", num);
//	printf("Creating new unique sequence: '%s'\n", qPrintable(seq));

	num++;
	map[o] = num;

	return seq;
}

void SciQApp::addResourcePath(QString p)
{
	qDebug("%s: %s", __PRETTY_FUNCTION__, qPrintable(p));
	QDir().mkpath(p);
	resourcePath << p;
}

QString SciQApp::getResourcePath(QString p)
{
	for(int i = 0; i < resourcePath.count(); ++i) {
		QString tmp = catdir(QStringList() + resourcePath.at(i) + p);
		if(QFile::exists(tmp)) {
		//	qDebug("%s: %s", __PRETTY_FUNCTION__, qPrintable(tmp));
			return tmp;
		}
	}

	// scan resources last
	QString tmp = catdir(QStringList() + QString(":/") + p);
	if(QFile::exists(tmp)) {
	//	qDebug("%s: %s", __PRETTY_FUNCTION__, qPrintable(tmp));
		return tmp;
	}

	return QDir().absoluteFilePath(p);
}

// this sets up the unix and windows default search paths
void SciQApp::initResourcePath() {
	QString tmp;
#ifdef Q_OS_UNIX
	// add /home/user/.SciQ
	tmp = catdir(QStringList() + QDir::homePath() + QString(".%1").arg(applicationName()));
	addResourcePath(tmp);

	// add /usr/share/SciQ
	tmp = catdir(QStringList() + QDir::rootPath() + "usr" + "share" + applicationName());
	addResourcePath(tmp);

#elif defined Q_OS_WIN32
	// This win32 code hasn't been tested...
	char szPath[MAX_PATH];
	if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, szPath)))
		/*
			CSIDL_APPDATA
				The file system directory that serves as a common repository for application-specific data.
				A typical path is C:\Documents and Settings\username\Application Data.

			I chose to try this before the code in the "else" clause,
			because who knows if the folder is really "Application Data",
			as I assume below.
		*/
		tmp = catdir(QStringList() + szPath + applicationName());
	else
		tmp = catdir(QStringList() + QDir::homePath() + "Application Data" + applicationName());

	addResourcePath(tmp);


	QString def = catdir(QStringList() + QDir::rootPath() + "Program Files" + applicationName());
	// if the installer saved a "installpath" var... if not, just assume %ROOT%\Program Files\SciQ
	addResourcePath(qs.value("installpath", def).toString());
#endif

	// And for good measure, add %TEMP%/SciQ
	tmp = catdir(QStringList() + QDir::tempPath() + applicationName());
	addResourcePath(tmp);
}

SciQWorkspace *SciQApp::newWorkspace(QString path)
{

}

SciQApp *SciQApp::instance = 0;
QStringList SciQApp::resourcePath;
int SciQApp::_argc = 0;
char **SciQApp::_argv = 0;