diff --git a/src/core/device.cpp b/src/core/device.cpp index fce2f05..8368633 100644 --- a/src/core/device.cpp +++ b/src/core/device.cpp @@ -1,157 +1,157 @@ /************************************************************************* * Copyright (C) 2008 by Volker Lanz * * Copyright (C) 2016-2018 by Andrius Štikonas * * * * 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 3 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, see .* *************************************************************************/ #include "core/device.h" #include "core/device_p.h" #include "core/partitiontable.h" #include "core/smartstatus.h" #include "util/capacity.h" #include /** Constructs a Device with an empty PartitionTable. @param name the Device's name, usually some string defined by the manufacturer @param deviceNode the Device's node, for example "/dev/sda" */ Device::Device(std::shared_ptr d_ptr, const QString& name, const QString& deviceNode, const qint64 logicalSectorSize, const qint64 totalLogicalSectors, const QString& iconName, Device::Type type) : QObject() , d(d_ptr) { d->m_Name = name.length() > 0 ? name : i18n("Unknown Device"); d->m_DeviceNode = deviceNode; d->m_LogicalSectorSize = logicalSectorSize; d->m_TotalLogical = totalLogicalSectors; d->m_PartitionTable = nullptr; d->m_IconName = iconName.isEmpty() ? QStringLiteral("drive-harddisk") : iconName; d->m_SmartStatus = type == Device::Type::Disk_Device ? std::make_shared(deviceNode) : nullptr; d->m_Type = type; } /** Copy constructor for Device. * @param other the other Device. */ Device::Device(const Device& other) : QObject() + , d(std::make_shared()) { - d = std::make_shared(); d->m_Name = other.d->m_Name; d->m_DeviceNode = other.d->m_DeviceNode; d->m_LogicalSectorSize = other.d->m_LogicalSectorSize; d->m_TotalLogical = other.d->m_TotalLogical; d->m_PartitionTable = nullptr; d->m_IconName = other.d->m_IconName; d->m_SmartStatus = nullptr; d->m_Type = other.d->m_Type; d->m_SmartStatus = other.d->m_SmartStatus; if (other.d->m_PartitionTable) d->m_PartitionTable = new PartitionTable(*other.d->m_PartitionTable); } /** Destructs a Device. */ Device::~Device() { delete d->m_PartitionTable; } bool Device::operator==(const Device& other) const { return d->m_DeviceNode == other.d->m_DeviceNode; } bool Device::operator!=(const Device& other) const { return !(other == *this); } QString Device::prettyName() const { return xi18nc("@item:inlistbox Device name – Capacity (device node)", "%1 – %2 (%3)", name(), Capacity::formatByteSize(capacity()), deviceNode()); } QString& Device::name() { return d->m_Name; } const QString& Device::name() const { return d->m_Name; } const QString& Device::deviceNode() const { return d->m_DeviceNode; } qint64 Device::logicalSize() const { return d->m_LogicalSectorSize; } qint64 Device::totalLogical() const { return d->m_TotalLogical; } PartitionTable* Device::partitionTable() { return d->m_PartitionTable; } const PartitionTable* Device::partitionTable() const { return d->m_PartitionTable; } void Device::setPartitionTable(PartitionTable* ptable) { d->m_PartitionTable = ptable; } const QString& Device::iconName() const { return d->m_IconName; } void Device::setIconName(const QString& name) { d->m_IconName = name; } SmartStatus& Device::smartStatus() { return *(d->m_SmartStatus); } const SmartStatus& Device::smartStatus() const { return *(d->m_SmartStatus); } Device::Type Device::type() const { return d->m_Type; } diff --git a/src/ops/operation.cpp b/src/ops/operation.cpp index 8115913..c837f29 100644 --- a/src/ops/operation.cpp +++ b/src/ops/operation.cpp @@ -1,174 +1,204 @@ /************************************************************************* * Copyright (C) 2008 by Volker Lanz * * Copyright (C) 2016 by Andrius Štikonas * * * * 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 3 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, see .* *************************************************************************/ -#include "ops/operation.h" +#include "ops/operation_p.h" #include "core/partition.h" #include "core/device.h" #include "jobs/job.h" #include "util/report.h" #include #include #include #include Operation::Operation() : - m_Status(StatusNone), - m_Jobs(), - m_ProgressBase(0) + d(std::make_unique()) { + d->m_Status = StatusNone; + d->m_ProgressBase = 0; } Operation::~Operation() { qDeleteAll(jobs()); jobs().clear(); } void Operation::insertPreviewPartition(Device& device, Partition& p) { Q_ASSERT(device.partitionTable()); device.partitionTable()->removeUnallocated(); p.parent()->insert(&p); device.partitionTable()->updateUnallocated(device); } void Operation::removePreviewPartition(Device& device, Partition& p) { Q_ASSERT(device.partitionTable()); if (p.parent()->remove(&p)) device.partitionTable()->updateUnallocated(device); else qWarning() << "failed to remove partition " << p.deviceNode() << " at " << &p << " from preview."; } /** @return text describing the Operation's current status */ QString Operation::statusText() const { static const QString s[] = { xi18nc("@info:progress operation", "None"), xi18nc("@info:progress operation", "Pending"), xi18nc("@info:progress operation", "Running"), xi18nc("@info:progress operation", "Success"), xi18nc("@info:progress operation", "Warning"), xi18nc("@info:progress operation", "Error") }; Q_ASSERT(status() >= 0 && static_cast(status()) < sizeof(s) / sizeof(s[0])); if (status() < 0 || static_cast(status()) >= sizeof(s) / sizeof(s[0])) { qWarning() << "invalid status " << status(); return QString(); } return s[status()]; } /** @return icon for the current Operation's status */ QString Operation::statusIcon() const { static const QString icons[] = { QString(), QStringLiteral("dialog-information"), QStringLiteral("dialog-information"), QStringLiteral("dialog-ok"), QStringLiteral("dialog-warning"), QStringLiteral("dialog-error") }; Q_ASSERT(status() >= 0 && static_cast(status()) < sizeof(icons) / sizeof(icons[0])); if (status() < 0 || static_cast(status()) >= sizeof(icons) / sizeof(icons[0])) { qWarning() << "invalid status " << status(); return QString(); } if (status() == StatusNone) return QString(); return icons[status()]; } void Operation::addJob(Job* job) { if (job) { jobs().append(job); connect(job, &Job::started, this, &Operation::onJobStarted); connect(job, &Job::progress, this, &Operation::progress); connect(job, &Job::finished, this, &Operation::onJobFinished); } } void Operation::onJobStarted() { Job* job = qobject_cast(sender()); if (job) emit jobStarted(job, this); } void Operation::onJobFinished() { Job* job = qobject_cast(sender()); if (job) { setProgressBase(progressBase() + job->numSteps()); emit jobFinished(job, this); } } /** @return total number of steps to run this Operation */ qint32 Operation::totalProgress() const { qint32 result = 0; for (const auto &job : jobs()) result += job->numSteps(); return result; } /** Execute the operation @param parent the parent Report to create a new child for @return true on success */ bool Operation::execute(Report& parent) { bool rval = false; Report* report = parent.newChild(description()); const auto Jobs = jobs(); for (const auto &job : Jobs) if (!(rval = job->run(*report))) break; setStatus(rval ? StatusFinishedSuccess : StatusError); report->setStatus(xi18nc("@info:status (success, error, warning...) of operation", "%1: %2", description(), statusText())); return rval; } + +Operation::OperationStatus Operation::status() const +{ + return d->m_Status; +} + +void Operation::setStatus(OperationStatus s) +{ + d->m_Status = s; +} + +QList& Operation::jobs() +{ + return d->m_Jobs; +} + +const QList& Operation::jobs() const +{ + return d->m_Jobs; +} + +void Operation::setProgressBase(qint32 i) +{ + d->m_ProgressBase = i; +} + +qint32 Operation::progressBase() const +{ + return d->m_ProgressBase; +} diff --git a/src/ops/operation.h b/src/ops/operation.h index d4dd29f..e551043 100644 --- a/src/ops/operation.h +++ b/src/ops/operation.h @@ -1,152 +1,144 @@ /************************************************************************* * Copyright (C) 2008 by Volker Lanz * + * Copyright (C) 2018 by Andrius Štikonas * * * * 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 3 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, see .* *************************************************************************/ -#if !defined(KPMCORE_OPERATION_H) - +#ifndef KPMCORE_OPERATION_H #define KPMCORE_OPERATION_H #include "util/libpartitionmanagerexport.h" #include #include #include +#include + class Partition; class Device; -class OperationStack; class Job; +class OperationPrivate; +class OperationStack; class OperationRunner; class Report; class QString; class QIcon; /** Base class of all Operations. An Operation serves two purposes: It is responsible for modifying the device preview to show the user a state as if the Operation had already been applied and it is made up of Jobs to actually perform what the Operation is supposed to do. Most Operations just run a list of Jobs and for that reason do not even overwrite Operation::execute(). The more complex Operations, however, need to perform some extra tasks in between running Jobs (most notably RestoreOperation and CopyOperation). These do overwrite Operation::execute(). Operations own the objects they deal with in most cases, usually Partitions. But as soon as an Operation has been successfully executed, it no longer owns anything, because the OperationStack then takes over ownership. Some rules for creating new operations that inherit the Operation class:
  1. Don't modify anything in the ctor. The ctor runs before merging operations. If you modify anything there, undo and merging will break. Just remember what you're supposed to do in the ctor and perform modifications in preview().
  2. Do not access the preview partitions and devices in description(). If you do, the operation descriptions will be wrong.
  3. Don't create or delete objects in preview() or undo() since these will be called more than once. Create and delete objects in the ctor and dtor.
