diff options
Diffstat (limited to 'kde2/kpsion')
-rw-r--r-- | kde2/kpsion/Makefile.am | 31 | ||||
-rw-r--r-- | kde2/kpsion/kpsion.cpp | 1046 | ||||
-rw-r--r-- | kde2/kpsion/kpsion.desktop | 10 | ||||
-rw-r--r-- | kde2/kpsion/kpsion.h | 165 | ||||
-rw-r--r-- | kde2/kpsion/kpsionui.rc | 15 | ||||
-rw-r--r-- | kde2/kpsion/lo16-action-psion_backup.png | bin | 0 -> 268 bytes | |||
-rw-r--r-- | kde2/kpsion/lo16-action-psion_restore.png | bin | 0 -> 274 bytes | |||
-rw-r--r-- | kde2/kpsion/lo16-app-kpsion.png | bin | 0 -> 250 bytes | |||
-rw-r--r-- | kde2/kpsion/lo22-action-psion_backup.png | bin | 0 -> 318 bytes | |||
-rw-r--r-- | kde2/kpsion/lo22-action-psion_restore.png | bin | 0 -> 318 bytes | |||
-rw-r--r-- | kde2/kpsion/lo32-action-psion_backup.png | bin | 0 -> 366 bytes | |||
-rw-r--r-- | kde2/kpsion/lo32-action-psion_restore.png | bin | 0 -> 368 bytes | |||
-rw-r--r-- | kde2/kpsion/lo32-app-kpsion.png | bin | 0 -> 309 bytes | |||
-rw-r--r-- | kde2/kpsion/main.cpp | 55 | ||||
-rw-r--r-- | kde2/kpsion/setupdialog.cpp | 62 | ||||
-rw-r--r-- | kde2/kpsion/setupdialog.h | 17 | ||||
-rw-r--r-- | kde2/kpsion/wizards.cpp | 586 | ||||
-rw-r--r-- | kde2/kpsion/wizards.h | 78 |
18 files changed, 2065 insertions, 0 deletions
diff --git a/kde2/kpsion/Makefile.am b/kde2/kpsion/Makefile.am new file mode 100644 index 0000000..85f70fa --- /dev/null +++ b/kde2/kpsion/Makefile.am @@ -0,0 +1,31 @@ +# $Id$ + +METASOURCES = AUTO + +KDE_ICON = AUTO + +INCLUDES = $(all_includes) -I$(top_srcdir)/lib + +DISTCLEANFILES = $(kpsion_METASOURCES) ./.deps/* ./.deps/.P + +lib_LTLIBRARIES = libkpsion.la +bin_PROGRAMS = kpsion + +libkpsion_la_LDFLAGS = $(LIBDEBUG) $(all_libraries) -module -version-info $(LIBVERSION) +libkpsion_la_SOURCES = kpsion.cpp setupdialog.cpp wizards.cpp +libkpsion_la_LIBADD = -L$(top_srcdir)/lib -lplp $(LIB_KFILE) + +kpsion_SOURCES = main.cpp +kpsion_LDFLAGS = $(KDE_RPATH) +kpsion_LDADD = libkpsion.la $(top_srcdir)/lib/libplp.la + +applnk_DATA = kpsion.desktop +applnkdir = $(kde_appsdir)/Utilities + +rcdir = $(kde_datadir)/kpsion +rc_DATA = kpsionui.rc + +noinst_HEADERS = kpsion.h setupdialog.h wizards.h + +messages: + $(XGETTEXT) -C -ki18n -kI18N_NOOP -ktranslate -kaliasLocale *.cpp *.h && mv messages.po ../po/kpsion.pot diff --git a/kde2/kpsion/kpsion.cpp b/kde2/kpsion/kpsion.cpp new file mode 100644 index 0000000..808ed1a --- /dev/null +++ b/kde2/kpsion/kpsion.cpp @@ -0,0 +1,1046 @@ +/*-*-c++-*- + * $Id$ + * + * This file is part of plptools. + * + * Copyright (C) 1999 Philip Proudman <philip.proudman@btinternet.com> + * Copyright (C) 2000, 2001 Fritz Elfert <felfert@to.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "kpsion.h" +#include "wizards.h" + +#include <kapp.h> +#include <klocale.h> +#include <kaction.h> +#include <kstdaction.h> +#include <kconfig.h> +#include <kiconview.h> +#include <kmessagebox.h> +#include <kfileitem.h> + +#include <qwhatsthis.h> +#include <qtimer.h> +#include <qlayout.h> +#include <qiodevice.h> +#include <qdir.h> + +#include <ppsocket.h> +#include <rfsvfactory.h> +#include <rpcsfactory.h> +#include <bufferarray.h> + +#include <iomanip> +#include <strstream> + +// internal use for developing offline without +// having a Psion connected. +// !!!!! set to 0 for production code !!!!! +#define OFFLINE 0 + +#define STID_CONNECTION 1 + +void KPsionCheckListItem:: +init(bool myparent) { + setSelectable(false); + dontPropagate = false; + parentIsKPsionCheckListItem = myparent; +} + +void KPsionCheckListItem:: +setMetaData(int bType, time_t bWhen) { + backupType = bType; + when = bWhen; +} + +void KPsionCheckListItem:: +stateChange(bool state) { + QCheckListItem::stateChange(state); + + if (dontPropagate) + return; + if (parentIsKPsionCheckListItem) + ((KPsionCheckListItem *)parent())->propagateUp(state); + propagateDown(state); +} + +void KPsionCheckListItem:: +propagateDown(bool state) { + setOn(state); + KPsionCheckListItem *child = (KPsionCheckListItem *)firstChild(); + while (child) { + child->propagateDown(state); + child = (KPsionCheckListItem *)child->nextSibling(); + } +} + +void KPsionCheckListItem:: +propagateUp(bool state) { + bool deactivateThis = false; + + KPsionCheckListItem *child = (KPsionCheckListItem *)firstChild(); + while (child) { + if ((child->isOn() != state) || (!child->isEnabled())) { + deactivateThis = true; + break; + } + child = (KPsionCheckListItem *)child->nextSibling(); + } + dontPropagate = true; + if (deactivateThis) { + setOn(true); + setEnabled(false); + } else { + setEnabled(true); + setOn(state); + } + // Bug in QListView? It doesn't update, when + // enabled/disabled without activating. + // -> force it. + listView()->repaintItem(this); + dontPropagate = false; + if (parentIsKPsionCheckListItem) + ((KPsionCheckListItem *)parent())->propagateUp(state); +} + +KPsionBackupListView::KPsionBackupListView(QWidget *parent, const char *name) + : KListView(parent, name) { + + toRestore.clear(); + uid = QString::null; + KConfig *config = kapp->config(); + config->setGroup("Settings"); + backupDir = config->readEntry("BackupDir"); + addColumn(i18n("Available backups")); + setRootIsDecorated(true); +} + +void KPsionBackupListView:: +readBackups(QString uid) { + QString bdir(backupDir); + bdir += "/"; + bdir += uid; + QDir d(bdir); + const QFileInfoList *fil = + d.entryInfoList("*.tar.gz", QDir::Files|QDir::Readable, QDir::Name); + QFileInfoListIterator it(*fil); + QFileInfo *fi; + while ((fi = it.current())) { + bool isValid = false; + KTarGz tgz(fi->absFilePath()); + const KTarEntry *te; + QString bTypeName; + int bType; + QDateTime date; + + tgz.open(IO_ReadOnly); + te = tgz.directory()->entry("KPsionFullIndex"); + if (te && (!te->isDirectory())) { + date.setTime_t(te->date()); + bTypeName = i18n("Full"); + bType = FULL; + isValid = true; + } else { + te = tgz.directory()->entry("KPsionIncrementalIndex"); + if (te && (!te->isDirectory())) { + date.setTime_t(te->date()); + bTypeName = i18n("Incremental"); + bType = INCREMENTAL; + isValid = true; + } + } + + if (isValid) { + QString n = i18n("%1 backup, created at %2").arg(bTypeName).arg(date.toString()); + + KPsionCheckListItem *i = + new KPsionCheckListItem(this, n, + KPsionCheckListItem::CheckBox); + i->setMetaData(bType, te->date()); + i->setPixmap(0, KGlobal::iconLoader()->loadIcon("mime_empty", KIcon::Small)); + QStringList files = tgz.directory()->entries(); + for (QStringList::Iterator f = files.begin(); + f != files.end(); f++) + if ((*f != "KPsionFullIndex") && + (*f != "KPsionIncrementalIndex")) + listTree(i, tgz.directory()->entry(*f), 0); + } + tgz.close(); + ++it; + } +} + +void KPsionBackupListView:: +listTree(KPsionCheckListItem *cli, const KTarEntry *te, int level) { + KPsionCheckListItem *i = + new KPsionCheckListItem(cli, te->name(), + KPsionCheckListItem::CheckBox); + if (te->isDirectory()) { + if (level) + i->setPixmap(0, KGlobal::iconLoader()->loadIcon("folder", + KIcon::Small)); + else + i->setPixmap(0, KGlobal::iconLoader()->loadIcon("hdd_unmount", + KIcon::Small)); + KTarDirectory *td = (KTarDirectory *)te; + QStringList files = td->entries(); + for (QStringList::Iterator f = files.begin(); f != files.end(); f++) + listTree(i, td->entry(*f), level + 1); + } else + i->setPixmap(0, KGlobal::iconLoader()->loadIcon("mime_empty", + KIcon::Small)); +} + +PlpDir &KPsionBackupListView:: +getRestoreList() { + return toRestore; +} + +KPsionMainWindow::KPsionMainWindow() + : KMainWindow() { + setupActions(); + + statusBar()->insertItem(i18n("Idle"), STID_CONNECTION, 1); + statusBar()->setItemAlignment(STID_CONNECTION, + QLabel::AlignLeft|QLabel::AlignVCenter); + + backupRunning = false; + restoreRunning = false; + formatRunning = false; + + view = new KIconView(this, "iconview"); + view->setSelectionMode(KIconView::Multi); + view->setResizeMode(KIconView::Adjust); + view->setItemsMovable(false); + connect(view, SIGNAL(clicked(QIconViewItem *)), + SLOT(iconClicked(QIconViewItem *))); + connect(view, SIGNAL(onItem(QIconViewItem *)), + SLOT(iconOver(QIconViewItem *))); + KConfig *config = kapp->config(); + config->setGroup("Psion"); + QStringList uids = config->readListEntry("MachineUIDs"); + for (QStringList::Iterator it = uids.begin(); it != uids.end(); it++) { + QString tmp = QString::fromLatin1("Name_%1").arg(*it); + machines.insert(*it, config->readEntry(tmp)); + } + config->setGroup("Settings"); + backupDir = config->readEntry("BackupDir"); + config->setGroup("Connection"); + reconnectTime = config->readNumEntry("Retry"); + ncpdDevice = config->readEntry("Device", i18n("off")); + ncpdSpeed = config->readNumEntry("Speed", 115200); + + QWhatsThis::add(view, i18n( + "<qt>Here, you see your Psion's drives.<br/>" + "Every drive is represented by an Icon. If you " + "click on it, it gets selected for the next " + "operation. E.g.: backup, restore or format.<br/>" + "To unselect it, simply click on it again.<br/>" + "Select as many drives a you want, then choose " + "an operation.</qt>")); + setCentralWidget(view); + + rfsvSocket = 0L; + rpcsSocket = 0L; + plpRfsv = 0L; + plpRpcs = 0L; + + firstTry = true; + connected = false; + shuttingDown = false; + + tryConnect(); +} + +KPsionMainWindow::~KPsionMainWindow() { + shuttingDown = true; + if (plpRfsv) + delete plpRfsv; + if (plpRpcs) + delete plpRpcs; + if (rfsvSocket) + delete rfsvSocket; + if (rfsvSocket) + delete rpcsSocket; +} + +void KPsionMainWindow:: +setupActions() { + + KStdAction::quit(this, SLOT(close()), actionCollection()); + KStdAction::showToolbar(this, SLOT(slotToggleToolbar()), + actionCollection()); + KStdAction::showStatusbar(this, SLOT(slotToggleStatusbar()), + actionCollection()); + KStdAction::saveOptions(this, SLOT(slotSaveOptions()), + actionCollection()); + KStdAction::preferences(this, SLOT(slotPreferences()), + actionCollection()); + new KAction(i18n("Start &Format"), 0L, 0, this, + SLOT(slotStartFormat()), actionCollection(), "format"); + new KAction(i18n("Start Full &Backup"), "psion_backup", 0, this, + SLOT(slotStartFullBackup()), actionCollection(), + "fullbackup"); + new KAction(i18n("Start &Incremental Backup"), "psion_backup", 0, this, + SLOT(slotStartIncBackup()), actionCollection(), "incbackup"); + new KAction(i18n("Start &Restore"), "psion_restore", 0, this, + SLOT(slotStartRestore()), actionCollection(), "restore"); + createGUI(); + + actionCollection()->action("fullbackup")->setEnabled(false); + actionCollection()->action("incbackup")->setEnabled(false); +#if OFFLINE + actionCollection()->action("restore")->setEnabled(true); +#else + actionCollection()->action("restore")->setEnabled(false); +#endif + actionCollection()->action("format")->setEnabled(false); + + actionCollection()->action("fullbackup")-> + setToolTip(i18n("Full backup of selected drive(s)")); + actionCollection()->action("incbackup")-> + setToolTip(i18n("Incremental backup of selected drive(s)")); + actionCollection()->action("restore")-> + setToolTip(i18n("Restore selected drive(s)")); + actionCollection()->action("format")-> + setToolTip(i18n("Format selected drive(s)")); +} + +void KPsionMainWindow:: +iconOver(QIconViewItem *i) { + lastSelected = i->isSelected(); +} + +void KPsionMainWindow:: +switchActions() { + QIconViewItem *i; + bool rwSelected = false; + bool anySelected = false; + + if (backupRunning | restoreRunning | formatRunning) + view->setEnabled(false); + else { + for (i = view->firstItem(); i; i = i->nextItem()) { + if (i->isSelected()) { + anySelected = true; + if (i->key() != "Z") { + rwSelected = true; + break; + } + } + } + view->setEnabled(true); + } +#if OFFLINE + actionCollection()->action("restore")->setEnabled(true); +#else + actionCollection()->action("restore")->setEnabled(rwSelected); +#endif + actionCollection()->action("format")->setEnabled(rwSelected); + actionCollection()->action("fullbackup")->setEnabled(anySelected); + actionCollection()->action("incbackup")->setEnabled(anySelected); +} + +void KPsionMainWindow:: +iconClicked(QIconViewItem *i) { + if (i == 0L) + return; + lastSelected = !lastSelected; + i->setSelected(lastSelected); + switchActions(); +} + +void KPsionMainWindow:: +insertDrive(char letter, const char * const name) { + QString tmp; + + if (name && strlen(name)) + tmp = QString::fromLatin1("%1 (%2:)").arg(name).arg(letter); + else + tmp = QString::fromLatin1("%1:").arg(letter); + drives.insert(letter,tmp); + QIconViewItem *it = + new QIconViewItem(view, tmp, + KFileItem(KURL(), "inode/x-psion-drive", 0).pixmap(0)); + tmp = QString::fromLatin1("%1").arg(letter); + it->setKey(tmp); + it->setDropEnabled(false); + it->setDragEnabled(false); + it->setRenameEnabled(false); +} + +void KPsionMainWindow:: +queryPsion() { + u_int32_t devbits; + Enum <rfsv::errs> res; + + statusBar()->changeItem(i18n("Retrieving machine info ..."), + STID_CONNECTION); +#if OFFLINE + machineUID = 0x1000118a0c428fa3ULL; + S5mx = true; + insertDrive('C', "Intern"); + insertDrive('D', "Flash"); + insertDrive('Z', "RomDrive"); +#else + rpcs::machineInfo mi; + if ((res = plpRpcs->getMachineInfo(mi)) != rfsv::E_PSI_GEN_NONE) { + QString msg = i18n("Could not get Psion machine info"); + statusBar()->changeItem(msg, STID_CONNECTION); + KMessageBox::error(this, msg); + return; + } + machineUID = mi.machineUID; + S5mx = (strcmp(mi.machineName, "SERIES5mx") == 0); +#endif + + QString uid = getMachineUID(); + bool machineFound = false; + KConfig *config = kapp->config(); + config->setGroup("Psion"); + machineName = i18n("an unknown machine"); + psionMap::Iterator it; + for (it = machines.begin(); it != machines.end(); it++) { + if (uid == it.key()) { + machineName = it.data(); + QString tmp = + QString::fromLatin1("BackupDrives_%1").arg(it.key()); + backupDrives = config->readListEntry(tmp); + machineFound = true; + } + } +#if (!(OFFLINE)) + drives.clear(); + statusBar()->changeItem(i18n("Retrieving drive list ..."), + STID_CONNECTION); + if ((res = plpRfsv->devlist(devbits)) != rfsv::E_PSI_GEN_NONE) { + QString msg = i18n("Could not get list of drives"); + statusBar()->changeItem(msg, STID_CONNECTION); + KMessageBox::error(this, msg); + return; + } + for (int i = 0; i < 26; i++) { + if ((devbits & 1) != 0) { + PlpDrive drive; + if (plpRfsv->devinfo(i, drive) == rfsv::E_PSI_GEN_NONE) + insertDrive('A' + i, drive.getName().c_str()); + } + devbits >>= 1; + } +#endif + if (!machineFound) { + NewPsionWizard *wiz = new NewPsionWizard(this, "newpsionwiz"); + wiz->exec(); + } + statusBar()->changeItem(i18n("Connected to %1").arg(machineName), + STID_CONNECTION); +} + +QString KPsionMainWindow:: +getMachineUID() { + // ??! None of QString's formatting methods knows about long long. + ostrstream s; + s << hex << setw(16) << machineUID; + QString ret = s.str(); + ret = ret.left(16); + return ret; +} + +bool KPsionMainWindow:: +queryClose() { + QString msg = 0L; + + if (backupRunning) + msg = i18n("A backup is running.\nDo you really want to quit?"); + if (restoreRunning) + msg = i18n("A restore is running.\nDo you really want to quit?"); + if (formatRunning) + msg = i18n("A format is running.\nDo you really want to quit?"); + + if ((!msg.isNull()) && + (KMessageBox::warningYesNo(this, msg) == KMessageBox::No)) + return false; + return true; +} + +void KPsionMainWindow:: +tryConnect() { +#if (!(OFFLINE)) + if (shuttingDown || connected) + return; + bool showMB = firstTry; + firstTry = false; + + if (plpRfsv) + delete plpRfsv; + if (plpRpcs) + delete plpRpcs; + if (rfsvSocket) + delete rfsvSocket; + if (rfsvSocket) + delete rpcsSocket; + + rfsvSocket = new ppsocket(); + statusBar()->changeItem(i18n("Connecting ..."), STID_CONNECTION); + if (!rfsvSocket->connect(NULL, 7501)) { + statusMsg = i18n("RFSV could not connect to ncpd at %1:%2. ").arg("localhost").arg(7501); + if (reconnectTime) { + nextTry = reconnectTime; + statusMsg += i18n(" (Retry in %1 seconds.)"); + QTimer::singleShot(1000, this, SLOT(slotUpdateTimer())); + } + statusBar()->changeItem(statusMsg.arg(reconnectTime), + STID_CONNECTION); + if (showMB) + KMessageBox::error(this, statusMsg.arg(reconnectTime)); + return; + } + rfsvfactory factory(rfsvSocket); + plpRfsv = factory.create(false); + if (plpRfsv == 0L) { + statusMsg = i18n("RFSV could not establish link: %1.").arg(factory.getError()); + delete rfsvSocket; + rfsvSocket = 0L; + if (reconnectTime) { + nextTry = reconnectTime; + statusMsg += i18n(" (Retry in %1 seconds.)"); + QTimer::singleShot(1000, this, SLOT(slotUpdateTimer())); + } + statusBar()->changeItem(statusMsg.arg(reconnectTime), + STID_CONNECTION); + if (showMB) + KMessageBox::error(this, statusMsg.arg(reconnectTime)); + return; + } + + rpcsSocket = new ppsocket(); + if (!rpcsSocket->connect(NULL, 7501)) { + statusMsg = i18n("RPCS could not connect to ncpd at %1:%2.").arg("localhost").arg(7501); + delete plpRfsv; + plpRfsv = 0L; + delete rfsvSocket; + rfsvSocket = 0L; + if (reconnectTime) { + nextTry = reconnectTime; + statusMsg += i18n(" (Retry in %1 seconds.)"); + QTimer::singleShot(1000, this, SLOT(slotUpdateTimer())); + } + statusBar()->changeItem(statusMsg.arg(reconnectTime), + STID_CONNECTION); + if (showMB) + KMessageBox::error(this, statusMsg.arg(reconnectTime)); + return; + } + rpcsfactory factory2(rpcsSocket); + plpRpcs = factory2.create(false); + if (plpRpcs == 0L) { + statusMsg = i18n("RPCS could not establish link: %1.").arg(factory.getError()); + delete plpRfsv; + plpRfsv = 0L; + delete rfsvSocket; + rfsvSocket = 0L; + delete rpcsSocket; + rpcsSocket = 0L; + if (reconnectTime) { + nextTry = reconnectTime; + statusMsg += i18n(" (Retry in %1 seconds.)"); + QTimer::singleShot(1000, this, SLOT(slotUpdateTimer())); + } + statusBar()->changeItem(statusMsg.arg(reconnectTime), + STID_CONNECTION); + if (showMB) + KMessageBox::error(this, statusMsg.arg(reconnectTime)); + return; + } +#endif + connected = true; + queryPsion(); +} + +void KPsionMainWindow:: +slotUpdateTimer() { + nextTry--; + if (nextTry <= 0) + tryConnect(); + else { + statusBar()->changeItem(statusMsg.arg(nextTry), STID_CONNECTION); + QTimer::singleShot(1000, this, SLOT(slotUpdateTimer())); + } +} + +void KPsionMainWindow:: +slotStartFullBackup() { + fullBackup = true; + doBackup(); +} + +void KPsionMainWindow:: +slotStartIncBackup() { + fullBackup = false; + doBackup(); +} + +void KPsionMainWindow:: +doBackup() { + backupRunning = true; + switchActions(); + toBackup.clear(); + KDialog *d = new KDialog(this, "backupDialog", false); + d->setCaption(i18n("Backup")); + QGridLayout *gl = new QGridLayout(d); + progressLabel = new KSqueezedTextLabel(d); + gl->addWidget(progressLabel, 1, 1); + progress = new KProgress(0, 100, 0, KProgress::Horizontal, d, + "backupProgress"); + + gl->addWidget(progress, 2, 1); + gl->addRowSpacing(0, KDialog::marginHint()); + gl->addRowSpacing(3, KDialog::marginHint()); + gl->addColSpacing(0, KDialog::marginHint()); + gl->addColSpacing(2, KDialog::marginHint()); + gl->setColStretch(1, 1); + gl->setRowStretch(1, 1); + d->setMinimumSize(250, 80); + d->show(); + + // Collect list of files to backup + backupSize = 0; + backupCount = 0; + progressTotal = 0; + for (QIconViewItem *i = view->firstItem(); i; i = i->nextItem()) { + if (i->isSelected()) { + QString drv = i->key(); + drv += ":"; + int drvNum = *(drv.data()) - 'A'; + PlpDrive drive; + if (plpRfsv->devinfo(drvNum, drive) != rfsv::E_PSI_GEN_NONE) { + KMessageBox::error(this, i18n("Could not retrieve drive details for drive %1").arg(drv)); + d->hide(); + delete d; + backupRunning = false; + switchActions(); + return; + } + progressLabel->setText(i18n("Scanning drive %1").arg(drv)); + + progressLocal = drive.getSize() - drive.getSpace(); + progressLocalCount = 0; + progressLocalPercent = -1; + progress->setValue(0); + collectFiles(drv); + } + } + progressLabel->setText(i18n("%1 files need backup").arg(backupSize)); + if (backupCount == 0) { + KMessageBox::information(this, i18n("No files need backup")); + d->hide(); + delete d; + backupRunning = false; + switchActions(); + return; + } + + statusBar()->message(i18n("Backup")); + progressCount = 0; + progressTotal = backupSize; + progressPercent = -1; + + // Create tgz with index file. + QString archiveName = backupDir; + if (archiveName.right(1) != "/") + archiveName += "/"; + archiveName += getMachineUID(); + QDir archiveDir(archiveName); + if (!archiveDir.exists()) + if (!archiveDir.mkdir(archiveName)) { + KMessageBox::error(this, i18n("Could not create backup folder %1").arg(archiveName)); + d->hide(); + delete d; + statusBar()->clear(); + backupRunning = false; + switchActions(); + return; + } + + archiveName += (fullBackup) ? "/F-" : "/I-"; + time_t now = time(0); + char tstr[30]; + strftime(tstr, sizeof(tstr), "%Y-%m-%d-%H-%M-%S.tar.gz", + localtime(&now)); + archiveName += tstr; + backupTgz = new KTarGz(archiveName); + backupTgz->open(IO_WriteOnly); + createIndex(); + + // Kill all running applications on the Psion + // and save their state. + killSave(); + + bool badBackup = false; + Enum<rfsv::errs> res; + // Now the real backup + for (int i = 0; i < toBackup.size(); i++) { + PlpDirent e = toBackup[i]; + const char *fn = e.getName(); + const char *p; + char *q; + char unixname[1024]; + + for (p = fn, q = unixname; *p; p++, q++) + switch (*p) { + case '%': + *q++ = '%'; + *q++ = '2'; + *q = '5'; + break; + case '/': + *q++ = '%'; + *q++ = '2'; + *q= 'f'; + break; + case '\\': + *q = '/'; + break; + default: + *q = *p; + } + *q = '\0'; + + ostrstream os; + + progressLabel->setText(i18n("Backing up %1").arg(fn)); + progressLocal = e.getSize(); + progressLocalCount = 0; + progressLocalPercent = -1; + progress->setValue(0); + + u_int32_t handle; + + kapp->processEvents(); + res = plpRfsv->fopen(plpRfsv->opMode(rfsv::PSI_O_RDONLY), fn, + handle); + if (res != rfsv::E_PSI_GEN_NONE) { + if (KMessageBox::warningYesNo(this, i18n("<QT>Could not open<BR/><B>%1</B></QT>").arg(fn)) == KMessageBox::No) { + badBackup = true; + break; + } else { + e.setName("!"); + continue; + } + } + unsigned char *buff = new unsigned char[RFSV_SENDLEN]; + u_int32_t len; + do { + if ((res = plpRfsv->fread(handle, buff, RFSV_SENDLEN, len)) == + rfsv::E_PSI_GEN_NONE) { + os.write(buff, len); + updateProgress(len); + } + kapp->processEvents(); + } while ((len > 0) && (res == rfsv::E_PSI_GEN_NONE)); + delete[]buff; + plpRfsv->fclose(handle); + if (res != rfsv::E_PSI_GEN_NONE) { + if (KMessageBox::warningYesNo(this, i18n("<QT>Could not read<BR/><B>%1</B></QT>").arg(fn)) == KMessageBox::No) { + badBackup = true; + break; + } else { + e.setName("!"); + continue; + } + } + backupTgz->writeFile(unixname, "root", "root", os.pcount(), + os.str()); + } + + if (!badBackup) { + // Reset archive attributes of all backuped files. + progressLabel->setText(i18n("Resetting archive attributes ...")); + progressLocal = backupSize; + progressLocalCount = 0; + progressLocalPercent = -1; + progress->setValue(0); + for (int i = 0; i < toBackup.size(); i++) { + PlpDirent e = toBackup[i]; + const char *fn = e.getName(); + if ((e.getAttr() & rfsv::PSI_A_ARCHIVE) && + (strcmp(fn, "!") != 0)) { + kapp->processEvents(); + res = plpRfsv->fsetattr(fn, 0, rfsv::PSI_A_ARCHIVE); + if (res != rfsv::E_PSI_GEN_NONE) { + if (KMessageBox::warningYesNo(this, i18n("<QT>Could not set attributes of<BR/><B>%1</B></QT>").arg(fn)) == KMessageBox::No) { + break; + } + } + } + updateProgress(e.getSize()); + } + } + // Restart previously running applications on the Psion + // from saved state info. + runRestore(); + + backupTgz->close(); + delete backupTgz; + if (badBackup) + unlink(archiveName.data()); + d->hide(); + delete d; + backupRunning = false; + switchActions(); + statusBar()->message(i18n("Backup done"), 2000); +} + +void KPsionMainWindow:: +slotStartRestore() { + restoreRunning = true; + switchActions(); + + KDialog *d = new KDialog(this, "restoreDialog", true); + d->setCaption(i18n("Restore")); + QGridLayout *gl = new QGridLayout(d); + //progressLabel = new KSqueezedTextLabel(d); + KPsionBackupListView *v = new KPsionBackupListView(d, "restoreSelector"); + gl->addWidget(v, 1, 1); + //progress = new KProgress(0, 100, 0, KProgress::Horizontal, d, "restoreProgress"); + + //gl->addWidget(progress, 2, 1); + gl->addRowSpacing(0, KDialog::marginHint()); + gl->addRowSpacing(3, KDialog::marginHint()); + gl->addColSpacing(0, KDialog::marginHint()); + gl->addColSpacing(2, KDialog::marginHint()); + gl->setColStretch(1, 1); + gl->setRowStretch(1, 1); + d->setMinimumSize(250, 80); + v->readBackups(getMachineUID()); + d->exec(); + + d->hide(); + delete d; + restoreRunning = false; + switchActions(); + statusBar()->message(i18n("Restore done"), 2000); +} + +void KPsionMainWindow:: +slotStartFormat() { + if (KMessageBox::warningYesNo(this, i18n( + "<QT>This erases <B>ALL</B> data " + "on the drive(s).<BR/>Do you really " + "want to proceed?" + )) == KMessageBox::No) + return; + formatRunning = true; + switchActions(); +} + +void KPsionMainWindow:: +slotToggleToolbar() { + if (toolBar()->isVisible()) + toolBar()->hide(); + else + toolBar()->show(); +} + +void KPsionMainWindow:: +slotToggleStatusbar() { + if (statusBar()->isVisible()) + statusBar()->hide(); + else + statusBar()->show(); +} + +void KPsionMainWindow:: +slotSaveOptions() { +} + +void KPsionMainWindow:: +slotPreferences() { +} + +void KPsionMainWindow:: +updateProgress(unsigned long amount) { + progressLocalCount += amount; + int lastPercent = progressLocalPercent; + if (progressLocal) + progressLocalPercent = progressLocalCount * 100 / progressLocal; + else + progressLocalPercent = 100; + if (progressLocalPercent != lastPercent) + progress->setValue(progressLocalPercent); + if (progressTotal > 0) { + progressCount += amount; + lastPercent = progressPercent; + if (progressTotal) + progressPercent = progressCount * 100 / progressTotal; + else + progressPercent = 100; + if (progressPercent != lastPercent) + statusBar()->message(i18n("Backup %1% complete").arg(progressPercent)); + } +} + +void KPsionMainWindow:: +collectFiles(QString dir) { + Enum<rfsv::errs> res; + PlpDir files; + QString tmp = dir; + + kapp->processEvents(); + tmp += "\\"; + if ((res = plpRfsv->dir(tmp.data(), files)) != rfsv::E_PSI_GEN_NONE) { + // messagebox "Couldn't get directory ...." + } else + for (int i = 0; i < files.size(); i++) { + PlpDirent e = files[i]; + + + long attr = e.getAttr(); + tmp = dir; + tmp += "\\"; + tmp += e.getName(); + if (attr & rfsv::PSI_A_DIR) { + collectFiles(tmp); + } else { + kapp->processEvents(); + updateProgress(e.getSize()); + if ((attr & rfsv::PSI_A_ARCHIVE) || fullBackup) { + backupCount++; + backupSize += e.getSize(); + e.setName(tmp.data()); + toBackup.push_back(e); + } + } + } +} + +void KPsionMainWindow:: +killSave() { + Enum<rfsv::errs> res; + bufferArray tmp; + + savedCommands.clear(); + if ((res = plpRpcs->queryDrive('C', tmp)) != rfsv::E_PSI_GEN_NONE) { + cerr << "Could not get process list, Error: " << res << endl; + return; + } else { + while (!tmp.empty()) { + QString pbuf; + bufferStore cmdargs; + bufferStore bs = tmp.pop(); + int pid = bs.getWord(0); + const char *proc = bs.getString(2); + if (S5mx) + pbuf.sprintf("%s.$%02d", proc, pid); + else + pbuf.sprintf("%s.$%d", proc, pid); + bs = tmp.pop(); + if (plpRpcs->getCmdLine(pbuf.data(), cmdargs) == 0) { + QString cmdline(cmdargs.getString(0)); + cmdline += " "; + cmdline += bs.getString(0); + savedCommands += cmdline; + } + progressLabel->setText(i18n("Stopping %1").arg(cmdargs.getString(0))); + kapp->processEvents(); + plpRpcs->stopProgram(pbuf); + } + } + return; +} + +void KPsionMainWindow:: +runRestore() { + Enum<rfsv::errs> res; + + for (QStringList::Iterator it = savedCommands.begin(); it != savedCommands.end(); it++) { + int firstBlank = (*it).find(' '); + QString cmd = (*it).left(firstBlank); + QString arg = (*it).mid(firstBlank + 1); + + if (!cmd.isEmpty()) { + // Workaround for broken programs like Backlite. + // These do not storethe full program path. + // In that case we try running the arg1 which + // results in starting the program via recog. facility. + progressLabel->setText(i18n("Starting %1").arg(cmd)); + kapp->processEvents(); + if ((arg.length() > 2) && (arg[1] == ':') && (arg[0] >= 'A') && + (arg[0] <= 'Z')) + res = plpRpcs->execProgram(arg.data(), ""); + else + res = plpRpcs->execProgram(cmd.data(), arg.data()); + if (res != rfsv::E_PSI_GEN_NONE) { + // If we got an error here, that happened probably because + // we have no path at all (e.g. Macro5) and the program is + // not registered in the Psion's path properly. Now try + // the ususal \System\Apps\<AppName>\<AppName>.app + // on all drives. + if (cmd.find('\\') == -1) { + driveMap::Iterator it; + for (it = drives.begin(); it != drives.end(); it++) { + QString newcmd = QString::fromLatin1("%1:\\System\\Apps\\%2\\%3").arg(it.key()).arg(cmd).arg(cmd); + res = plpRpcs->execProgram(newcmd.data(), ""); + if (res == rfsv::E_PSI_GEN_NONE) + break; + newcmd += ".app"; + res = plpRpcs->execProgram(newcmd.data(), ""); + if (res == rfsv::E_PSI_GEN_NONE) + break; + + } + } + } + } + } + return; +} + +void KPsionMainWindow:: +createIndex() { + ostrstream os; + os << "#plpbackup index " << + (fullBackup ? "F" : "I") << endl; + for (int i = 0; i < toBackup.size(); i++) { + PlpDirent e = toBackup[i]; + PsiTime t = e.getPsiTime(); + long attr = e.getAttr() & + ~rfsv::PSI_A_ARCHIVE; + os << hex + << setw(8) << setfill('0') << + t.getPsiTimeHi() << " " + << setw(8) << setfill('0') << + t.getPsiTimeLo() << " " + << setw(8) << setfill('0') << + e.getSize() << " " + << setw(8) << setfill('0') << + attr << " " + << setw(0) << e.getName() << endl; + kapp->processEvents(); + } + backupTgz->writeFile("Index", "root", "root", os.pcount(), os.str()); +} + +/* + * Local variables: + * c-basic-offset: 4 + * End: + */ diff --git a/kde2/kpsion/kpsion.desktop b/kde2/kpsion/kpsion.desktop new file mode 100644 index 0000000..e29bb73 --- /dev/null +++ b/kde2/kpsion/kpsion.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +DocPath=kpsion/index.html +Exec=kpsion +Terminal=0 +Type=Application +Icon=psion_desktop +Comment=My Psion PDA +Comment[de]=Mein Psion +Name=KPsion +Name[de]=KPsion diff --git a/kde2/kpsion/kpsion.h b/kde2/kpsion/kpsion.h new file mode 100644 index 0000000..86aeff4 --- /dev/null +++ b/kde2/kpsion/kpsion.h @@ -0,0 +1,165 @@ +#ifndef _KPSION_H_ +#define _KPSION_H_ + +#include "setupdialog.h" + +#include <kmainwindow.h> +#include <kiconview.h> +#include <kprogress.h> +#include <ksqueezedtextlabel.h> +#include <klistview.h> +#include <ktar.h> + +#include <rfsv.h> +#include <rpcs.h> +#include <ppsocket.h> + +typedef QMap<char,QString> driveMap; +typedef QMap<QString,QString> psionMap; + +class KPsionCheckListItem : public QCheckListItem { + public: + KPsionCheckListItem(KPsionCheckListItem *parent, const QString &text, + Type tt) + : QCheckListItem(parent, text, tt) { init(true); } + KPsionCheckListItem(QCheckListItem *parent, const QString &text, Type tt) + : QCheckListItem(parent, text, tt) { init(false); } + KPsionCheckListItem(QListViewItem *parent, const QString &text, Type tt) + : QCheckListItem(parent, text, tt) { init(false); } + KPsionCheckListItem(QListView *parent, const QString &text, Type tt) + : QCheckListItem(parent, text, tt) { init(false); } + KPsionCheckListItem(QListViewItem *parent, const QString &text, + const QPixmap &p) + : QCheckListItem(parent, text, p) { init(false); } + KPsionCheckListItem(QListView *parent, const QString &text, + const QPixmap &p) + : QCheckListItem(parent, text, p) { init(false); } + void setMetaData(int, time_t); + + protected: + virtual void stateChange(bool); + void propagateUp(bool); + void propagateDown(bool); + + private: + void init(bool); + + bool parentIsKPsionCheckListItem; + bool dontPropagate; + int backupType; + time_t when; +}; + +class KPsionBackupListView : public KListView { + Q_OBJECT + public: + enum backupTypes { + UNKNOWN = 0, + FULL = 1, + INCREMENTAL = 2, + }; + + KPsionBackupListView(QWidget *parent = 0, const char *name = 0); + void readBackups(QString uid); + PlpDir &getRestoreList(); + + private: + void listTree(KPsionCheckListItem *cli, const KTarEntry *te, int level); + + QString uid; + QString backupDir; + PlpDir toRestore; +}; + +class KPsionMainWindow : public KMainWindow { + Q_OBJECT + + public: + KPsionMainWindow(); + ~KPsionMainWindow(); + void setMachineName(QString &_name) { machineName = _name; } + QString getMachineUID(); + driveMap &getDrives() { return drives; } + psionMap &getMachines() { return machines; } + QString &getMachineName() { return machineName; } + QString &getBackupDir() { return backupDir; } + + public slots: + void slotStartRestore(); + void slotStartFullBackup(); + void slotStartIncBackup(); + void slotStartFormat(); + void slotToggleToolbar(); + void slotToggleStatusbar(); + void slotSaveOptions(); + void slotPreferences(); + + protected: + virtual bool queryClose(); + void setupActions(); + void switchActions(); + void queryPsion(); + void insertDrive(char letter, const char * const name); + + private slots: + void iconClicked(QIconViewItem *i); + void iconOver(QIconViewItem *i); + void slotUpdateTimer(); + + private: + void doBackup(); + void tryConnect(); + void updateProgress(unsigned long); + void collectFiles(QString dir); + void killSave(); + void runRestore(); + void createIndex(); + + rfsv *plpRfsv; + rpcs *plpRpcs; + ppsocket *rfsvSocket; + ppsocket *rpcsSocket; + SetupDialog *setupDialog; + KIconView *view; + KProgress *progress; + KSqueezedTextLabel *progressLabel; + KTarGz *backupTgz; + + driveMap drives; + psionMap machines; + QStringList backupDrives; + QStringList savedCommands; + QString backupDir; + QString machineName; + QString statusMsg; + QString ncpdDevice; + bool S5mx; + bool backupRunning; + bool restoreRunning; + bool formatRunning; + bool lastSelected; + bool connected; + bool firstTry; + bool shuttingDown; + bool fullBackup; + int reconnectTime; + int nextTry; + int ncpdSpeed; + unsigned long long machineUID; + PlpDir toBackup; + unsigned long backupSize; + unsigned long backupCount; + unsigned long progressTotal; + unsigned long progressLocal; + unsigned long progressCount; + unsigned long progressLocalCount; + int progressPercent; + int progressLocalPercent; +}; + +#endif +/* + * Local variables: + * c-basic-offset: 4 + * End: + */ diff --git a/kde2/kpsion/kpsionui.rc b/kde2/kpsion/kpsionui.rc new file mode 100644 index 0000000..17302c5 --- /dev/null +++ b/kde2/kpsion/kpsionui.rc @@ -0,0 +1,15 @@ +<!DOCTYPE kpartgui> +<kpartgui name="kpsion"> + <MenuBar> + <Menu name="file"><text>&File</text> + <Action name="fullbackup"/> + <Action name="incbackup"/> + <Action name="restore"/> + <Action name="format"/> + </Menu> + </MenuBar> + <ToolBar fullWidth="true" name="mainToolBar"> + <Action name="fullbackup"/> + <Action name="restore"/> + </ToolBar> +</kpartgui> diff --git a/kde2/kpsion/lo16-action-psion_backup.png b/kde2/kpsion/lo16-action-psion_backup.png Binary files differnew file mode 100644 index 0000000..4d0f815 --- /dev/null +++ b/kde2/kpsion/lo16-action-psion_backup.png diff --git a/kde2/kpsion/lo16-action-psion_restore.png b/kde2/kpsion/lo16-action-psion_restore.png Binary files differnew file mode 100644 index 0000000..8f3103b --- /dev/null +++ b/kde2/kpsion/lo16-action-psion_restore.png diff --git a/kde2/kpsion/lo16-app-kpsion.png b/kde2/kpsion/lo16-app-kpsion.png Binary files differnew file mode 100644 index 0000000..2382c76 --- /dev/null +++ b/kde2/kpsion/lo16-app-kpsion.png diff --git a/kde2/kpsion/lo22-action-psion_backup.png b/kde2/kpsion/lo22-action-psion_backup.png Binary files differnew file mode 100644 index 0000000..b5ebd45 --- /dev/null +++ b/kde2/kpsion/lo22-action-psion_backup.png diff --git a/kde2/kpsion/lo22-action-psion_restore.png b/kde2/kpsion/lo22-action-psion_restore.png Binary files differnew file mode 100644 index 0000000..47780b8 --- /dev/null +++ b/kde2/kpsion/lo22-action-psion_restore.png diff --git a/kde2/kpsion/lo32-action-psion_backup.png b/kde2/kpsion/lo32-action-psion_backup.png Binary files differnew file mode 100644 index 0000000..4a99260 --- /dev/null +++ b/kde2/kpsion/lo32-action-psion_backup.png diff --git a/kde2/kpsion/lo32-action-psion_restore.png b/kde2/kpsion/lo32-action-psion_restore.png Binary files differnew file mode 100644 index 0000000..782e2d9 --- /dev/null +++ b/kde2/kpsion/lo32-action-psion_restore.png diff --git a/kde2/kpsion/lo32-app-kpsion.png b/kde2/kpsion/lo32-app-kpsion.png Binary files differnew file mode 100644 index 0000000..7285992 --- /dev/null +++ b/kde2/kpsion/lo32-app-kpsion.png diff --git a/kde2/kpsion/main.cpp b/kde2/kpsion/main.cpp new file mode 100644 index 0000000..df909ef --- /dev/null +++ b/kde2/kpsion/main.cpp @@ -0,0 +1,55 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "kpsion.h" +#include "wizards.h" +#include <kapp.h> +#include <klocale.h> +#include <kconfig.h> +#include <kcmdlineargs.h> +#include <kaboutdata.h> + +static KCmdLineOptions options[] = { + {"b", 0, 0}, + {"backup", I18N_NOOP("perform backup"), 0}, + {"r", 0, 0}, + {"restore", I18N_NOOP("perform restore"), 0}, + {"f", 0, 0}, + {"format", I18N_NOOP("format drive"), 0}, + {"+[DriveLetter]", I18N_NOOP("The drive letter to backup/restore or format."), 0}, + { 0, 0, 0}, +}; + +int main(int argc, char **argv) { + KAboutData *about = new KAboutData("kpsion", I18N_NOOP("KPsion"), + VERSION, I18N_NOOP("Psion connectivity utility"), + KAboutData::License_GPL, + "(C) 2001, Fritz Elfert", 0L, + "http://plptools.sourceforge.net", + "plptools-developers@sourceforge.net"); + about->addAuthor("Fritz Elfert", I18N_NOOP("Original Developer/Maintainer"), + "felfert@users.sourceforge.net", + "http://plptools.sourceforge.net"); + KCmdLineArgs::init(argc, argv, about); + KCmdLineArgs::addCmdLineOptions(options); + + KApplication a; + + KConfig *config = kapp->config(); + config->setGroup("Settings"); + QString backupDir = config->readEntry("BackupDir"); + + if (backupDir.isEmpty()) { + FirstTimeWizard *wiz = new FirstTimeWizard(0L, "firsttimewizard"); + wiz->exec(); + } + + KPsionMainWindow *w = new KPsionMainWindow(); + w->resize(300, 150); + a.setMainWidget(w); + w->show(); + return a.exec(); +} + + diff --git a/kde2/kpsion/setupdialog.cpp b/kde2/kpsion/setupdialog.cpp new file mode 100644 index 0000000..370bb30 --- /dev/null +++ b/kde2/kpsion/setupdialog.cpp @@ -0,0 +1,62 @@ +#include "setupdialog.h" + +#include <kapp.h> +#include <kconfig.h> +#include <klocale.h> +#include <knuminput.h> +#include <klineedit.h> +#include <kcombobox.h> + +#include <qlayout.h> +#include <qlabel.h> + +SetupDialog::SetupDialog(QWidget *parent, rfsv *plpRfsv, rpcs *plpRpcs) + : KDialogBase(Tabbed, "Settings", Ok|Apply|Default|Cancel, Ok, parent, + "settingsDialog", true, true) { + + enableLinkedHelp(true); + + KConfig *config = kapp->config(); + QFrame *page = addPage(i18n("&General")); + QGridLayout *gl = new QGridLayout(page, 4, 2, 15); + gl->addRowSpacing(0, 10); + QLabel *l; + + l = new QLabel(i18n("Backup &directory"), page, "backupDirLabel"); + gl->addWidget(l, 1, 0); + KLineEdit *bdiredit = new KLineEdit(page, "backupDirEdit"); + gl->addWidget(bdiredit, 1 , 1); + l->setBuddy(bdiredit); + QPushButton *bdirbutton = new QPushButton(i18n("Browse"), page, "backupDirButton"); + gl->addWidget(bdirbutton, 1 , 2); + + l = new QLabel(i18n("Backup &generations"), page, "backupGenLabel"); + gl->addMultiCellWidget(l, 2, 2, 0, 1); + KIntSpinBox *genspin = new KIntSpinBox(0, 10, 1, 3, 10, page, "backupGenSpin"); + gl->addWidget(genspin, 2, 2); + l->setBuddy(genspin); + + page = addPage(i18n("&Machines")); + gl = new QGridLayout(page, 4, 2, 15); + gl->addRowSpacing(0, 10); + + l = new QLabel(i18n("Machine &Name"), page, "NameLabel"); + gl->addWidget(l, 1, 0); + KLineEdit *nedit = new KLineEdit(page, "NameEdit"); + gl->addWidget(nedit, 1, 1); + l->setBuddy(nedit); + l = new QLabel(i18n("Machine &UID"), page, "UIDLabel"); + gl->addWidget(l, 2, 0); + KComboBox *uidcombo = new KComboBox(true, page, "UIDCombo"); + config->setGroup("Psion"); + uidcombo->insertStringList(config->readListEntry("MachineUIDs")); + gl->addWidget(uidcombo, 1, 1); + l->setBuddy(uidcombo); + + connect(this, SIGNAL(defaultClicked()), SLOT(slotDefaultClicked())); +} + +void SetupDialog:: +slotDefaultClicked() { + enableLinkedHelp(false); +} diff --git a/kde2/kpsion/setupdialog.h b/kde2/kpsion/setupdialog.h new file mode 100644 index 0000000..b385dce --- /dev/null +++ b/kde2/kpsion/setupdialog.h @@ -0,0 +1,17 @@ +#ifndef _SETUPDIALOGS_H_ +#define _SETUPDIALOGS_H_ + +#include <rfsv.h> +#include <rpcs.h> + +#include <kdialogbase.h> + +class SetupDialog : public KDialogBase { + public: + SetupDialog(QWidget *parent, rfsv *plpRfsv, rpcs *plpRpcs); + + private slots: + void slotDefaultClicked(); +}; + +#endif diff --git a/kde2/kpsion/wizards.cpp b/kde2/kpsion/wizards.cpp new file mode 100644 index 0000000..24cd121 --- /dev/null +++ b/kde2/kpsion/wizards.cpp @@ -0,0 +1,586 @@ +/*-*-c++-*- + * $Id$ + * + * This file is part of plptools. + * + * Copyright (C) 2001 Fritz Elfert <felfert@to.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <sys/types.h> +#include <unistd.h> +#include <pwd.h> + +#include "wizards.h" + +#include <kapp.h> +#include <kdebug.h> +#include <kdialog.h> +#include <klocale.h> +#include <kfiledialog.h> +#include <kmessagebox.h> + +#include <qlayout.h> +#include <qwhatsthis.h> +#include <qheader.h> + +FirstTimeWizard::FirstTimeWizard(QWidget *parent, const char *name) + : KWizard(parent, name, true) { + + setCaption(i18n("KPsion Setup")); + QWhatsThis::add(nextButton(), + i18n("Click this button to continue with the next page.")); + QWhatsThis::add(backButton(), + i18n("Click this button, to go to a previous page.")); + QWhatsThis::add(cancelButton(), + i18n("<QT>If you click this button, the setup of <B>KPSion</B> will be aborted and next time you start <B>KPsion</B>, it will run this setup again.</QT>")); + + // Getting the users home directory from the passwd-entry is MUCH safer + // than getting it from $HOME !!! (Environments can be tweaked) + struct passwd *pw = getpwuid(getuid()); + bdirDefault = QString((pw) ? pw->pw_dir : 0L); + if (bdirDefault.isEmpty()) + bdirDefault = QDir::homeDirPath(); + bdirDefault += "/KPsionBackup"; + bdirCreated = ""; + + // Page 1 + page1 = new QWidget(this, "welcome"); + QGridLayout *grid = new QGridLayout(page1); + + QLabel *l = new QLabel(page1, "welcome message"); + l->setText(i18n( + "<QT>" + "<H2>Welcome to KPsion!</H2>" + "It looks like you started <B>KPsion</B> the first time. " + "At least, i could not find any valid configuration.</BR>" + "On the following pages, we will gather some information, " + "which is needed for working with <B>KPsion</B>.</BR>" + " </BR>" + "Have fun." + "</QT>" + )); + grid->addWidget(l, 1, 1, Qt::AlignTop); + grid->setColStretch(1, 1); + grid->setRowStretch(1, 1); + grid->addRowSpacing(0, KDialog::marginHint()); + grid->addRowSpacing(2, KDialog::marginHint()); + grid->addColSpacing(0, KDialog::marginHint()); + grid->addColSpacing(2, KDialog::marginHint()); + addPage(page1, i18n("<QT><BIG><B>Welcome<B></BIG></QT>")); + + // Page 2 + page2 = new QWidget(this, "step1"); + grid = new QGridLayout(page2); + + l = new QLabel(page2, "step1"); + l->setText(i18n( + "<QT>" + "First, we need a folder for storing backups of " + "your Psion. You probably don't want others to " + "have access to it, so it's best to choose a " + "location somewhere in your home directory. " + "Please browse through existing folders and select a suitable " + "location or simply accept the default shown below." + "</QT>" + )); + grid->addMultiCellWidget(l, 1, 1, 1, 2, Qt::AlignTop); + + bdirLabel = new QLabel(page2, "bdirLabel"); + bdirLabel->setText(bdirDefault); + bdirButton = new QPushButton(i18n("Browse"), page2); + + QWhatsThis::add(bdirLabel, + i18n("This is the name of the backup folder.")); + QWhatsThis::add(bdirButton, + i18n("Click here, for opening a dialog which lets you easily select the backup folder.")); + grid->addWidget(bdirLabel, 3, 1); + grid->addWidget(bdirButton, 3, 2); + + grid->setRowStretch(1, 1); + grid->setColStretch(1, 1); + + grid->addRowSpacing(2, KDialog::spacingHint()); + + grid->addRowSpacing(0, KDialog::marginHint()); + grid->addRowSpacing(4, KDialog::marginHint()); + grid->addColSpacing(0, KDialog::marginHint()); + grid->addColSpacing(3, KDialog::marginHint()); + + connect(bdirButton, SIGNAL(clicked()), SLOT(slotBdirBrowse())); + addPage(page2, i18n("<QT><BIG><B>Step 1</B></BIG> - Specify backup directory</QT>")); + // Page 3 + page3 = new QWidget(this, "step2"); + grid = new QGridLayout(page3); + + l = new QLabel(page3, "step2"); + l->setText(i18n( + "<QT>" + "Next, please specify some information regarding " + "backup policy:<UL><LI>How many generations of backups " + "do you want to keep?</LI><LI>Shall i remind you about " + "backups?</LI><LI>If yes, in what intervals do you want " + "to happen backups?</LI></UL>" + "</QT>" + )); + grid->addMultiCellWidget(l, 1, 1, 1, 2, Qt::AlignTop); + + l = new QLabel(i18n("&Incremental backup reminder"), page3, "iBackupIntLabel"); + grid->addWidget(l, 3, 1); + iIntCombo = new KComboBox(false, page3, "iIntCombo"); + iIntCombo->insertItem(i18n("none")); + iIntCombo->insertItem(i18n("daily")); + iIntCombo->insertItem(i18n("every 2 days")); + iIntCombo->insertItem(i18n("every 3 days")); + iIntCombo->insertItem(i18n("every 4 days")); + iIntCombo->insertItem(i18n("every 5 days")); + iIntCombo->insertItem(i18n("every 6 days")); + iIntCombo->insertItem(i18n("weekly")); + iIntCombo->insertItem(i18n("every 2 weeks")); + iIntCombo->insertItem(i18n("every 3 weeks")); + iIntCombo->insertItem(i18n("monthly")); + iIntCombo->setCurrentItem(1); + grid->addWidget(iIntCombo, 3, 2); + l->setBuddy(iIntCombo); + + l = new QLabel(i18n("&Full backup reminder"), page3, "fBackupIntLabel"); + grid->addWidget(l, 5, 1); + fIntCombo = new KComboBox(false, page3, "fIntCombo"); + fIntCombo->insertItem(i18n("none")); + fIntCombo->insertItem(i18n("daily")); + fIntCombo->insertItem(i18n("every 2 days")); + fIntCombo->insertItem(i18n("every 3 days")); + fIntCombo->insertItem(i18n("every 4 days")); + fIntCombo->insertItem(i18n("every 5 days")); + fIntCombo->insertItem(i18n("every 6 days")); + fIntCombo->insertItem(i18n("weekly")); + fIntCombo->insertItem(i18n("every 2 weeks")); + fIntCombo->insertItem(i18n("every 3 weeks")); + fIntCombo->insertItem(i18n("monthly")); + fIntCombo->setCurrentItem(7); + grid->addWidget(fIntCombo, 5, 2); + l->setBuddy(fIntCombo); + + l = new QLabel(i18n("Backup &generations"), page3, "backupGenLabel"); + grid->addWidget(l, 7, 1); + genSpin = new KIntSpinBox(0, 10, 1, 3, 10, page3, "backupGenSpin"); + grid->addWidget(genSpin, 7, 2); + l->setBuddy(genSpin); + + grid->setRowStretch(1, 1); + grid->setColStretch(1, 1); + + grid->addRowSpacing(2, KDialog::spacingHint()); + grid->addRowSpacing(4, KDialog::spacingHint()); + grid->addRowSpacing(6, KDialog::spacingHint()); + + grid->addRowSpacing(0, KDialog::marginHint()); + grid->addRowSpacing(8, KDialog::marginHint()); + grid->addColSpacing(0, KDialog::marginHint()); + grid->addColSpacing(3, KDialog::marginHint()); + + addPage(page3, i18n("<QT><BIG><B>Step 2</B></BIG> - Backup policy</QT>")); + + // Page 4 + page4 = new QWidget(this, "step3"); + grid = new QGridLayout(page4); + + l = new QLabel(page4, "step2"); + l->setText(i18n( + "<QT>" + "If no connection could be established on startup, " + "<B>KPsion</B> will attempt to connect in regular " + "intervals. Please specify the interval after which " + "a connection attempt should happen. If you don't want " + "automatic retry, set the interval to zero. Furthermore, " + "<B>KPsion</B> can try to start ncpd if it is not already " + "running. For that to work correctly, you need to" + "<UL><LI>specify the serial port to use.</LI>" + "<LI>specify the baud rate</LI>" + "<LI>have permission to use the specified port</LI></UL>" + "</QT>" + )); + grid->addMultiCellWidget(l, 1, 1, 1, 2, Qt::AlignTop); + + l = new QLabel(i18n("&Connection retry interval (sec.)"), page4, "rconLabel"); + grid->addWidget(l, 3, 1); + rconSpin = new KIntSpinBox(0, 600, 1, 30, 10, page4, "rconSpin"); + grid->addWidget(rconSpin, 3, 2); + l->setBuddy(rconSpin); + + l = new QLabel(i18n("Serial &device"), page4, "devLabel"); + grid->addWidget(l, 5, 1); + devCombo = new KComboBox(false, page4, "devCombo"); + devCombo->insertItem(i18n("off")); + devCombo->insertItem(i18n("/dev/ttyS0")); + devCombo->insertItem(i18n("/dev/ttyS1")); + devCombo->insertItem(i18n("/dev/ttyS2")); + devCombo->insertItem(i18n("/dev/ttyS3")); + devCombo->insertItem(i18n("/dev/ircomm0")); + devCombo->insertItem(i18n("/dev/ircomm1")); + devCombo->insertItem(i18n("/dev/ircomm2")); + devCombo->insertItem(i18n("/dev/ircomm3")); + devCombo->setCurrentItem(0); + grid->addWidget(devCombo, 5, 2); + l->setBuddy(devCombo); + + l = new QLabel(i18n("Serial &speed"), page4, "speedLabel"); + grid->addWidget(l, 7, 1); + speedCombo = new KComboBox(false, page4, "speedCombo"); + speedCombo->insertItem("9600"); + speedCombo->insertItem("19200"); + speedCombo->insertItem("38400"); + speedCombo->insertItem("57600"); + speedCombo->insertItem("115200"); + speedCombo->setCurrentItem(4); + grid->addWidget(speedCombo, 7, 2); + l->setBuddy(speedCombo); + + grid->setRowStretch(1, 1); + grid->setColStretch(1, 1); + + grid->addRowSpacing(2, KDialog::spacingHint()); + grid->addRowSpacing(4, KDialog::spacingHint()); + grid->addRowSpacing(6, KDialog::spacingHint()); + + grid->addRowSpacing(0, KDialog::marginHint()); + grid->addRowSpacing(8, KDialog::marginHint()); + grid->addColSpacing(0, KDialog::marginHint()); + grid->addColSpacing(3, KDialog::marginHint()); + + addPage(page4, i18n("<QT><BIG><B>Step 3</B></BIG> - Connection parameters</QT>")); + + // Page 5 + page5 = new QWidget(this, "step3"); + grid = new QGridLayout(page5); + + l = new QLabel(page5, "step2"); + l->setText(i18n( + "<QT>" + "That's it!<BR/>" + "Next, i will start <B>KPsion</B> and if your Psion is already " + "connected and it's communication turned on (use " + "<B>Ctrl-T</B> at system level), then <B>KPsion</B> will " + "bring up a similar Dialog like this which lets you assing a " + "Name for it. After that, i suggest performing a full " + "Backup.<BR/>Please click <B>Finish</B> now.</QT>" + )); + grid->addWidget(l, 1, 1, Qt::AlignTop); + + grid->setRowStretch(1, 1); + grid->setColStretch(1, 1); + + grid->addRowSpacing(0, KDialog::marginHint()); + grid->addRowSpacing(2, KDialog::marginHint()); + grid->addColSpacing(0, KDialog::marginHint()); + grid->addColSpacing(2, KDialog::marginHint()); + + addPage(page5, i18n("<QT><BIG><B>Finished</B></BIG></QT>")); + + setFinishEnabled(page5, true); +} + +void FirstTimeWizard:: +slotBdirBrowse() { + QString dir = KFileDialog::getExistingDirectory(bdirLabel->text(), this, + i18n("Backup folder")); + checkBackupDir(dir); +} + +void FirstTimeWizard:: +reject() { + // kapp->quit() and [QK]Application::exit(0) don't work here?! + // probably because we didn't call kapp->exec() yet? + // -> brute force + if (KMessageBox::questionYesNo(this, + i18n("<QT>You are about to abort the initial setup of <B>KPsion</B>. No configuration will be stored and you will have to repeat this procedure when you start <B>KPsion</B> next time.<BR/>Do you really want to exit now?</QT>")) == KMessageBox::Yes) { + if (!bdirCreated.isEmpty()) + ::rmdir(bdirCreated.data()); + ::exit(0); + } +} + +void FirstTimeWizard:: +accept() { + KConfig *config = kapp->config(); + config->setGroup("Settings"); + config->writeEntry("BackupDir", bdirLabel->text()); + config->writeEntry("BackupGenerations", genSpin->value()); + config->writeEntry("IncrementalInterval", iIntCombo->currentItem()); + config->writeEntry("FullInterval", fIntCombo->currentItem()); + config->setGroup("Connection"); + config->writeEntry("Retry", rconSpin->value()); + config->writeEntry("Device", devCombo->currentText()); + config->writeEntry("Speed", speedCombo->currentText()); + hide(); + setResult(Accepted); +} + +void FirstTimeWizard:: +next() { + for (int i = 0; i < pageCount(); i++) + if (currentPage() == page(i)) { + switch (i) { + case 1: + QString dir(bdirLabel->text()); + if (!checkBackupDir(dir)) + return; + } + break; + } + KWizard::next(); +} + +void FirstTimeWizard:: +closeEvent(QCloseEvent *e) { + reject(); +} + +bool FirstTimeWizard:: +checkBackupDir(QString &dir) { + if (!bdirCreated.isEmpty()) { + if (bdirCreated != dir) { + ::rmdir(bdirCreated.data()); + bdirCreated = ""; + } + } + if (!dir.isEmpty()) { + QDir d(dir); + if (!d.exists()) { + if (KMessageBox::questionYesNo(this, + i18n("<QT>The folder <B>%1</B> does <B>not</B> exist.<BR/>Shall it be created?</QT>").arg(dir)) == KMessageBox::No) { + bdirLabel->setText(bdirDefault); + return false; + } + if (mkdir(dir.data(), 0700) != 0) { + QString msg = i18n("<QT>The specified folder<BR/><B>%1</B><BR/>could <B>not</B> be created"); + switch (errno) { + case EACCES: + case EPERM: + case EROFS: + msg += i18n(", because you either don't have sufficient rights to do that, or the filesystem is readonly."); + // Insufficient permissions/ readonly FS + break; + case ENOSPC: + msg += i18n(", because the filesystem has not enough space."); + // No space + break; + case EEXIST: + // shouldn't happen, we checked already + // for existence. + msg += i18n(", because there already exists another object with the same name."); + break; + case EFAULT: + case ENOMEM: + case ENAMETOOLONG: + // shouldn't happen. + msg += "."; + break; + case ENOENT: + // propably dangling symlink + msg += i18n(", because you specified a path which probably contains a dangling symbolic link."); + break; + case ENOTDIR: + msg += i18n(", because you specified a path which contains an element which is not a folder."); + // path element not dir. + break; + case ELOOP: + msg += i18n(", because you specified a path which contains too many symbolic links."); + // Too many symlinks + break; + + + } + bdirLabel->setText(bdirDefault); + msg += i18n("<BR/>Please select another folder.</QT>"); + KMessageBox::error(this, msg.arg(dir)); + return false; + } + bdirCreated = dir; + } + bdirLabel->setText(dir); + return true; + } + bdirLabel->setText(bdirDefault); + return false; +} + +NewPsionWizard::NewPsionWizard(QWidget *parent, const char *name) + : KWizard(parent, name, true) { + + setCaption(i18n("New Psion detected")); + psion = (KPsionMainWindow *)parent; + + QWhatsThis::add(nextButton(), + i18n("Click this button to continue with the next page.")); + QWhatsThis::add(backButton(), + i18n("Click this button, to go to a previous page.")); + QWhatsThis::add(cancelButton(), + i18n("<QT>If you click this button, the setup for the new connected Psion will be aborted and next time you connect this Psion again, <B>KPsion</B> will run this setup again.</QT>")); + + // Page 1 + page1 = new QWidget(this, "newmachine"); + QGridLayout *grid = new QGridLayout(page1); + + QLabel *l = new QLabel(page1, "newmachmessage"); + uid = psion->getMachineUID(); + l->setText(i18n( + "<QT>" + "The Psion with the unique ID <B>%1</B> " + "is connected the first time. Please assign a name to it." + "</QT>").arg(uid)); + grid->addMultiCellWidget(l, 1, 1, 1, 2, Qt::AlignTop); + + l = new QLabel(page1, "nameLabel"); + l->setText(i18n("&Name of new Psion")); + nameEdit = new KLineEdit(page1, "nameEdit"); + nameEdit->setText(i18n("My new Psion")); + nameEdit->selectAll(); + nameEdit->setFocus(); + l->setBuddy(nameEdit); + grid->addWidget(l, 3, 1); + grid->addWidget(nameEdit, 3, 2); + + grid->setColStretch(1, 1); + grid->setRowStretch(1, 1); + + grid->addRowSpacing(2, KDialog::spacingHint()); + + grid->addRowSpacing(0, KDialog::marginHint()); + grid->addRowSpacing(4, KDialog::marginHint()); + grid->addColSpacing(0, KDialog::marginHint()); + grid->addColSpacing(2, KDialog::marginHint()); + + addPage(page1, i18n("<QT><BIG><B>New Psion detected<B></BIG></QT>")); + + // Page 2 + page2 = new QWidget(this, "bdrives"); + grid = new QGridLayout(page2); + + l = new QLabel(page2, "bdrivemessage"); + l->setText(i18n( + "<QT>" + "Please select the Drive(s), you want to be backed up when " + "running in unattended backup mode." + "</QT>" + )); + grid->addMultiCellWidget(l, 1, 1, 1, 3, Qt::AlignTop); + + backupListView = new KListView(page2, "bdriveListView"); + backupListView->addColumn(i18n("Available drives")); + driveMap dlist = psion->getDrives(); + driveMap::Iterator it; + int height = backupListView->header()->height(); + for (it = dlist.begin(); it != dlist.end(); it++) { + QCheckListItem *i = new QCheckListItem(backupListView, it.data(), + QCheckListItem::CheckBox); + height += i->height(); + i->setSelectable(false); + } + backupListView->setMaximumSize(backupListView->columnWidth(0) + 5, height + 5); + grid->addWidget(backupListView, 3, 2); + + grid->setColStretch(1, 1); + grid->setRowStretch(1, 1); + grid->setColStretch(3, 1); + + grid->addRowSpacing(2, KDialog::spacingHint()); + + grid->addRowSpacing(0, KDialog::marginHint()); + grid->addRowSpacing(4, KDialog::marginHint()); + grid->addColSpacing(0, KDialog::marginHint()); + grid->addColSpacing(4, KDialog::marginHint()); + + addPage(page2, i18n("<QT><BIG><B>Specify drives to backup<B></BIG></QT>")); + + setFinishEnabled(page2, true); +} + +void NewPsionWizard:: +next() { + for (int i = 0; i < pageCount(); i++) + if (currentPage() == page(i)) { + switch (i) { + case 0: + QString tmp(nameEdit->text()); + if (!checkPsionName(tmp)) + return; + } + break; + } + KWizard::next(); +} + +bool NewPsionWizard:: +checkPsionName(QString &name) { + KConfig *config = kapp->config(); + if (name.isEmpty()) { + KMessageBox::sorry(this, i18n("The name cannot be empty.")); + return false; + } + psionMap l = psion->getMachines(); + psionMap::Iterator it; + for (it = l.begin(); it != l.end(); it++) { + if (name == it.data()) { + KMessageBox::sorry(this, i18n("<QT>The name <B>%1</B> is already assigned to another machine.<BR/>Please choose a different name.</QT>")); + return false; + } + } + return true; +} + +void NewPsionWizard:: +accept() { + KConfig *config = kapp->config(); + config->setGroup("Psion"); + QStringList machines = config->readListEntry("MachineUIDs"); + machines += uid; + config->writeEntry("MachineUIDs", machines); + QString tmp = QString::fromLatin1("Name_%1").arg(uid); + config->writeEntry(tmp, nameEdit->text()); + tmp = nameEdit->text(); + psion->setMachineName(tmp); + QListViewItemIterator li(backupListView); + driveMap dlist = psion->getDrives(); + driveMap::Iterator di; + QStringList bdrives; + for (; li.current(); li++) { + QCheckListItem *qcli = (QCheckListItem *)(li.current()); + if (qcli->isOn()) { + tmp = qcli->text(); + for (di = dlist.begin(); di != dlist.end(); di++) + if (di.data() == tmp) { + QString drv = ""; + drv += di.key(); + bdrives += drv; + } + } + } + config->writeEntry("BackupDrives", bdrives); + hide(); + setResult(Accepted); +} + +/* + * Local variables: + * c-basic-offset: 4 + * End: + */ diff --git a/kde2/kpsion/wizards.h b/kde2/kpsion/wizards.h new file mode 100644 index 0000000..6edd8d9 --- /dev/null +++ b/kde2/kpsion/wizards.h @@ -0,0 +1,78 @@ +#ifndef _WIZARDS_H_ +#define _WIZARDS_H_ + +#include "kpsion.h" + +#include <kwizard.h> +#include <knuminput.h> +#include <kcombobox.h> +#include <klineedit.h> +#include <klistview.h> + +#include <qpushbutton.h> +#include <qcheckbox.h> +#include <qlabel.h> + +class FirstTimeWizard : public KWizard { + Q_OBJECT + public: + FirstTimeWizard(QWidget *parent = 0, const char *name = 0); + + protected: + virtual void closeEvent(QCloseEvent *e); + virtual void reject(); + virtual void accept(); + + protected slots: + virtual void next(); + + private slots: + void slotBdirBrowse(); + + private: + bool checkBackupDir(QString &); + + QWidget *page1; + QWidget *page2; + QWidget *page3; + QWidget *page4; + QWidget *page5; + QLabel *bdirLabel; + KIntSpinBox *genSpin; + KIntSpinBox *rconSpin; + QPushButton *bdirButton; + QCheckBox *remCheck; + KComboBox *iIntCombo; + KComboBox *fIntCombo; + KComboBox *devCombo; + KComboBox *speedCombo; + + QString bdirDefault; + QString bdirCreated; +}; + +class NewPsionWizard : public KWizard { + Q_OBJECT + + public: + NewPsionWizard(QWidget *parent = 0, const char *name = 0); + + protected: + virtual void accept(); + + protected slots: + virtual void next(); + + private: + bool checkPsionName(QString &); + + QWidget *page1; + QWidget *page2; + KPsionMainWindow *psion; + KLineEdit *nameEdit; + KListView *backupListView; + + QString uid; + QString machineName; +}; +#endif |