Add a DeviceScanner class. Move code to scan for devices from

core/libparted.cpp to this new class and use this class in
PartitionManagerWidget

Move the libparted-specific code to inspect _one_ device to a static method in
LibParted.

Make scanning for devices asynchronous with the new DeviceScanner class.

Introduce a progress dialog to show progress while scanning.

Rename the progress dialog for applying operations to something less generic.

Remove the signal emitted when the status bar should change: It's the same
logic used for the signal emitted when operations change.

Remove the onFinished() method in PartitionManagerWidget and directly connect
the finished signal from the apply-progress-dialog to the scanDevices slot.

Rename the PartitionManagerWidget::selectionChanged() signal to the less generic
PartitionManagerWidget::selectedPartitionChanged().

Rename PartitionManagerWidget::clearSelection() to the less generic
PartitionManagerWidget::clearSelectedPartition().

NOTE: The DeviceScanner class is a thread and exposes some race conditions if
not used with caution (aka workarounds). See comments in
PartitionManagerWidget::onScanDevicesFinished().

svn path=/trunk/extragear/sysadmin/partitionmanager/; revision=1088844
This commit is contained in:
Volker Lanz 2010-02-11 18:47:51 +00:00
parent 75181b6d2f
commit 6f5680866c
20 changed files with 470 additions and 228 deletions

View File

@ -0,0 +1,93 @@
/***************************************************************************
* Copyright (C) 2010 by Volker Lanz <vl@fidra.de *
* *
* 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 Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
#include "core/devicescanner.h"
#include "core/libparted.h"
#include "core/operationstack.h"
#include "core/device.h"
#include <solid/device.h>
#include <solid/deviceinterface.h>
#include <solid/block.h>
#include <solid/storagedrive.h>
/** Constructs a DeviceScanner
@param ostack the OperationStack where the devices will be created
*/
DeviceScanner::DeviceScanner(OperationStack& ostack) :
QThread(),
m_LibParted(),
m_OperationStack(ostack)
{
}
void DeviceScanner::clear()
{
operationStack().clearOperations();
emit operationsChanged();
operationStack().clearDevices();
emit devicesChanged();
}
static quint32 countDevices(const QList<Solid::Device>& driveList)
{
quint32 rval = 0;
foreach(const Solid::Device& solidDevice, driveList)
{
const Solid::StorageDrive* solidDrive = solidDevice.as<Solid::StorageDrive>();
if (solidDrive->driveType() == Solid::StorageDrive::HardDisk)
rval++;
}
return rval;
}
void DeviceScanner::run()
{
clear();
const QList<Solid::Device> driveList = Solid::Device::listFromType(Solid::DeviceInterface::StorageDrive, QString());
const quint32 totalDevices = countDevices(driveList);
quint32 count = 0;
foreach(const Solid::Device& solidDevice, driveList)
{
const Solid::StorageDrive* solidDrive = solidDevice.as<Solid::StorageDrive>();
if (solidDrive->driveType() != Solid::StorageDrive::HardDisk)
continue;
const Solid::Block* solidBlock = solidDevice.as<Solid::Block>();
Device* d = libParted().scanDevice(solidBlock->device());
if (d != NULL)
{
d->setIconName(solidDevice.icon());
operationStack().addDevice(d);
emit devicesChanged();
}
emit progressChanged(solidBlock->device(), (++count) * 100 / totalDevices);
}
operationStack().sortDevices();
}

64
src/core/devicescanner.h Normal file
View File

@ -0,0 +1,64 @@
/***************************************************************************
* Copyright (C) 2010 by Volker Lanz <vl@fidra.de> *
* *
* 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 Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
#ifndef DEVICESCANNER_H
#define DEVICESCANNER_H
#include <QThread>
#include "core/libparted.h"
class OperationStack;
/** @brief Thread to scan for all available Devices on this computer.
This class is used to find all Devices on the computer and to create new Device instances for each of them. It's subclassing QThread to run asynchronously.
@author vl@fidra.de
*/
class DeviceScanner : public QThread
{
Q_OBJECT
public:
DeviceScanner(OperationStack& ostack);
public:
void clear(); /**< clear Devices and the OperationStack */
signals:
void progressChanged(const QString& device_node, int progress);
void devicesChanged();
void operationsChanged();
protected:
virtual void run();
OperationStack& operationStack() { return m_OperationStack; }
const OperationStack& operationStack() const { return m_OperationStack; }
LibParted& libParted() { return m_LibParted; }
const LibParted& libParted() const { return m_LibParted; }
private:
LibParted m_LibParted;
OperationStack& m_OperationStack;
};
#endif

View File

