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.
951 lines
28 KiB
951 lines
28 KiB
11 years ago
|
/***************************************************************************
|
||
|
* Copyright (C) 2004 by David Sansome *
|
||
|
* me@davidsansome.com *
|
||
|
* *
|
||
|
* This program is free software; you can redistribute it and/or modify *
|
||
|
* it under the terms of the GNU General Public License as published by *
|
||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||
|
* (at your option) any later version. *
|
||
|
* *
|
||
|
* This program 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 General Public License for more details. *
|
||
|
* *
|
||
|
* You should have received a copy of the GNU General Public License *
|
||
|
* along with this program; if not, write to the *
|
||
|
* Free Software Foundation, Inc., *
|
||
|
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||
|
***************************************************************************/
|
||
|
#include "wizard.h"
|
||
|
|
||
|
#include <qfiledialog.h>
|
||
|
#include <qwidgetstack.h>
|
||
|
#include <qpushbutton.h>
|
||
|
#include <qpainter.h>
|
||
|
#include <qheader.h>
|
||
|
#include <qapplication.h>
|
||
|
#include <qmessagebox.h>
|
||
|
#include <qprogressbar.h>
|
||
|
#include <qradiobutton.h>
|
||
|
#include <qtextedit.h>
|
||
|
#include <qlineedit.h>
|
||
|
#include <qpopupmenu.h>
|
||
|
#include <qhbox.h>
|
||
|
#include <qfileinfo.h>
|
||
|
#include <qlabel.h>
|
||
|
#include <qfontmetrics.h>
|
||
|
#include <qcheckbox.h>
|
||
|
|
||
|
#include "data.h"
|
||
|
|
||
|
#include "rcparser.h"
|
||
|
#include "headerlistitem.h"
|
||
|
|
||
|
typedef QValueVector<CompileError> CompileErrorVector;
|
||
|
CompileErrorVector errs( 5 ); // vector of 3 Employees
|
||
|
|
||
|
|
||
|
ComponentListItem::ComponentListItem(struct Component c, QListView* parent)
|
||
|
: QCheckListItem(parent, "", QCheckListItem::CheckBox)
|
||
|
{
|
||
|
component = c;
|
||
|
setText(0, c.niceName);
|
||
|
setOn(true);
|
||
|
|
||
|
if (c.gnomeOnly)
|
||
|
section=2;
|
||
|
else if (c.kdeOnly)
|
||
|
section=3;
|
||
|
else if (c.optional)
|
||
|
section=1;
|
||
|
else
|
||
|
section=0;
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
int ComponentListItem::compare(QListViewItem* i, int col, bool ascending) const
|
||
|
{
|
||
|
switch (i->rtti())
|
||
|
{
|
||
|
case 1001: // Component
|
||
|
{
|
||
|
ComponentListItem* item = (ComponentListItem*) i;
|
||
|
if (section < item->section)
|
||
|
return -1;
|
||
|
if (section > item->section)
|
||
|
return 1;
|
||
|
return QListViewItem::compare(i, col, ascending);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 1002: // Header
|
||
|
{
|
||
|
HeaderListItem* item = (HeaderListItem*) i;
|
||
|
if (section < item->section)
|
||
|
return -1;
|
||
|
return 1;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
Wizard::Wizard(QWidget *parent, const char *name)
|
||
|
: WizardBase(parent, name, false, WDestructiveClose)
|
||
|
{
|
||
|
componentInfo->setMaximumSize(32767,70);
|
||
|
componentList->header()->hide();
|
||
|
//progressLabel2->setMaximumSize(32767, progressLabel2->fontMetrics().height()*2);
|
||
|
externalProcess = new QProcess(this);
|
||
|
connect(externalProcess, SIGNAL(processExited()), SLOT(processExited()));
|
||
|
connect(externalProcess, SIGNAL(readyReadStdout()), SLOT(readyReadStdout()));
|
||
|
connect(externalProcess, SIGNAL(readyReadStderr()), SLOT(readyReadStderr()));
|
||
|
|
||
|
logDialog = new LogDialog(this);
|
||
|
logDialog->hide();
|
||
|
previousButton->hide();
|
||
|
|
||
|
createActionFormats();
|
||
|
|
||
|
kdeDirProcess = new QProcess(this);
|
||
|
connect(kdeDirProcess, SIGNAL(readyReadStdout()), SLOT(kdeDirReady()));
|
||
|
connect(kdeDirProcess, SIGNAL(processExited()), SLOT(getInstalledComponents()));
|
||
|
kdeDirProcess->addArgument("kde-config");
|
||
|
kdeDirProcess->addArgument("--prefix");
|
||
|
if (!kdeDirProcess->start())
|
||
|
getInstalledComponents();
|
||
|
|
||
|
errs[0] = CompileError( "libevent", "The installation process finished with an error because it needs a "
|
||
|
" component missing on your system. To correct this, "
|
||
|
"do the following: <br> 1. Download and install the package for your distribution with the word 'libevent' in its title. <br> 2. Retry installation." );
|
||
|
errs[1] = CompileError( "X includes", "The installation process finished with an error because it needs a "
|
||
|
" component missing on your system. To correct this, "
|
||
|
"do the following: <br> 1. Download and install any packages for your distribution with (i) 'X' and "
|
||
|
" either 'devel' or 'lib' in their name. <br> 2. Retry installation. " );
|
||
|
errs[2] = CompileError( "There is no user 'privoxy' on this system", "The installation reported an"
|
||
|
"error because you need to create the 'privoxy' user. To correct this, "
|
||
|
"do the following: <br> 1. As root, enter the following command: useradd privoxy. <br> 2. Retry installation. " );
|
||
|
errs[3] = CompileError( "installing config files as root", "The installation reported an"
|
||
|
"error because I attempted to install the privoxy config files as root. <b> There is no "
|
||
|
"need to take any action on your part. Privoxy has been installed and you can now use it with TorK. " );
|
||
|
errs[4] = CompileError( "Qt (>= ", "The installation process finished with an error because it needs a "
|
||
|
" component missing on your system. To correct this, "
|
||
|
"do the following: <br> 1. Download and install any packages for your distribution with (i) 'qt' and "
|
||
|
" either 'devel' or 'lib' in their name. <br> 2. Retry installation. " );
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
void Wizard::createActionFormats()
|
||
|
{
|
||
|
// Taken from KDevelop
|
||
|
actionFormats.clear();
|
||
|
actionFormats.append(ActionFormat( tr("compiling"), "g++", "g\\+\\+\\S* (?:\\S* )*-c (?:\\S* )*`[^`]*`(?:[^/\\s;]*/)*([^/\\s;]+)", 1 ));
|
||
|
actionFormats.append(ActionFormat( tr("compiling"), "g++", "g\\+\\+\\S* (?:\\S* )*-c (?:\\S* )*(?:[^/]*/)*([^/\\s;]*)", 1 ));
|
||
|
actionFormats.append(ActionFormat( tr("compiling"), "gcc", "gcc\\S* (?:\\S* )*-c (?:\\S* )*`[^`]*`(?:[^/\\s;]*/)*([^/\\s;]+)", 1 ));
|
||
|
actionFormats.append(ActionFormat( tr("compiling"), "gcc", "gcc\\S* (?:\\S* )*-c (?:\\S* )*(?:[^/]*/)*([^/\\s;]*)", 1 ));
|
||
|
actionFormats.append(ActionFormat( tr("compiling"), "distcc", "distcc (?:\\S* )*-c (?:\\S* )*`[^`]*`(?:[^/\\s;]*/)*([^/\\s;]+)", 1 ));
|
||
|
actionFormats.append(ActionFormat( tr("compiling"), "distcc", "distcc (?:\\S* )*-c (?:\\S* )*(?:[^/]*/)*([^/\\s;]*)", 1 ));
|
||
|
actionFormats.append(ActionFormat( tr("compiling"), "unknown", "^compiling (.*)", 1 ));
|
||
|
actionFormats.append(ActionFormat( tr("generating"), "moc", "/moc\\b.*\\s-o\\s([^\\s;]+)", 1 ));
|
||
|
actionFormats.append(ActionFormat( tr("generating"), "uic", "/uic\\b.*\\s-o\\s([^\\s;]+)", 1 ));
|
||
|
actionFormats.append(ActionFormat( tr("linking"), "libtool", "/+bin/+sh\\s.*libtool.*--mode=link\\s.*\\s-o\\s([^\\s;]+)", 1 ));
|
||
|
actionFormats.append(ActionFormat( tr("linking"), "g++", "g\\+\\+\\S* (?:\\S* )*-o ([^\\s;]+)", 1 ));
|
||
|
actionFormats.append(ActionFormat( tr("linking"), "gcc", "gcc\\S* (?:\\S* )*-o ([^\\s;]+)", 1 ));
|
||
|
actionFormats.append(ActionFormat( tr("creating"), "", "/(?:bin/+sh\\s.*mkinstalldirs).*\\s([^\\s;]+)", 1 ));
|
||
|
actionFormats.append(ActionFormat( tr("installing"), "", "/(?:usr/+bin/+install|bin/+sh\\s.*mkinstalldirs|bin/+sh\\s.*libtool.*--mode=install).*\\s\\'?([^\\s;\\']+)\\'?", 1 ));
|
||
|
actionFormats.append(ActionFormat( tr("generating"), "dcopidl", "dcopidl .* > ([^\\s;]+)", 1 ));
|
||
|
actionFormats.append(ActionFormat( tr("compiling"), "dcopidl2cpp", "dcopidl2cpp (?:\\S* )*([^\\s;]+)", 1 ));
|
||
|
}
|
||
|
|
||
|
void Wizard::kdeDirReady()
|
||
|
{
|
||
|
while (kdeDirProcess->canReadLineStdout())
|
||
|
{
|
||
|
QString line = kdeDirProcess->readLineStdout();
|
||
|
if (!line.isEmpty())
|
||
|
kdeDir = line;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Wizard::getInstalledComponents()
|
||
|
{
|
||
|
QFile uninstallScript("/tmp/arkollon-uninstall.sh");
|
||
|
if (uninstallScript.exists())
|
||
|
uninstallScript.remove();
|
||
|
uninstallScript.open(IO_WriteOnly);
|
||
|
QDataStream stream(&uninstallScript);
|
||
|
stream.writeRawBytes((const char*)uninstaller_sh_data, uninstaller_sh_len);
|
||
|
uninstallScript.close();
|
||
|
|
||
|
installedComponentsProcess = new QProcess(this);
|
||
|
connect(installedComponentsProcess, SIGNAL(readyReadStdout()), SLOT(installedComponentsReady()));
|
||
|
connect(installedComponentsProcess, SIGNAL(processExited()), SLOT(setup()));
|
||
|
installedComponentsProcess->addArgument("/bin/sh");
|
||
|
installedComponentsProcess->addArgument("/tmp/arkollon-uninstall.sh");
|
||
|
installedComponentsProcess->addArgument("--list");
|
||
|
if (!installedComponentsProcess->start())
|
||
|
setup();
|
||
|
}
|
||
|
|
||
|
void Wizard::installedComponentsReady()
|
||
|
{
|
||
|
while (installedComponentsProcess->canReadLineStdout())
|
||
|
{
|
||
|
QString line = installedComponentsProcess->readLineStdout();
|
||
|
if (line.isEmpty())
|
||
|
continue;
|
||
|
|
||
|
// See if it already exists
|
||
|
if (installedComponents.find(line.lower()) != installedComponents.end())
|
||
|
continue;
|
||
|
|
||
|
installedComponents.append(line.lower());
|
||
|
//printf("Found installed component %s\n", parser.cap(3).latin1());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Wizard::setup()
|
||
|
{
|
||
|
QFile uninstallScript("/tmp/arkollon-uninstall.sh");
|
||
|
if (uninstallScript.exists())
|
||
|
uninstallScript.remove();
|
||
|
|
||
|
if (kdeDir.isEmpty())
|
||
|
kdeDir = "/usr";
|
||
|
|
||
|
// Firstly check if there's an arkollonrc file in the current directory
|
||
|
// If there is, use it.
|
||
|
dir = QDir::currentDirPath();
|
||
|
if (qApp->argc() > 1)
|
||
|
{
|
||
|
// The directory specified on the command line overrides the current dir.
|
||
|
QDir d(qApp->argv()[1]);
|
||
|
dir = d.absPath();
|
||
|
}
|
||
|
if (QFile::exists(dir + "/arkollonrc"))
|
||
|
{
|
||
|
setupFromRc();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!setupFromDir())
|
||
|
{
|
||
|
QMessageBox::critical(NULL, "Error", "This directory does not contain any recognised buildsystem", QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton);
|
||
|
reject();
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
show();
|
||
|
}
|
||
|
|
||
|
void Wizard::setupFromRc()
|
||
|
{
|
||
|
RcParser parser;
|
||
|
parser.addSearchDir(dir);
|
||
|
if (!parser.openFile("arkollonrc"))
|
||
|
{
|
||
|
QMessageBox::critical(NULL, "Error", "The \"arkollonrc\" file in this directory could not be read", QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton);
|
||
|
reject();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
parser.setSection("Arkollon");
|
||
|
QString appName = parser.readString("AppName");
|
||
|
if (appName.isEmpty())
|
||
|
{
|
||
|
QMessageBox::critical(NULL, "Error", "The \"arkollonrc\" file in this directory contains no application name!", QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton);
|
||
|
reject();
|
||
|
return;
|
||
|
}
|
||
|
setAppName(appName);
|
||
|
|
||
|
QString icon32Path = parser.readString("Icon32");
|
||
|
QString icon16Path = parser.readString("Icon16");
|
||
|
if ((!icon32Path.isEmpty()) && (QFile::exists(dir + "/" + icon32Path)))
|
||
|
{
|
||
|
QPixmap icon32(dir + "/" + icon32Path);
|
||
|
appIcon->setPixmap(icon32);
|
||
|
}
|
||
|
if ((!icon16Path.isEmpty()) && (QFile::exists(dir + "/" + icon16Path)))
|
||
|
{
|
||
|
QPixmap icon16(dir + "/" + icon16Path);
|
||
|
setIcon(icon16);
|
||
|
}
|
||
|
|
||
|
buildOrder = parser.readList("BuildOrder");
|
||
|
QStringList compNames = parser.readList("Components");
|
||
|
QStringList::Iterator it = compNames.begin();
|
||
|
while( it != compNames.end() )
|
||
|
{
|
||
|
parser.setSection(*it);
|
||
|
|
||
|
struct Component c;
|
||
|
c.name = *it;
|
||
|
c.niceName = parser.readString("NiceName");
|
||
|
c.subDir = parser.readString("SubDir");
|
||
|
c.forceDir = sub(parser.readString("ForceDir"));
|
||
|
c.optional = parser.readBool("Optional", false);
|
||
|
c.kdeOnly = parser.readBool("KDEOnly", false);
|
||
|
c.gnomeOnly = parser.readBool("GnomeOnly", false);
|
||
|
c.description = sub(parser.readString("Description"));
|
||
|
c.confOptions = parser.readString("ConfigureOptions");
|
||
|
c.alreadyInstalled = false;
|
||
|
|
||
|
// Load the buildtimes data
|
||
|
if (QFile::exists(dir + "/" + c.subDir + "/buildtimes"))
|
||
|
{
|
||
|
QRegExp re("([^,]*,[^,]*),(\\d*)");
|
||
|
QFile file(dir + "/" + c.subDir + "/buildtimes");
|
||
|
file.open(IO_ReadOnly);
|
||
|
QTextStream stream(&file);
|
||
|
for (;;)
|
||
|
{
|
||
|
QString line = stream.readLine();
|
||
|
if (line.isNull())
|
||
|
break;
|
||
|
if (re.search(line) == -1)
|
||
|
continue;
|
||
|
c.buildTimes.insert(re.cap(1), re.cap(2).toInt());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Add the header for this component
|
||
|
ComponentListItem* item = new ComponentListItem(c, componentList);
|
||
|
if (!headers.contains(item->section))
|
||
|
{
|
||
|
headers[item->section] = new HeaderListItem(componentList);
|
||
|
((HeaderListItem*)headers[item->section])->section = item->section;
|
||
|
|
||
|
switch(item->section)
|
||
|
{
|
||
|
case 0: headers[item->section]->setText(0, "Required components"); break;
|
||
|
case 1: headers[item->section]->setText(0, "Optional components"); break;
|
||
|
case 2: headers[item->section]->setText(0, "Gnome specific components"); break;
|
||
|
case 3: headers[item->section]->setText(0, "KDE specific components"); break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Check if it's already installed
|
||
|
QStringList::Iterator it2 = installedComponents.begin();
|
||
|
while( it2 != installedComponents.end() )
|
||
|
{
|
||
|
int dashPos = c.subDir.findRev('-');
|
||
|
if (dashPos < 0)
|
||
|
dashPos = c.subDir.length();
|
||
|
QString version = c.subDir.left(dashPos) + ":" + c.subDir.right(c.subDir.length() - dashPos - 1);
|
||
|
if (*it2 == version.lower())
|
||
|
{
|
||
|
item->setOn(false);
|
||
|
item->component.alreadyInstalled = true;
|
||
|
}
|
||
|
++it2;
|
||
|
}
|
||
|
|
||
|
++it;
|
||
|
}
|
||
|
parser.setSection("Arkollon");
|
||
|
exec = sub(parser.readString("Exec"));
|
||
|
desktop = sub(parser.readString("Desktop"));
|
||
|
}
|
||
|
|
||
|
bool Wizard::setupFromDir()
|
||
|
{
|
||
|
if ((!QFile::exists(dir + "/configure")) &&
|
||
|
(!QFile::exists(dir + "/autogen.sh")) &&
|
||
|
(!QFile::exists(dir + "/auto-gen.sh")))
|
||
|
{
|
||
|
QDir myDir(dir + "/" + selectedComponents[currentComponent].subDir);
|
||
|
if (myDir.entryList("*.pro", QDir::Files).count() <= 0)
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Use the directory name as the appname
|
||
|
QDir myDir2(dir);
|
||
|
QString dirName = myDir2.dirName();
|
||
|
setAppName(makeDirNice(dirName));
|
||
|
|
||
|
buildOrder.append(dirName);
|
||
|
struct Component c;
|
||
|
c.name = dirName;
|
||
|
c.niceName = makeDirNice(dirName);
|
||
|
c.optional = false;
|
||
|
c.subDir = "";
|
||
|
c.gnomeOnly = false;
|
||
|
c.kdeOnly = false;
|
||
|
c.description = "<i>No description is associated with this component.</i>";
|
||
|
c.alreadyInstalled = false;
|
||
|
ComponentListItem* item = new ComponentListItem(c, componentList);
|
||
|
HeaderListItem* header = new HeaderListItem(componentList);
|
||
|
header->setText(0, "Required components");
|
||
|
header->section = 0;
|
||
|
|
||
|
QStringList::Iterator it2 = installedComponents.begin();
|
||
|
while( it2 != installedComponents.end() )
|
||
|
{
|
||
|
int dashPos = dirName.findRev('-');
|
||
|
if (dashPos < 0)
|
||
|
dashPos = dirName.length();
|
||
|
QString version = dirName.left(dashPos) + ":" + dirName.right(dirName.length() - dashPos - 1);
|
||
|
if (*it2 == version.lower())
|
||
|
item->component.alreadyInstalled = true;
|
||
|
++it2;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
Wizard::~Wizard()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
void Wizard::componentSelected(QListViewItem* item)
|
||
|
{
|
||
|
if (item->rtti() != 1001)
|
||
|
return;
|
||
|
|
||
|
ComponentListItem* i = (ComponentListItem*) item;
|
||
|
QString text = "<p><b>" + item->text(0) + "</b>";
|
||
|
if (i->component.alreadyInstalled)
|
||
|
text += " <i>(Already installed)</i>";
|
||
|
text += "</p><p>";
|
||
|
text += i->component.description;
|
||
|
text += "</p>";
|
||
|
|
||
|
componentInfo->setText(text);
|
||
|
}
|
||
|
|
||
|
|
||
|
QString Wizard::makeDirNice(QString name)
|
||
|
{
|
||
|
int dashPos = name.findRev('-');
|
||
|
if (dashPos < 0)
|
||
|
dashPos = name.length();
|
||
|
|
||
|
QString ret = name.left(dashPos);
|
||
|
ret = ret.left(1).upper() + ret.right(ret.length()-1);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
void Wizard::cancelPressed()
|
||
|
{
|
||
|
if (externalProcess->isRunning())
|
||
|
externalProcess->tryTerminate();
|
||
|
|
||
|
reject();
|
||
|
}
|
||
|
|
||
|
void Wizard::nextPressed()
|
||
|
{
|
||
|
int currentId = installStack->id(installStack->visibleWidget());
|
||
|
if (currentId == 3)
|
||
|
{
|
||
|
QDir d(kdeDir);
|
||
|
d.mkdir("share/apps/kdesktop/Desktop");
|
||
|
if (shortcutBox->isChecked())
|
||
|
{
|
||
|
QFile source(dir + "/" + desktop);
|
||
|
QString destDir = kdeDir + "/share/apps/kdesktop/Desktop";
|
||
|
int slashPos = desktop.findRev('/');
|
||
|
if (slashPos < 0)
|
||
|
slashPos = 0;
|
||
|
QFile dest(destDir + "/" + desktop.right(desktop.length() - slashPos));
|
||
|
source.open(IO_ReadOnly);
|
||
|
dest.open(IO_WriteOnly | IO_Truncate);
|
||
|
QDataStream destStream(&dest);
|
||
|
QByteArray data = source.readAll();
|
||
|
destStream.writeRawBytes(data.data(), data.size());
|
||
|
source.close();
|
||
|
dest.close();
|
||
|
}
|
||
|
if (uninstallBox->isChecked())
|
||
|
{
|
||
|
QFile source(dir + "/Uninstall TorK.desktop");
|
||
|
QFile dest(kdeDir + "/share/apps/kdesktop/Desktop/Uinstall TorK.desktop");
|
||
|
source.open(IO_ReadOnly);
|
||
|
dest.open(IO_WriteOnly | IO_Truncate);
|
||
|
QDataStream destStream(&dest);
|
||
|
QByteArray data = source.readAll();
|
||
|
destStream.writeRawBytes(data.data(), data.size());
|
||
|
source.close();
|
||
|
dest.close();
|
||
|
}
|
||
|
accept();
|
||
|
return;
|
||
|
}
|
||
|
if ((currentId == 2) && (exec.isEmpty()))
|
||
|
{
|
||
|
accept();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (currentId == 1)
|
||
|
{
|
||
|
bool itemsSelected = false;
|
||
|
|
||
|
QListViewItemIterator it( componentList );
|
||
|
while ( it.current() )
|
||
|
{
|
||
|
if (it.current()->rtti() != 1001)
|
||
|
{
|
||
|
++it;
|
||
|
continue;
|
||
|
}
|
||
|
ComponentListItem* item = (ComponentListItem*) it.current();
|
||
|
if (item->isOn())
|
||
|
itemsSelected = true;
|
||
|
++it;
|
||
|
}
|
||
|
if (!itemsSelected)
|
||
|
{
|
||
|
QMessageBox::warning(this, "Warning", "You need to select at least one component", QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
installStack->raiseWidget(++currentId);
|
||
|
|
||
|
if (currentId == 2)
|
||
|
{
|
||
|
pleaseWaitLabel->setText("Please wait while the software is compiled and installed");
|
||
|
timeRemaining->setText("Estimated time remaining: <b>Calculating...</b>");
|
||
|
startProcess();
|
||
|
nextButton->setEnabled(false);
|
||
|
previousButton->setEnabled(false);
|
||
|
}
|
||
|
else if (currentId == 3)
|
||
|
{
|
||
|
nextButton->setText("Finish");
|
||
|
}
|
||
|
else
|
||
|
previousButton->setEnabled(true);
|
||
|
}
|
||
|
|
||
|
void Wizard::previousPressed()
|
||
|
{
|
||
|
int currentId = installStack->id(installStack->visibleWidget());
|
||
|
if (currentId == 0)
|
||
|
return;
|
||
|
|
||
|
installStack->raiseWidget(--currentId);
|
||
|
|
||
|
if (currentId == 0)
|
||
|
previousButton->setEnabled(false);
|
||
|
nextButton->setEnabled(true);
|
||
|
}
|
||
|
|
||
|
|
||
|
void Wizard::startProcess()
|
||
|
{
|
||
|
selectedComponents.clear();
|
||
|
|
||
|
totalBTime = 0;
|
||
|
elapsedTime = 0;
|
||
|
elapsedBTime = 0;
|
||
|
for ( QStringList::Iterator it = buildOrder.begin(); it != buildOrder.end(); ++it )
|
||
|
{
|
||
|
QListViewItemIterator it2( componentList );
|
||
|
while ( it2.current() )
|
||
|
{
|
||
|
if (it2.current()->rtti() != 1001)
|
||
|
{
|
||
|
++it2;
|
||
|
continue;
|
||
|
}
|
||
|
ComponentListItem* item = (ComponentListItem*) it2.current();
|
||
|
if (item->component.name == *it)
|
||
|
{
|
||
|
if (item->isOn())
|
||
|
{
|
||
|
selectedComponents.append(item->component);
|
||
|
QMap<QString, uint>::iterator it3;
|
||
|
for ( it3 = item->component.buildTimes.begin(); it3 != item->component.buildTimes.end(); ++it3 )
|
||
|
totalBTime += it3.data();
|
||
|
}
|
||
|
}
|
||
|
++it2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
progressBar->setProgress(0);
|
||
|
progressBar->setTotalSteps(totalBTime);
|
||
|
|
||
|
currentComponent = 0;
|
||
|
currentStage = None;
|
||
|
currentIsQMake = false;
|
||
|
|
||
|
nextStep();
|
||
|
}
|
||
|
|
||
|
void Wizard::nextStep()
|
||
|
{
|
||
|
externalProcess->clearArguments();
|
||
|
|
||
|
switch (currentStage)
|
||
|
{
|
||
|
case None:
|
||
|
{
|
||
|
logLine(selectedComponents[currentComponent].niceName);
|
||
|
progressLabel1->setText("<b>Running autogen for " + selectedComponents[currentComponent].niceName + "</b>");
|
||
|
setProgress2Text("");
|
||
|
//progressLabel2->setCursorPosition(0);
|
||
|
currentStage = Autogen;
|
||
|
QDir myDir(dir + "/" + selectedComponents[currentComponent].subDir);
|
||
|
if (myDir.entryList("*.pro", QDir::Files).count() > 0)
|
||
|
{
|
||
|
currentIsQMake = true;
|
||
|
nextStep();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (QFile::exists(dir + "/" + selectedComponents[currentComponent].subDir + "/configure"))
|
||
|
{
|
||
|
nextStep();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
QString autogenName;
|
||
|
if (QFile::exists(dir + "/" + selectedComponents[currentComponent].subDir + "/autogen.sh"))
|
||
|
autogenName = "autogen.sh";
|
||
|
else if (QFile::exists(dir + "/" + selectedComponents[currentComponent].subDir + "/auto-gen.sh"))
|
||
|
autogenName = "auto-gen.sh";
|
||
|
else
|
||
|
{
|
||
|
logLine("No configure, autogen, or qmake scripts found");
|
||
|
errorOccured();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
externalProcess->addArgument(dir + "/" + selectedComponents[currentComponent].subDir + autogenName);
|
||
|
externalProcess->setWorkingDirectory(dir + "/" + selectedComponents[currentComponent].subDir);
|
||
|
logLine("Running autogen...");
|
||
|
externalProcess->start();
|
||
|
break;
|
||
|
}
|
||
|
case Autogen:
|
||
|
{
|
||
|
//progressBar->setProgress(progressBar->progress() + 1);
|
||
|
currentStage = Configure;
|
||
|
if (currentIsQMake)
|
||
|
{
|
||
|
progressLabel1->setText("<b>Running qmake for " + selectedComponents[currentComponent].niceName + "</b>");
|
||
|
setProgress2Text("");
|
||
|
//progressLabel2->setCursorPosition(0);
|
||
|
externalProcess->addArgument("qmake");
|
||
|
externalProcess->setWorkingDirectory(dir + "/" + selectedComponents[currentComponent].subDir);
|
||
|
if (!externalProcess->start())
|
||
|
{
|
||
|
logLine("Error: qmake was not found. Try installing the Qt-devel libraries.");
|
||
|
errorOccured();
|
||
|
return;
|
||
|
}
|
||
|
logLine("Running qmake...");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (!selectedComponents[currentComponent].forceDir.isEmpty())
|
||
|
prefix = selectedComponents[currentComponent].forceDir;
|
||
|
else
|
||
|
prefix = "/usr/local";
|
||
|
|
||
|
externalProcess->addArgument("./configure");
|
||
|
//externalProcess->addArgument("--prefix=" + prefix);
|
||
|
if (!selectedComponents[currentComponent].confOptions.isEmpty())
|
||
|
{
|
||
|
QStringList extraArgs = QStringList::split(" ", sub(selectedComponents[currentComponent].confOptions));
|
||
|
for ( QStringList::Iterator it = extraArgs.begin(); it != extraArgs.end(); ++it )
|
||
|
externalProcess->addArgument(*it);
|
||
|
}
|
||
|
externalProcess->setWorkingDirectory(dir + "/" + selectedComponents[currentComponent].subDir);
|
||
|
logLine("Running configure (" + externalProcess->arguments().join(" ") + ")...");
|
||
|
progressLabel1->setText("<b>Configuring " + selectedComponents[currentComponent].niceName + "</b>");
|
||
|
setProgress2Text("");
|
||
|
timer.start();
|
||
|
externalProcess->start();
|
||
|
break;
|
||
|
}
|
||
|
case Configure:
|
||
|
{
|
||
|
updateTime("configure,");
|
||
|
|
||
|
currentStage = Compile;
|
||
|
|
||
|
externalProcess->addArgument("make");
|
||
|
externalProcess->setWorkingDirectory(dir + "/" + selectedComponents[currentComponent].subDir);
|
||
|
logLine("Running make...");
|
||
|
progressLabel1->setText("<b>Compiling " + selectedComponents[currentComponent].niceName + "</b>");
|
||
|
setProgress2Text("");
|
||
|
timer.setHMS(0, 0, 0);
|
||
|
externalProcess->start();
|
||
|
break;
|
||
|
}
|
||
|
case Compile:
|
||
|
{
|
||
|
currentStage = Install;
|
||
|
|
||
|
logLine("Installing...");
|
||
|
progressLabel1->setText("<b>Installing " + selectedComponents[currentComponent].niceName + "</b>");
|
||
|
setProgress2Text("");
|
||
|
|
||
|
installedFiles.clear();
|
||
|
|
||
|
externalProcess->addArgument("make");
|
||
|
externalProcess->addArgument("install");
|
||
|
externalProcess->setWorkingDirectory(dir + "/" + selectedComponents[currentComponent].subDir);
|
||
|
externalProcess->start();
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case Install:
|
||
|
{
|
||
|
currentStage = WriteUninstallInfo;
|
||
|
logLine("Writing uninstall information...");
|
||
|
progressLabel1->setText("<b>Writing uninstall information for " + selectedComponents[currentComponent].niceName + "</b>");
|
||
|
setProgress2Text("");
|
||
|
|
||
|
QFile postInstallScript("/tmp/arkollon-postinstall.sh");
|
||
|
if (postInstallScript.exists())
|
||
|
postInstallScript.remove();
|
||
|
postInstallScript.open(IO_WriteOnly);
|
||
|
QDataStream stream(&postInstallScript);
|
||
|
stream.writeRawBytes((const char*)postinstall_sh_data, postinstall_sh_len);
|
||
|
postInstallScript.close();
|
||
|
|
||
|
QFile fileList("/tmp/arkollon-filelist");
|
||
|
if (fileList.exists())
|
||
|
fileList.remove();
|
||
|
fileList.open(IO_WriteOnly);
|
||
|
QTextStream fileStream(&fileList);
|
||
|
QStringList doneFiles;
|
||
|
for ( QStringList::Iterator it = installedFiles.begin(); it != installedFiles.end(); ++it )
|
||
|
{
|
||
|
if (doneFiles.find(*it) != doneFiles.end())
|
||
|
continue;
|
||
|
QFileInfo fileInfo(*it);
|
||
|
if (fileInfo.isDir())
|
||
|
continue;
|
||
|
fileStream << (*it) << '\n';
|
||
|
doneFiles.append(*it);
|
||
|
}
|
||
|
fileList.close();
|
||
|
|
||
|
struct Component c = selectedComponents[currentComponent];
|
||
|
int dashPos = c.subDir.findRev('-');
|
||
|
if (dashPos < 0)
|
||
|
dashPos = c.subDir.length();
|
||
|
QString appname = c.subDir.left(dashPos);
|
||
|
QString version = c.subDir.right(c.subDir.length() - dashPos - 1);
|
||
|
|
||
|
externalProcess->addArgument("/bin/sh");
|
||
|
externalProcess->addArgument("/tmp/arkollon-postinstall.sh");
|
||
|
externalProcess->addArgument("--appname");
|
||
|
externalProcess->addArgument(appname);
|
||
|
externalProcess->addArgument("--version");
|
||
|
externalProcess->addArgument(version);
|
||
|
externalProcess->addArgument("--filelist");
|
||
|
externalProcess->addArgument("/tmp/arkollon-filelist");
|
||
|
externalProcess->start();
|
||
|
break;
|
||
|
}
|
||
|
case WriteUninstallInfo:
|
||
|
{
|
||
|
currentStage = None;
|
||
|
currentComponent++;
|
||
|
currentIsQMake = false;
|
||
|
if (currentComponent >= selectedComponents.count())
|
||
|
{
|
||
|
progressLabel1->setText("<b>Installation completed!</b>");
|
||
|
pleaseWaitLabel->setText("Installation complete");
|
||
|
timeRemaining->setText("");
|
||
|
progressBar->setProgress(totalBTime);
|
||
|
nextButton->setEnabled(true);
|
||
|
if (exec.isEmpty())
|
||
|
{
|
||
|
nextButton->setText("Finish");
|
||
|
setProgress2Text("");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
setProgress2Text("Click \"next\" to continue");
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
nextStep();
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Wizard::processExited()
|
||
|
{
|
||
|
if (currentStage == WriteUninstallInfo)
|
||
|
{
|
||
|
// Remove temp files from the last stage
|
||
|
QFile postInstallScript("/tmp/arkollon-postinstall.sh");
|
||
|
if (postInstallScript.exists())
|
||
|
postInstallScript.remove();
|
||
|
|
||
|
QFile fileList("/tmp/arkollon-filelist");
|
||
|
if (fileList.exists())
|
||
|
fileList.remove();
|
||
|
}
|
||
|
if (!externalProcess->normalExit())
|
||
|
{
|
||
|
logLine("Process was killed");
|
||
|
errorOccured();
|
||
|
return;
|
||
|
}
|
||
|
if (externalProcess->exitStatus() != 0)
|
||
|
{
|
||
|
logLine("Return value " + QString::number(externalProcess->exitStatus()));
|
||
|
errorOccured();
|
||
|
return;
|
||
|
}
|
||
|
if (currentStage == Compile)
|
||
|
updateTime(lastTimeLine);
|
||
|
nextStep();
|
||
|
}
|
||
|
|
||
|
void Wizard::readyReadStderr()
|
||
|
{
|
||
|
while (externalProcess->canReadLineStderr())
|
||
|
{
|
||
|
QString line = externalProcess->readLineStderr().latin1();
|
||
|
CompileErrorVector::iterator it;
|
||
|
for( it = errs.begin(); it != errs.end(); ++it ){
|
||
|
if (line.contains((*it).type()))
|
||
|
QMessageBox::information( this, (*it).type(), (*it).message() );
|
||
|
}
|
||
|
logDialog->logBox->append(" * "+line);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Wizard::readyReadStdout()
|
||
|
{
|
||
|
while (externalProcess->canReadLineStdout())
|
||
|
{
|
||
|
QString line = externalProcess->readLineStdout().latin1();
|
||
|
logDialog->logBox->append(line);
|
||
|
|
||
|
if (currentStage == Configure)
|
||
|
{
|
||
|
setProgress2Text(line);
|
||
|
continue;
|
||
|
}
|
||
|
commandLine += line;
|
||
|
if (line.right(1) == "\\")
|
||
|
continue;
|
||
|
commandLine = commandLine.left(commandLine.find(';'));
|
||
|
for ( QValueList<ActionFormat>::Iterator it = actionFormats.begin(); it != actionFormats.end(); ++it )
|
||
|
{
|
||
|
if ((*it).regExp.search(commandLine) == -1)
|
||
|
continue;
|
||
|
setProgress2Text((*it).action + " <b>" + (*it).regExp.cap(1) + "</b> (" + (*it).tool + ")");
|
||
|
if ((currentStage == Install) && ((*it).action == "installing"))
|
||
|
installedFiles.append((*it).regExp.cap(1));
|
||
|
else
|
||
|
updateTime(lastTimeLine);
|
||
|
lastTimeLine = (*it).tool + "," + (*it).regExp.cap(1);
|
||
|
}
|
||
|
commandLine = "";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Wizard::updateTime(QString key)
|
||
|
{
|
||
|
if (!timer.isNull())
|
||
|
{
|
||
|
elapsedBTime += selectedComponents[currentComponent].buildTimes[key];
|
||
|
elapsedTime += timer.elapsed();
|
||
|
float ratio = (float)elapsedTime / (float)elapsedBTime;
|
||
|
int remainingTime = (int)((float)(totalBTime - elapsedBTime) * ratio) / 60000;
|
||
|
if (remainingTime < 0)
|
||
|
remainingTime = 0;
|
||
|
QString text = QString::number(remainingTime + 1) + " minutes";
|
||
|
if (remainingTime == 0)
|
||
|
text = "1 minute";
|
||
|
timeRemaining->setText("Estimated time remaining: <b>" + text + "</b>");
|
||
|
progressBar->setProgress(elapsedBTime);
|
||
|
}
|
||
|
timer.start();
|
||
|
}
|
||
|
|
||
|
void Wizard::logLine(QString line)
|
||
|
{
|
||
|
QString tmp = line;
|
||
|
QStringList lines = QStringList::split("\n", tmp);
|
||
|
for ( QStringList::Iterator it = lines.begin(); it != lines.end(); ++it )
|
||
|
{
|
||
|
if ((*it).isEmpty())
|
||
|
continue;
|
||
|
logDialog->logBox->append("***** "+*it);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Wizard::setProgress2Text(QString text)
|
||
|
{
|
||
|
QString croppedText = text;
|
||
|
int i = croppedText.length();
|
||
|
|
||
|
QFont boldFont = progressLabel2->font();
|
||
|
boldFont.setBold(true);
|
||
|
QFontMetrics boldFontMetrics(boldFont);
|
||
|
while (boldFontMetrics.width(croppedText) > progressLabel2->width())
|
||
|
{
|
||
|
croppedText = croppedText.left(--i);
|
||
|
}
|
||
|
|
||
|
progressLabel2->setText(croppedText);
|
||
|
}
|
||
|
|
||
|
void Wizard::errorOccured()
|
||
|
{
|
||
|
//logFrame->show();
|
||
|
pleaseWaitLabel->setText("An error occured");
|
||
|
progressLabel1->setText("<b>An error occured</b>");
|
||
|
setProgress2Text("See the log file for more information");
|
||
|
previousButton->setEnabled(true);
|
||
|
}
|
||
|
|
||
|
QString Wizard::sub(QString s)
|
||
|
{
|
||
|
QString tmp = s;
|
||
|
tmp.replace(QRegExp("\\$KDEDIR"), kdeDir);
|
||
|
tmp.replace(QRegExp("\\$HOMEDIR"), QDir::homeDirPath());
|
||
|
tmp.replace(QRegExp("~"), QDir::homeDirPath());
|
||
|
tmp.replace(QRegExp("\\$PREFIX"), "/usr/local");
|
||
|
|
||
|
return tmp;
|
||
|
}
|
||
|
|
||
|
void Wizard::runPressed()
|
||
|
{
|
||
|
QProcess* proc = new QProcess(this);
|
||
|
proc->addArgument(exec);
|
||
|
if (!proc->start())
|
||
|
{
|
||
|
QMessageBox::warning(this, "Warning", "The application could not be started<br>"+exec, QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Wizard::logPressed()
|
||
|
{
|
||
|
logDialog->show();
|
||
|
}
|
||
|
|
||
|
#include "wizard.moc"
|
||
|
|