@author Volker Lanz */ class LIBKPMCORE_EXPORT Operation : public QObject { Q_OBJECT Q_DISABLE_COPY(Operation) friend class OperationStack; friend class OperationRunner; public: /** Status of this Operation */ enum OperationStatus { StatusNone = 0, /**< None yet, can be merged */ StatusPending, /**< Pending, can be undone */ StatusRunning, /**< Currently running */ StatusFinishedSuccess, /**< Successfully finished */ StatusFinishedWarning, /**< Finished with warnings */ StatusError /**< Finished with errors */ }; protected: Operation(); virtual ~Operation(); Q_SIGNALS: void progress(int); void jobStarted(Job*, Operation*); void jobFinished(Job*, Operation*); public: virtual QString iconName() const = 0; /**< @return name of the icon for the Operation */ virtual QString description() const = 0; /**< @return the Operation's description */ virtual void preview() = 0; /**< Apply the Operation to the current preview */ virtual void undo() = 0; /**< Undo applying the Operation to the current preview */ virtual bool execute(Report& parent); virtual bool targets(const Device&) const = 0; virtual bool targets(const Partition&) const = 0; - virtual OperationStatus status() const { - return m_Status; /**< @return the current status */ - } + /**< @return the current status */ + virtual OperationStatus status() const; + virtual QString statusText() const; virtual QString statusIcon() const; - virtual void setStatus(OperationStatus s) { - m_Status = s; /**< @param s the new status */ - } + /**< @param s the new status */ + virtual void setStatus(OperationStatus s); - LIBKPMCORE_EXPORT qint32 totalProgress() const; + qint32 totalProgress() const; protected: void onJobStarted(); void onJobFinished(); void insertPreviewPartition(Device& targetDevice, Partition& newPartition); void removePreviewPartition(Device& device, Partition& p); void addJob(Job* job); - QList& jobs() { - return m_Jobs; - } - const QList& jobs() const { - return m_Jobs; - } + QList& jobs(); + const QList& jobs() const; - void setProgressBase(qint32 i) { - m_ProgressBase = i; - } - qint32 progressBase() const { - return m_ProgressBase; - } + void setProgressBase(qint32 i); + qint32 progressBase() const; private: - OperationStatus m_Status; - QList m_Jobs; - qint32 m_ProgressBase; + std::unique_ptr d; }; #endif