@ -45,11 +45,6 @@
#include <kmountpoint.h>
#include <kdiskfreespaceinfo.h>
#include <solid/device.h>
#include <solid/deviceinterface.h>
#include <solid/block.h>
#include <solid/storagedrive.h>
#include <parted/parted.h>
#include <unistd.h>
@ -289,60 +284,30 @@ LibParted::LibParted()
ped_exception_set_handler(pedExceptionHandler);
}
/** Scans for all available Devices on this computer.
This method tries to find all Devices on the computer and creates new Device instances for each of them. It then calls scanDevicePartitions() to find all Partitions and FileSystems on each Device and set those up.
The method will clear the list of operations and devices currently in the OperationStack given.
@param ostack the OperationStack where the devices will be created
*/
void LibParted::scanDevices(OperationStack& ostack)
Device* LibParted::scanDevice(const QString& device_node)
{
ostack.clearOperations();
ostack.clearDevices();
PedDevice* pedDevice = ped_device_get(device_node.toLocal8Bit());
// LibParted's ped_device_probe_all()
// 1) segfaults when it finds "illegal" entries in /dev/mapper
// 2) takes several minutes to time out if the BIOS says there's a floppy drive present
// when in fact there is none.
// For that reason we scan devices on our own using Solid now.
const QList<Solid::Device> driveList = Solid::Device::listFromType(Solid::DeviceInterface::StorageDrive, QString());
foreach(const Solid::Device& solidDevice, driveList)
if (pedDevice == NULL)
{
const Solid::StorageDrive* solidDrive = solidDevice.as<Solid::StorageDrive>();
if (solidDrive->driveType() != Solid::StorageDrive::HardDisk)
continue;
const Solid::Block* solidBlock = solidDevice.as<Solid::Block>();
PedDevice* pedDevice = ped_device_get(solidBlock->device().toLocal8Bit());
if (pedDevice == NULL)
{
Log(Log::warning) << i18nc("@info/plain", "Could not access device <filename>%1</filename>", solidBlock->device());
continue;
}
Log(Log::information) << i18nc("@info/plain", "Device found: %1", pedDevice->model);
Device* d = new Device(pedDevice->model, pedDevice->path, pedDevice->bios_geom.heads, pedDevice->bios_geom.sectors, pedDevice->bios_geom.cylinders, pedDevice->sector_size, solidDevice.icon());
PedDisk* pedDisk = ped_disk_new(pedDevice);
if (pedDisk)
{
const PartitionTable::LabelType type = PartitionTable::nameToLabelType(pedDisk->type->name);
d->setPartitionTable(new PartitionTable(type, firstUsableSector(*d), lastUsableSector(*d)));
d->partitionTable()->setMaxPrimaries(ped_disk_get_max_primary_partition_count(pedDisk));
scanDevicePartitions(pedDevice, *d, pedDisk);
}
ostack.addDevice(d);
Log(Log::warning) << i18nc("@info/plain", "Could not access device <filename>%1</filename>", device_node);
return NULL;
}
ostack.sortDevices();
}
Log(Log::information) << i18nc("@info/plain", "Device found: %1", pedDevice->model);
Device* d = new Device(pedDevice->model, pedDevice->path, pedDevice->bios_geom.heads, pedDevice->bios_geom.sectors, pedDevice->bios_geom.cylinders, pedDevice->sector_size);
PedDisk* pedDisk = ped_disk_new(pedDevice);
if (pedDisk)
{
const PartitionTable::LabelType type = PartitionTable::nameToLabelType(pedDisk->type->name);
d->setPartitionTable(new PartitionTable(type, firstUsableSector(*d), lastUsableSector(*d)));
d->partitionTable()->setMaxPrimaries(ped_disk_get_max_primary_partition_count(pedDisk));
scanDevicePartitions(pedDevice, *d, pedDisk);
}
return d;
}

View File

@ -44,9 +44,9 @@ class LibParted
LibParted();
public:
void scanDevices(OperationStack& ostack);
static quint64 firstUsableSector(const Device& d);
static quint64 lastUsableSector(const Device& d);
static Device* scanDevice(const QString& device_node);
};
#endif

View File

@ -26,8 +26,8 @@
class Device;
class Partition;
class LibParted;
class Operation;
class DeviceScanner;
/** @brief The list of Operations the user wants to have performed.
@ -40,7 +40,7 @@ class OperationStack
{
Q_DISABLE_COPY(OperationStack)
friend class LibParted;
friend class DeviceScanner;
public:
typedef QList<Device*> Devices;

View File

@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2008 by Volker Lanz <vl@fidra.de> *
* Copyright (C) 2008,2010 by Volker Lanz <vl@fidra.de> *
* *
* 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 *
@ -17,4 +17,4 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
#include "gui/progressdialogwidget.h"
#include "gui/applyprogressdetailswidget.h"

View File

@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2008 by Volker Lanz <vl@fidra.de> *
* Copyright (C) 2008,2010 by Volker Lanz <vl@fidra.de> *
* *
* 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 *
@ -17,21 +17,21 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
#if !defined(PROGRESSDETAILSWIDGET__H)
#if !defined(APPLYPROGRESSDETAILSWIDGET__H)
#define PROGRESSDETAILSWIDGET__H
#define APPLYPROGRESSDETAILSWIDGET__H
#include "ui_progressdetailswidgetbase.h"
#include "ui_applyprogressdetailswidgetbase.h"
/** @brief Details widget for the ProgressDialog.
@author vl@fidra.de
*/
class ProgressDetailsWidget : public QWidget, public Ui::ProgressDetailsWidgetBase
class ApplyProgressDetailsWidget : public QWidget, public Ui::ApplyProgressDetailsWidgetBase
{
Q_OBJECT
public:
ProgressDetailsWidget(QWidget* parent) : QWidget(parent) { setupUi(this); }
ApplyProgressDetailsWidget(QWidget* parent) : QWidget(parent) { setupUi(this); }
public:
KTextEdit& editReport() { Q_ASSERT(m_EditReport); return *m_EditReport; }

View File

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ApplyProgressDetailsWidgetBase</class>
<widget class="QWidget" name="ApplyProgressDetailsWidgetBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>736</width>
<height>600</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="3">
<widget class="KTextEdit" name="m_EditReport">
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="1" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>608</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="m_ButtonSave">
<property name="text">
<string>&amp;Save</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="m_ButtonBrowser">
<property name="text">
<string>&amp;Open in External Browser</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KTextEdit</class>
<extends>QTextEdit</extends>
<header>ktextedit.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -17,10 +17,10 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
#include "gui/progressdialog.h"
#include "gui/applyprogressdialog.h"
#include "gui/progressdialogwidget.h"
#include "gui/progressdetailswidget.h"
#include "gui/applyprogressdialogwidget.h"
#include "gui/applyprogressdetailswidget.h"
#include "core/operationrunner.h"
@ -45,7 +45,7 @@
#include <kaboutdata.h>
#include <ktextedit.h>
const QString ProgressDialog::m_TimeFormat = "hh:mm:ss";
const QString ApplyProgressDialog::m_TimeFormat = "hh:mm:ss";
static QWidget* mainWindow(QWidget* w)
{
@ -58,10 +58,10 @@ static QWidget* mainWindow(QWidget* w)
@param parent pointer to the parent widget
@param orunner the OperationRunner whose progress this dialog is showing
*/
ProgressDialog::ProgressDialog(QWidget* parent, OperationRunner& orunner) :
ApplyProgressDialog::ApplyProgressDialog(QWidget* parent, OperationRunner& orunner) :
KDialog(parent),
m_ProgressDialogWidget(new ProgressDialogWidget(this)),
m_ProgressDetailsWidget(new ProgressDetailsWidget(this)),
m_ProgressDialogWidget(new ApplyProgressDialogWidget(this)),
m_ProgressDetailsWidget(new ApplyProgressDetailsWidget(this)),
m_OperationRunner(orunner),
m_Report(NULL),
m_SavedParentTitle(mainWindow(this)->windowTitle()),
@ -85,14 +85,14 @@ ProgressDialog::ProgressDialog(QWidget* parent, OperationRunner& orunner) :
}
/** Destroys a ProgressDialog */
ProgressDialog::~ProgressDialog()
ApplyProgressDialog::~ApplyProgressDialog()
{
KConfigGroup kcg(KGlobal::config(), "progressDialog");
saveDialogSize(kcg);
delete m_Report;
}
void ProgressDialog::setupConnections()
void ApplyProgressDialog::setupConnections()
{
connect(&operationRunner(), SIGNAL(progressSub(int)), &dialogWidget().progressSub(), SLOT(setValue(int)));
connect(&operationRunner(), SIGNAL(finished()), SLOT(onAllOpsFinished()));
@ -106,7 +106,7 @@ void ProgressDialog::setupConnections()
}
/** Shows the dialog */
void ProgressDialog::show()
void ApplyProgressDialog::show()
{
foreach (QWidget* w, kapp->topLevelWidgets())
w->setEnabled(false);
@ -134,7 +134,7 @@ void ProgressDialog::show()
KDialog::show();
}
void ProgressDialog::resetReport()
void ApplyProgressDialog::resetReport()
{
delete m_Report;
m_Report = new Report(NULL);
@ -147,13 +147,13 @@ void ProgressDialog::resetReport()
connect(&report(), SIGNAL(outputChanged()), SLOT(updateReport()));
}
void ProgressDialog::closeEvent(QCloseEvent* e)
void ApplyProgressDialog::closeEvent(QCloseEvent* e)
{
e->ignore();
slotButtonClicked(operationRunner().isRunning() ? KDialog::Cancel : KDialog::Ok);
}
void ProgressDialog::slotButtonClicked(int button)
void ApplyProgressDialog::slotButtonClicked(int button)
{
if (button == KDialog::Details)
{
@ -200,22 +200,22 @@ void ProgressDialog::slotButtonClicked(int button)
KDialog::accept();
}
void ProgressDialog::onAllOpsFinished()
void ApplyProgressDialog::onAllOpsFinished()
{
allOpsDone(i18nc("@info:progress", "All operations successfully finished."));
}
void ProgressDialog::onAllOpsCancelled()
void ApplyProgressDialog::onAllOpsCancelled()
{
allOpsDone(i18nc("@info:progress", "Operations cancelled."));
}
void ProgressDialog::onAllOpsError()
void ApplyProgressDialog::onAllOpsError()
{
allOpsDone(i18nc("@info:progress", "There were errors while applying operations. Aborted."));
}
void ProgressDialog::allOpsDone(const QString& msg)
void ApplyProgressDialog::allOpsDone(const QString& msg)
{
dialogWidget().progressTotal().setValue(operationRunner().numJobs());
showButton(KDialog::Cancel, false);
@ -228,7 +228,7 @@ void ProgressDialog::allOpsDone(const QString& msg)
setStatus(msg);
}
void ProgressDialog::updateReport(bool force)
void ApplyProgressDialog::updateReport(bool force)
{
// Rendering the HTML in the KTextEdit is extremely expensive. So make sure not to do that
// unnecessarily and not too often:
@ -245,7 +245,7 @@ void ProgressDialog::updateReport(bool force)
}
}
void ProgressDialog::onOpStarted(int num, Operation* op)
void ApplyProgressDialog::onOpStarted(int num, Operation* op)
{
addTaskOutput(num, *op);
setStatus(op->description());
@ -257,7 +257,7 @@ void ProgressDialog::onOpStarted(int num, Operation* op)
connect(op, SIGNAL(jobFinished(Job*, Operation*)), SLOT(onJobFinished(Job*, Operation*)));
}
void ProgressDialog::onJobStarted(Job* job, Operation* op)
void ApplyProgressDialog::onJobStarted(Job* job, Operation* op)
{
for (qint32 i = 0; i < dialogWidget().treeTasks().topLevelItemCount(); i++)
{
@ -277,7 +277,7 @@ void ProgressDialog::onJobStarted(Job* job, Operation* op)
}
}
void ProgressDialog::onJobFinished(Job* job, Operation* op)
void ApplyProgressDialog::onJobFinished(Job* job, Operation* op)
{
if (currentJobItem())
currentJobItem()->setIcon(0, job->statusIcon());
@ -291,7 +291,7 @@ void ProgressDialog::onJobFinished(Job* job, Operation* op)
updateReport(true);
}
void ProgressDialog::onOpFinished(int num, Operation* op)
void ApplyProgressDialog::onOpFinished(int num, Operation* op)
{
if (currentOpItem())
{
@ -307,13 +307,13 @@ void ProgressDialog::onOpFinished(int num, Operation* op)
updateReport(true);
}
void ProgressDialog::setParentTitle(const QString& s)
void ApplyProgressDialog::setParentTitle(const QString& s)
{
const int percent = dialogWidget().progressTotal().value() * 100 / dialogWidget().progressTotal().maximum();
mainWindow(this)->setWindowTitle(QString::number(percent) + "% - " + s + " - " + savedParentTitle());
}
void ProgressDialog::setStatus(const QString& s)
void ApplyProgressDialog::setStatus(const QString& s)
{
setCaption(s);
dialogWidget().status().setText(s);
@ -321,12 +321,12 @@ void ProgressDialog::setStatus(const QString& s)
setParentTitle(s);
}
QString ProgressDialog::opDesc(int num, const Operation& op) const
QString ApplyProgressDialog::opDesc(int num, const Operation& op) const
{
return i18nc("@info:progress", "[%1/%2] - %3: %4", num, operationRunner().numOperations(), op.statusText(), op.description());
}
void ProgressDialog::addTaskOutput(int num, const Operation& op)
void ApplyProgressDialog::addTaskOutput(int num, const Operation& op)
{
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setIcon(0, op.statusIcon());
@ -344,7 +344,7 @@ void ProgressDialog::addTaskOutput(int num, const Operation& op)
setCurrentOpItem(item);
}
void ProgressDialog::onSecondElapsed()
void ApplyProgressDialog::onSecondElapsed()
{
if (currentJobItem())
{
@ -362,7 +362,7 @@ void ProgressDialog::onSecondElapsed()
dialogWidget().totalTime().setText(i18nc("@info:progress", "Total Time: %1", outputTime.toString(timeFormat())));
}
void ProgressDialog::keyPressEvent(QKeyEvent* e)
void ApplyProgressDialog::keyPressEvent(QKeyEvent* e)
{
e->accept();
@ -383,7 +383,7 @@ void ProgressDialog::keyPressEvent(QKeyEvent* e)
}
}
void ProgressDialog::saveReport()
void ApplyProgressDialog::saveReport()
{
QString fileName = KFileDialog::getSaveFileName(KUrl("kfiledialog://saveReport"));
@ -407,7 +407,7 @@ void ProgressDialog::saveReport()
}
}
void ProgressDialog::browserReport()
void ApplyProgressDialog::browserReport()
{
KTemporaryFile file;

View File

@ -17,9 +17,9 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
#if !defined(PROGRESSDIALOG__H)
#if !defined(APPLYPROGRESSDIALOG__H)
#define PROGRESSDIALOG__H
#define APPLYPROGRESSDIALOG__H
#include <kdialog.h>
@ -30,8 +30,8 @@
class OperationRunner;
class Operation;
class Job;
class ProgressDialogWidget;
class ProgressDetailsWidget;
class ApplyProgressDialogWidget;
class ApplyProgressDetailsWidget;
class Report;
@ -45,14 +45,14 @@ class QKeyEvent;
@author vl@fidra.de
*/
class ProgressDialog : public KDialog
class ApplyProgressDialog : public KDialog
{
Q_OBJECT
Q_DISABLE_COPY(ProgressDialog)
Q_DISABLE_COPY(ApplyProgressDialog)
public:
ProgressDialog(QWidget* parent, OperationRunner& orunner);
~ProgressDialog();
ApplyProgressDialog(QWidget* parent, OperationRunner& orunner);
~ApplyProgressDialog();
public:
void show();
@ -82,11 +82,15 @@ class ProgressDialog : public KDialog
const OperationRunner& operationRunner() const { return m_OperationRunner; }
ProgressDialogWidget& dialogWidget() { Q_ASSERT(m_ProgressDialogWidget); return *m_ProgressDialogWidget; }
const ProgressDialogWidget& dialogWidget() const { Q_ASSERT(m_ProgressDialogWidget); return *m_ProgressDialogWidget; }
ApplyProgressDialogWidget
& dialogWidget() { Q_ASSERT(m_ProgressDialogWidget); return *m_ProgressDialogWidget; }
const ApplyProgressDialogWidget
& dialogWidget() const { Q_ASSERT(m_ProgressDialogWidget); return *m_ProgressDialogWidget; }
ProgressDetailsWidget& detailsWidget() { Q_ASSERT(m_ProgressDetailsWidget); return *m_ProgressDetailsWidget; }
const ProgressDetailsWidget& detailsWidget() const { Q_ASSERT(m_ProgressDetailsWidget); return *m_ProgressDetailsWidget; }
ApplyProgressDetailsWidget
& detailsWidget() { Q_ASSERT(m_ProgressDetailsWidget); return *m_ProgressDetailsWidget; }
const ApplyProgressDetailsWidget
& detailsWidget() const { Q_ASSERT(m_ProgressDetailsWidget); return *m_ProgressDetailsWidget; }
void setStatus(const QString& s);
@ -119,8 +123,10 @@ class ProgressDialog : public KDialog
static const QString& timeFormat() { return m_TimeFormat; }
private:
ProgressDialogWidget* m_ProgressDialogWidget;
ProgressDetailsWidget* m_ProgressDetailsWidget;
ApplyProgressDialogWidget
* m_ProgressDialogWidget;
ApplyProgressDetailsWidget
* m_ProgressDetailsWidget;
const OperationRunner& m_OperationRunner;
Report* m_Report;
QString m_SavedParentTitle;

View File

@ -17,4 +17,4 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
#include "gui/progressdetailswidget.h"
#include "gui/applyprogressdialogwidget.h"

View File

@ -17,19 +17,19 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
#if !defined(PROGRESSDIALOGWIDGET__H)
#if !defined(APPLYPROGRESSDIALOGWIDGET__H)
#define PROGRESSDIALOGWIDGET__H
#define APPLYPROGRESSDIALOGWIDGET__H
#include "ui_progressdialogwidgetbase.h"
#include "ui_applyprogressdialogwidgetbase.h"
/** @brief Central widget for the ProgressDialog.
@author vl@fidra.de
*/
class ProgressDialogWidget : public QWidget, public Ui::ProgressDialogWidgetBase
class ApplyProgressDialogWidget : public QWidget, public Ui::ApplyProgressDialogWidgetBase
{
public:
ProgressDialogWidget(QWidget* parent) : QWidget(parent) { setupUi(this); }
ApplyProgressDialogWidget(QWidget* parent) : QWidget(parent) { setupUi(this); }
public:
QTreeWidget& treeTasks() { Q_ASSERT(m_TreeTasks); return *m_TreeTasks; }

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ProgressDialogWidgetBase</class>
<widget class="QWidget" name="ProgressDialogWidgetBase">
<class>ApplyProgressDialogWidgetBase</class>
<widget class="QWidget" name="ApplyProgressDialogWidgetBase">
<property name="geometry">
<rect>
<x>0</x>

View File

@ -19,7 +19,7 @@
#include "gui/mainwindow.h"
#include "gui/infopane.h"
#include "gui/progressdialog.h"
#include "gui/applyprogressdialog.h"
#include "core/device.h"
@ -82,7 +82,7 @@ void MainWindow::init()
void MainWindow::closeEvent(QCloseEvent* event)
{
if (pmWidget().progressDialog().isVisible())
if (pmWidget().applyProgressDialog().isVisible())
{
event->ignore();
return;
@ -109,10 +109,10 @@ void MainWindow::closeEvent(QCloseEvent* event)
void MainWindow::changeEvent(QEvent* event)
{
if ((event->type() == QEvent::ActivationChange || event->type() == QEvent::WindowStateChange) && event->spontaneous() && isActiveWindow() && pmWidget().progressDialog().isVisible())
if ((event->type() == QEvent::ActivationChange || event->type() == QEvent::WindowStateChange) && event->spontaneous() && isActiveWindow() && pmWidget().applyProgressDialog().isVisible())
{
pmWidget().progressDialog().activateWindow();
pmWidget().progressDialog().raise();
pmWidget().applyProgressDialog().activateWindow();
pmWidget().applyProgressDialog().raise();
}
KXmlGuiWindow::changeEvent(event);
@ -134,8 +134,8 @@ void MainWindow::setupConnections()
{
connect(&pmWidget(), SIGNAL(devicesChanged()), SLOT(updateDevices()));
connect(&pmWidget(), SIGNAL(operationsChanged()), &listOperations(), SLOT(updateOperations()));
connect(&pmWidget(), SIGNAL(statusChanged()), SLOT(updateStatusBar()));
connect(&pmWidget(), SIGNAL(selectionChanged(const Partition*)), SLOT(updateSelection(const Partition*)));
connect(&pmWidget(), SIGNAL(operationsChanged()), SLOT(updateStatusBar()));
connect(&pmWidget(), SIGNAL(selectedPartitionChanged(const Partition*)), SLOT(updateSelection(const Partition*)));
connect(&dockInformation(), SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), SLOT(onDockLocationChanged(Qt::DockWidgetArea)));
}

View File

@ -24,16 +24,18 @@
#include "gui/infopane.h"
#include "gui/newdialog.h"
#include "gui/filesystemsupportdialog.h"
#include "gui/progressdialog.h"
#include "gui/applyprogressdialog.h"
#include "gui/insertdialog.h"
#include "gui/editmountpointdialog.h"
#include "gui/createpartitiontabledialog.h"
#include "gui/scanprogressdialog.h"
#include "core/partition.h"
#include "core/device.h"
#include "core/operationstack.h"
#include "core/partitiontable.h"
#include "core/operationrunner.h"
#include "core/devicescanner.h"
#include "fs/filesystemfactory.h"
@ -101,10 +103,11 @@ class PartitionTreeWidgetItem : public QTreeWidgetItem
PartitionManagerWidget::PartitionManagerWidget(QWidget* parent, KActionCollection* coll) :
QWidget(parent),
Ui::PartitionManagerWidgetBase(),
m_LibParted(),
m_OperationStack(),
m_OperationRunner(operationStack()),
m_ProgressDialog(new ProgressDialog(this, operationRunner())),
m_DeviceScanner(operationStack()),
m_ApplyProgressDialog(new ApplyProgressDialog(this, operationRunner())),
m_ScanProgressDialog(new ScanProgressDialog(this)),
m_ActionCollection(coll),
m_SelectedDevice(NULL),
m_ClipboardPartition(NULL)
@ -300,36 +303,58 @@ void PartitionManagerWidget::setupConnections()
Q_ASSERT(actionCollection());
connect(&partTableWidget(), SIGNAL(itemActivated(const PartWidget*)), actionCollection()->action("propertiesPartition"), SLOT(trigger()));
connect(&progressDialog(), SIGNAL(finished(int)), SLOT(onFinished()));
connect(&applyProgressDialog(), SIGNAL(finished(int)), SLOT(scanDevices()));
connect(&deviceScanner(), SIGNAL(finished()), SLOT(onScanDevicesFinished()));
connect(&deviceScanner(), SIGNAL(progressChanged(const QString&, int)), SLOT(onScanDevicesProgressChanged(const QString&, int)));
connect(&deviceScanner(), SIGNAL(operationsChanged()), SIGNAL(operationsChanged()));
connect(&deviceScanner(), SIGNAL(devicesChanged()), SIGNAL(devicesChanged()));
}
void PartitionManagerWidget::scanDevices()
{
Log() << i18nc("@info/plain", "Rescanning devices...");
Log() << i18nc("@info/plain", "Scanning devices...");
clear();
KApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
setSelectedDevice(NULL);
setClipboardPartition(NULL);
clear();
foreach (QWidget* w, kapp->topLevelWidgets())
w->setEnabled(false);
libParted().scanDevices(operationStack());
scanProgressDialog().setEnabled(true);
scanProgressDialog().show();
deviceScanner().start();
}
void PartitionManagerWidget::onScanDevicesProgressChanged(const QString& device_node, int percent)
{
scanProgressDialog().setProgress(percent);
scanProgressDialog().setDeviceName(device_node);
}
void PartitionManagerWidget::onScanDevicesFinished()
{
if (!operationStack().previewDevices().isEmpty())
{
setSelectedDevice(operationStack().previewDevices()[0]);
// FIXME: Normally this should be emitted in setSelectedDevice(), but if we do that
// now we get all kinds of terrible races and crashes during rescan (because DeviceScanner
// clears the devices in the operationstack while ListDevices is just iterating them).
// Once that is fixed, remove the emit here.
emit devicesChanged();
}
updatePartitions();
Log() << i18nc("@info/plain", "Rescan finished.");
Log() << i18nc("@info/plain", "Scan finished.");
KApplication::restoreOverrideCursor();
emit selectionChanged(NULL);
emit devicesChanged();
emit operationsChanged();
emit statusChanged();
scanProgressDialog().hide();
foreach (QWidget* w, kapp->topLevelWidgets())
w->setEnabled(true);
}
void PartitionManagerWidget::enableActions()
@ -367,13 +392,17 @@ void PartitionManagerWidget::enableActions()
void PartitionManagerWidget::clear()
{
setSelectedDevice(NULL);
setClipboardPartition(NULL);
treePartitions().clear();
partTableWidget().clear();
deviceScanner().clear();
}
void PartitionManagerWidget::clearSelection()
void PartitionManagerWidget::clearSelectedPartition()
{
treePartitions().setCurrentItem(NULL);
emit selectedPartitionChanged(NULL);
enableActions();
updatePartitions();
}
@ -381,7 +410,9 @@ void PartitionManagerWidget::clearSelection()
void PartitionManagerWidget::setSelectedDevice(Device* d)
{
m_SelectedDevice = d;
clearSelection();
// FIXME: We should emit devicesChanged() here, but if we do that we get terrible
// races. See onScanDevicesFinished()
clearSelectedPartition();
}
static QTreeWidgetItem* createTreeWidgetItem(const Partition& p)
@ -471,7 +502,7 @@ void PartitionManagerWidget::on_m_PartTableWidget_itemSelectionChanged(PartWidge
if (item == NULL)
{
treePartitions().setCurrentItem(NULL);
emit selectionChanged(NULL);
emit selectedPartitionChanged(NULL);
return;
}
@ -492,7 +523,7 @@ void PartitionManagerWidget::on_m_PartTableWidget_itemSelectionChanged(PartWidge
}
}
emit selectionChanged(p);
emit selectedPartitionChanged(p);
}
void PartitionManagerWidget::on_m_PartTableWidget_customContextMenuRequested(const QPoint& pos)
@ -580,7 +611,6 @@ void PartitionManagerWidget::onPropertiesPartition()
updatePartitions();
emit operationsChanged();
emit statusChanged();
}
delete dlg;
@ -684,7 +714,6 @@ void PartitionManagerWidget::onNewPartition()
PartitionTable::snap(*selectedDevice(), *newPartition);
operationStack().push(new NewOperation(*selectedDevice(), newPartition));
updatePartitions();
emit statusChanged();
emit operationsChanged();
}
else
@ -743,7 +772,6 @@ void PartitionManagerWidget::onDeletePartition(bool shred)
operationStack().push(new DeleteOperation(*selectedDevice(), selectedPartition(), shred));
updatePartitions();
emit statusChanged();
emit operationsChanged();
}
@ -788,7 +816,6 @@ void PartitionManagerWidget::onResizePartition()
operationStack().push(new ResizeOperation(*selectedDevice(), *selectedPartition(), resizedPartition.firstSector(), resizedPartition.lastSector()));
updatePartitions();
emit statusChanged();
emit operationsChanged();
}
}
@ -848,7 +875,6 @@ void PartitionManagerWidget::onPastePartition()
{
operationStack().push(new CopyOperation(*selectedDevice(), copiedPartition, *dSource, clipboardPartition()));
updatePartitions();
emit statusChanged();
emit operationsChanged();
}
else
@ -920,7 +946,6 @@ void PartitionManagerWidget::onCreateNewPartitionTable()
operationStack().push(new CreatePartitionTableOperation(*selectedDevice(), dlg->type()));
updatePartitions();
emit statusChanged();
emit operationsChanged();
emit devicesChanged();
enableActions();
@ -950,7 +975,6 @@ void PartitionManagerWidget::onUndoOperation()
updatePartitions();
emit operationsChanged();
emit statusChanged();
emit devicesChanged();
enableActions();
}
@ -968,7 +992,6 @@ void PartitionManagerWidget::onClearAllOperations()
updatePartitions();
emit operationsChanged();
emit statusChanged();
enableActions();
}
}
@ -990,9 +1013,9 @@ void PartitionManagerWidget::onApplyAllOperations()
{
Log() << i18nc("@info/plain", "Applying operations...");
progressDialog().show();
applyProgressDialog().show();
operationRunner().setReport(&progressDialog().report());
operationRunner().setReport(&applyProgressDialog().report());
// Undo all operations so the runner has a defined starting point
for (int i = operationStack().operations().size() - 1; i >= 0; i--)
@ -1021,7 +1044,6 @@ void PartitionManagerWidget::onCheckPartition()
operationStack().push(new CheckOperation(*selectedDevice(), *selectedPartition()));
updatePartitions();
emit statusChanged();
emit operationsChanged();
}
@ -1046,7 +1068,6 @@ void PartitionManagerWidget::onBackupPartition()
{
operationStack().push(new BackupOperation(*selectedDevice(), *selectedPartition(), fileName));
updatePartitions();
emit statusChanged();
emit operationsChanged();
}
}
@ -1084,7 +1105,6 @@ void PartitionManagerWidget::onRestorePartition()
operationStack().push(new RestoreOperation(*selectedDevice(), restorePartition, fileName));
updatePartitions();
emit statusChanged();
emit operationsChanged();
}
else
@ -1097,8 +1117,3 @@ void PartitionManagerWidget::onFileSystemSupport()
FileSystemSupportDialog dlg(this);
dlg.exec();
}
void PartitionManagerWidget::onFinished()
{
scanDevices();
}

View File

@ -23,9 +23,9 @@
#include "util/libpartitionmanagerexport.h"
#include "core/libparted.h"
#include "core/operationrunner.h"
#include "core/operationstack.h"
#include "core/devicescanner.h"
#include "ui_partitionmanagerwidgetbase.h"
@ -36,7 +36,8 @@ class QLabel;
class PartWidget;
class KActionCollection;
class Device;
class ProgressDialog;
class ApplyProgressDialog;
class ScanProgressDialog;
/** @brief The central widget for the application.
@ -54,8 +55,7 @@ class LIBPARTITIONMANAGERPRIVATE_EXPORT PartitionManagerWidget : public QWidget,
signals:
void devicesChanged();
void operationsChanged();
void statusChanged();
void selectionChanged(const Partition*);
void selectedPartitionChanged(const Partition*);
public slots:
void setSelectedDevice(Device* d);
@ -65,7 +65,7 @@ class LIBPARTITIONMANAGERPRIVATE_EXPORT PartitionManagerWidget : public QWidget,
KActionCollection* actionCollection() const { return m_ActionCollection; }
void clear();
void clearSelection();
void clearSelectedPartition();
void setPartitionTable(const PartitionTable* ptable);
void setSelection(const Partition* p);
void enableActions();
@ -85,8 +85,11 @@ class LIBPARTITIONMANAGERPRIVATE_EXPORT PartitionManagerWidget : public QWidget,
const Partition* clipboardPartition() const { return m_ClipboardPartition; }
void setClipboardPartition(Partition* p) { m_ClipboardPartition = p; }
ProgressDialog& progressDialog() { Q_ASSERT(m_ProgressDialog); return *m_ProgressDialog; }
const ProgressDialog& progressDialog() const { Q_ASSERT(m_ProgressDialog); return *m_ProgressDialog; }
ApplyProgressDialog& applyProgressDialog() { Q_ASSERT(m_ApplyProgressDialog); return *m_ApplyProgressDialog; }
const ApplyProgressDialog& applyProgressDialog() const { Q_ASSERT(m_ApplyProgressDialog); return *m_ApplyProgressDialog; }
ScanProgressDialog& scanProgressDialog() { Q_ASSERT(m_ScanProgressDialog); return *m_ScanProgressDialog; }
const ScanProgressDialog& scanProgressDialog() const { Q_ASSERT(m_ScanProgressDialog); return *m_ScanProgressDialog; }
quint32 numPendingOperations();
@ -104,15 +107,15 @@ class LIBPARTITIONMANAGERPRIVATE_EXPORT PartitionManagerWidget : public QWidget,
QTreeWidget& treePartitions() { Q_ASSERT(m_TreePartitions); return *m_TreePartitions; }
const QTreeWidget& treePartitions() const { Q_ASSERT(m_TreePartitions); return *m_TreePartitions; }
LibParted& libParted() { return m_LibParted; }
const LibParted& libParted() const { return m_LibParted; }
OperationRunner& operationRunner() { return m_OperationRunner; }
const OperationRunner& operationRunner() const { return m_OperationRunner; }
OperationStack& operationStack() { return m_OperationStack; }
const OperationStack& operationStack() const { return m_OperationStack; }
DeviceScanner& deviceScanner() { return m_DeviceScanner; }
const DeviceScanner& deviceScanner() const { return m_DeviceScanner; }
protected slots:
void on_m_TreePartitions_currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous);
void on_m_PartTableWidget_customContextMenuRequested(const QPoint& pos);
@ -121,6 +124,8 @@ class LIBPARTITIONMANAGERPRIVATE_EXPORT PartitionManagerWidget : public QWidget,
void on_m_PartTableWidget_itemSelectionChanged(PartWidget* item);
void scanDevices();
void onScanDevicesFinished();
void onScanDevicesProgressChanged(const QString& device_node, int percent);
void onPropertiesPartition();
void onMountPartition();
@ -140,13 +145,13 @@ class LIBPARTITIONMANAGERPRIVATE_EXPORT PartitionManagerWidget : public QWidget,
void onFileSystemSupport();
void onBackupPartition();
void onRestorePartition();
void onFinished();
private:
LibParted m_LibParted;
OperationStack m_OperationStack;
OperationRunner m_OperationRunner;
ProgressDialog* m_ProgressDialog;
DeviceScanner m_DeviceScanner;
ApplyProgressDialog* m_ApplyProgressDialog;
ScanProgressDialog* m_ScanProgressDialog;
KActionCollection* m_ActionCollection;
Device* m_SelectedDevice;
Partition* m_ClipboardPartition;

View File

@ -1,51 +0,0 @@
<ui version="4.0" >
<class>ProgressDetailsWidgetBase</class>
<widget class="QWidget" name="ProgressDetailsWidgetBase" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>736</width>
<height>600</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout" >
<item row="0" column="0" colspan="3" >
<widget class="KTextEdit" name="m_EditReport" >
<property name="textInteractionFlags" >
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="1" column="0" >
<spacer name="horizontalSpacer" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>608</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="2" >
<widget class="QPushButton" name="m_ButtonSave" >
<property name="text" >
<string>&amp;Save</string>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QPushButton" name="m_ButtonBrowser" >
<property name="text" >
<string>&amp;Open in External Browser</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,42 @@
/***************************************************************************
* Copyright (C) 2010 by Volker Lanz <vl@fidra.de> *
* *
* 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include "gui/scanprogressdialog.h"
#include <klocale.h>
ScanProgressDialog::ScanProgressDialog(QWidget* parent) :
KProgressDialog(parent)
{
setCaption(i18nc("@title:window", "Scanning devices..."));
setMinimumWidth(280);
setMinimumDuration(150);
}
void ScanProgressDialog::setDeviceName(const QString& d)
{
setLabelText(i18nc("@label", "Scanning device: <filename>%1</filename>", d));
}
void ScanProgressDialog::showEvent(QShowEvent* e)
{
setAllowCancel(false);
KProgressDialog::showEvent(e);
}

View File

@ -0,0 +1,44 @@
/***************************************************************************
* Copyright (C) 2010 by Volker Lanz <vl@fidra.de> *
* *
* 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#if !defined(SCANPROGRESSDIALOG__H)
#define SCANPROGRESSDIALOG__H
#include <kprogressdialog.h>
class QShowEvent;
class ScanProgressDialog : public KProgressDialog
{
Q_OBJECT
public:
ScanProgressDialog(QWidget* parent);
protected:
virtual void showEvent(QShowEvent* e);
public:
void setProgress(quint32 p) { progressBar()->setValue(p); }
void setDeviceName(const QString& d);
};
#endif

View File

@ -107,7 +107,7 @@ void PartitionManagerKCM::setupConnections()
connect(&pmWidget(), SIGNAL(devicesChanged()), &listDevices(), SLOT(updateDevices()));
connect(&pmWidget(), SIGNAL(operationsChanged()), &listOperations(), SLOT(updateOperations()));
connect(&listDevices(), SIGNAL(selectionChanged(Device*)), &pmWidget(), SLOT(setSelectedDevice(Device*)));
connect(&pmWidget(), SIGNAL(statusChanged()), SLOT(onStatusChanged()));
connect(&pmWidget(), SIGNAL(operationsChanged()), SLOT(onStatusChanged()));
}
void PartitionManagerKCM::onStatusChanged()