Add a ctor to CreatePartitionTableOperation that takes a PartitionTable

pointer, not a PartitionTable::Type. This is required for the import.

Add a basic import partition table feature to the GUI and make it work.

Add calls to PartitionManagerWidget::updatePartitions(),
MainWindow::enableActions() and the selectedPartitionChanged handler to the
operationsChanged handler to make sure the info pane and actions are always
updated when the operation stack changes (e.g. on undo). TODO: remove all
updatePartition() and similar calls from methods in PartitionManagerWidget.

Make the device properties action disabled per default and enable it only if a
device is selected. It's actually possible for no device to be selected if the
backend doesn't find any devices at all.

Fix status tips and markup.

svn path=/trunk/extragear/sysadmin/partitionmanager/; revision=1098154
This commit is contained in:
Volker Lanz 2010-03-03 00:15:26 +00:00
parent 845f44ccef
commit 7f33130265
6 changed files with 210 additions and 9 deletions

15
TODO
View File

@ -19,5 +19,20 @@ Random plans and ideas for 1.1 and beyond:
* save msdos mbr?
* don't call updatePartitions() or anything after pushing an operation to the
stack: MainWindow::on_m_OperationStack_operationsChanged() will be called and
will deal with all that. warning: this might cause problems, it calls
PartitionManagerWidget::updatePartitions() which currently clears the
selection -- maybe it shouldn't...
* let the user specify extern command locations and options in the settings
* move device scanning to backend plugin (call it from the device scanner
thread though)
Bugs:
* don't show available and used values for extended partitions
* solid and its object-created-with-parent-in-wrong-thread problem

View File

@ -40,6 +40,7 @@
#include "ops/checkoperation.h"
#include "fs/filesystem.h"
#include "fs/filesystemfactory.h"
#include <kstandardaction.h>
#include <kactioncollection.h>
@ -225,10 +226,18 @@ void MainWindow::setupActions()
exportPartitionTable->setEnabled(false);
exportPartitionTable->setText(i18nc("@action:inmenu", "Export Partition Table"));
exportPartitionTable->setToolTip(i18nc("@info:tooltip", "Export a partition table"));
exportPartitionTable->setStatusTip(i18nc("@info:status", "Exports the device's partition table in sfdisk-compatible format to a text file."));
exportPartitionTable->setStatusTip(i18nc("@info:status", "Export the device's partition table to a text file."));
exportPartitionTable->setIcon(BarIcon("document-export"));
KAction* importPartitionTable = actionCollection()->addAction("importPartitionTable", this, SLOT(onImportPartitionTable()));
importPartitionTable->setEnabled(false);
importPartitionTable->setText(i18nc("@action:inmenu", "Import Partition Table"));
importPartitionTable->setToolTip(i18nc("@info:tooltip", "Import a partition table"));
importPartitionTable->setStatusTip(i18nc("@info:status", "Import a partition table from a text file."));
importPartitionTable->setIcon(BarIcon("document-import"));
KAction* propertiesDevice = actionCollection()->addAction("propertiesDevice", this, SLOT(onPropertiesDevice()));
propertiesDevice->setEnabled(false);
propertiesDevice->setText(i18nc("@action:inmenu", "Properties"));
propertiesDevice->setToolTip(i18nc("@info:tooltip", "Show device properties dialog"));
propertiesDevice->setStatusTip(i18nc("@info:status", "View and modify device properties"));
@ -371,6 +380,8 @@ void MainWindow::enableActions()
{
actionCollection()->action("createNewPartitionTable")->setEnabled(CreatePartitionTableOperation::canCreate(pmWidget().selectedDevice()));
actionCollection()->action("exportPartitionTable")->setEnabled(pmWidget().selectedDevice() && pmWidget().selectedDevice()->partitionTable() && numPendingOperations() == 0);
actionCollection()->action("importPartitionTable")->setEnabled(CreatePartitionTableOperation::canCreate(pmWidget().selectedDevice()));
actionCollection()->action("propertiesDevice")->setEnabled(pmWidget().selectedDevice() != NULL);
actionCollection()->action("undoOperation")->setEnabled(numPendingOperations() > 0);
actionCollection()->action("clearAllOperations")->setEnabled(numPendingOperations() > 0);
@ -411,6 +422,11 @@ void MainWindow::on_m_ApplyProgressDialog_finished()
void MainWindow::on_m_OperationStack_operationsChanged()
{
listOperations().updateOperations(operationStack().operations());
pmWidget().updatePartitions();
enableActions();
// this will make sure that the info pane gets updated
on_m_PartitionManagerWidget_selectedPartitionChanged(pmWidget().selectedPartition());
if (!isKPart())
statusText().setText(i18ncp("@info:status", "One pending operation", "%1 pending operations", numPendingOperations()));
@ -508,7 +524,7 @@ void MainWindow::onShowMenuBar()
else
{
const QString accel = menuBarAction->shortcut().toString();
KMessageBox::information(this, i18nc("@info", "This will hide the menu bar completely. You can show it again by typing %1.", accel), i18nc("@window:title", "Hide Menu Bar"), "hideMenuBarWarning");
KMessageBox::information(this, i18nc("@info", "This will hide the menu bar completely. You can show it again by typing %1.", accel), i18nc("@title:window", "Hide Menu Bar"), "hideMenuBarWarning");
menuBar()->hide();
}
@ -655,15 +671,166 @@ void MainWindow::onCreateNewPartitionTable()
QPointer<CreatePartitionTableDialog> dlg = new CreatePartitionTableDialog(this, *pmWidget().selectedDevice());
if (dlg->exec() == KDialog::Accepted)
{
operationStack().push(new CreatePartitionTableOperation(*pmWidget().selectedDevice(), dlg->type()));
pmWidget().updatePartitions();
enableActions();
infoPane().showDevice(dockWidgetArea(&dockInformation()), *pmWidget().selectedDevice());
delete dlg;
}
void MainWindow::onImportPartitionTable()
{
Q_ASSERT(pmWidget().selectedDevice());
Device& device = *pmWidget().selectedDevice();
QString fileName = KFileDialog::getOpenFileName(KUrl("kfiledialog://importPartitionTable"));
if (fileName.isEmpty())
return;
QFile file(fileName);
if (!file.open(QFile::ReadOnly))
{
KMessageBox::error(this, i18nc("@info", "Could not open input file <filename>%1</filename>.", fileName), i18nc("@title:window", "Error Importing Partition Table"));
return;
}
delete dlg;
QByteArray line;
QRegExp rxPartition("(\\d+);(\\d+);(\\d+);(\\w+);(\\w+);(\"\\w*\");(\"[^\"]*\")");
QRegExp rxType("type:\\s\"(.+)\"");
QRegExp rxMagic("^##|v(\\d+)|##");
quint32 lineNo = 0;
bool haveMagic = false;
PartitionTable* ptable = NULL;
PartitionTable::TableType tableType = PartitionTable::unknownTableType;
while (!(line = file.readLine()).isEmpty())
{
lineNo++;
line = line.simplified();
if (line.isEmpty())
continue;
if (!haveMagic && rxMagic.indexIn(line) == -1)
{
KMessageBox::error(this, i18nc("@info", "The file <filename>%1</filename> is not a valid partition table text file.", fileName), i18nc("@title:window", "Error While Importing Partition Table"));
return;
}
else
haveMagic = true;
if (line.startsWith('#'))
continue;
if (rxType.indexIn(line) != -1)
{
if (ptable != NULL)
{
KMessageBox::error(this, i18nc("@info", "Found more than one partition table type in import file (line %1).", lineNo), i18nc("@title:window", "Error While Importing Partition Table"));
return;
}
tableType = PartitionTable::nameToTableType(rxType.cap(1));
if (tableType == PartitionTable::unknownTableType)
{
KMessageBox::error(this, i18nc("@info", "Partition table type \"%1\" is unknown (line %2).", rxType.cap(1), lineNo), i18nc("@title:window", "Error While Importing Partition Table"));
return;
}
if (tableType != PartitionTable::msdos && tableType != PartitionTable::gpt)
{
KMessageBox::error(this, i18nc("@info", "Partition table type \"%1\" is not supported for import (line %2).", rxType.cap(1), lineNo), i18nc("@title:window", "Error While Importing Partition Table"));
return;
}
ptable = new PartitionTable(tableType, PartitionTable::defaultFirstUsable(device, tableType), PartitionTable::defaultLastUsable(device, tableType));
operationStack().push(new CreatePartitionTableOperation(device, ptable));
}
else if (rxPartition.indexIn(line) != -1)
{
if (ptable == NULL)
{
KMessageBox::error(this, i18nc("@info", "Found partition but no partition table type (line %1).", lineNo), i18nc("@title:window", "Error While Importing Partition Table"));
return;
}
qint32 num = rxPartition.cap(1).toInt();
qint64 firstSector = rxPartition.cap(2).toLongLong();
qint64 lastSector = rxPartition.cap(3).toLongLong();
QString fsName = rxPartition.cap(4);
QString roleNames = rxPartition.cap(5);
QString volumeLabel = rxPartition.cap(6).replace('"', "");
QStringList flags = rxPartition.cap(7).replace('"', "").split(',');
if (firstSector < ptable->firstUsable() || lastSector > ptable->lastUsable())
{
KMessageBox::error(this, i18nc("@info", "Partition %1 would be outside the device's boundaries (line %2).", num, lineNo), i18nc("@title:window", "Error While Importing Partition Table"));
return;
}
if (firstSector >= lastSector)
{
KMessageBox::error(this, i18nc("@info", "Partition %1 has end before start sector (line %2).", num, lineNo), i18nc("@title:window", "Error While Importing Partition Table"));
return;
}
PartitionNode* parent = ptable;
Q_ASSERT(parent);
PartitionRole role(PartitionRole::None);
if (roleNames == "extended")
role = PartitionRole(PartitionRole::Extended);
else if (roleNames == "logical")
{
role = PartitionRole(PartitionRole::Logical);
parent = ptable->findPartitionBySector(firstSector, PartitionRole(PartitionRole::Extended));
}
else if (roleNames == "primary")
role = PartitionRole(PartitionRole::Primary);
if (role == PartitionRole(PartitionRole::None))
{
KMessageBox::error(this, i18nc("@info", "Unrecognized partition role \"%1\" for partition %2 (line %3).", roleNames, num, lineNo), i18nc("@title:window", "Error While Importing Partition Table"));
return;
}
if (parent == NULL)
{
KMessageBox::error(this, i18nc("@info", "No parent partition or partition table found for partition %1 (line %2).", num, lineNo), i18nc("@title:window", "Error While Importing Partition Table"));
return;
}
if (role.has(PartitionRole::Extended) && !PartitionTable::tableTypeSupportsExtended(tableType))
{
KMessageBox::error(this, i18nc("@info", "The partition table type \"%1\" does not support extended partitions, but one was found (line %2).", PartitionTable::tableTypeToName(tableType), lineNo), i18nc("@title:window", "Error While Importing Partition Table"));
return;
}
FileSystem* fs = FileSystemFactory::create(FileSystem::typeForName(fsName), firstSector, lastSector);
if (fs == NULL)
{
KMessageBox::error(this, i18nc("@info", "Could not create file system \"%1\" for partition %2 (line %3).", fsName, num, lineNo), i18nc("@title:window", "Error While Importing Partition Table"));
return;
}
if (fs->supportSetLabel() != FileSystem::cmdSupportNone && !volumeLabel.isEmpty())
fs->setLabel(volumeLabel);
Partition* p = new Partition(parent, device, role, fs, firstSector, lastSector, -1, PartitionTable::FlagNone, QStringList(), false, PartitionTable::FlagNone, Partition::StateNew);
operationStack().push(new NewOperation(device, p));
}
else
Log(Log::warning) << i18nc("@info/plain", "Could not parse line %1 from import file. Ignoring it.", lineNo);
}
if (ptable->type() == PartitionTable::msdos && ptable->isSectorBased())
ptable->setType(device, PartitionTable::msdos_sectorbased);
}
void MainWindow::onExportPartitionTable()
@ -683,13 +850,13 @@ void MainWindow::onExportPartitionTable()
if (!file.open(QFile::WriteOnly | QFile::Truncate))
{
KMessageBox::error(this, i18nc("@info", "Could not create output file <filename>%1</filename>.", fileName), i18nc("@window:title", "Error Exporting Partition Table"));
KMessageBox::error(this, i18nc("@info", "Could not create output file <filename>%1</filename>.", fileName), i18nc("@title:window", "Error Exporting Partition Table"));
return;
}
QTextStream stream(&file);
stream << "# partition table of " << pmWidget().selectedDevice()->deviceNode() << "\n";
stream << "##|v1|## partition table of " << pmWidget().selectedDevice()->deviceNode() << "\n";
stream << "# on " << QDateTime::currentDateTime().toString() << "\n";
stream << *pmWidget().selectedDevice()->partitionTable();
}

View File

@ -149,6 +149,7 @@ class LIBPARTITIONMANAGERPRIVATE_EXPORT MainWindow : public KXmlGuiWindow, publi
void onRefreshDevices();
void onCreateNewPartitionTable();
void onExportPartitionTable();
void onImportPartitionTable();
void onApplyAllOperations();
void onUndoOperation();

View File

@ -45,7 +45,10 @@
<Menu name="device">
<text context="@title:menu">Device</text>
<Action name="createNewPartitionTable"/>
<separator/>
<Action name="exportPartitionTable"/>
<Action name="importPartitionTable"/>
<separator/>
<Action name="propertiesDevice"/>
</Menu>
<Menu name="partition">

View File

@ -44,6 +44,20 @@ CreatePartitionTableOperation::CreatePartitionTableOperation(Device& d, Partitio
addJob(createPartitionTableJob());
}
/** Creates a new CreatePartitionTableOperation.
@param d the Device to create the new PartitionTable on
@param ptable pointer to the new partition table object. the operation takes ownership.
*/
CreatePartitionTableOperation::CreatePartitionTableOperation(Device& d, PartitionTable* ptable) :
Operation(),
m_TargetDevice(d),
m_OldPartitionTable(targetDevice().partitionTable()),
m_PartitionTable(ptable),
m_CreatePartitionTableJob(new CreatePartitionTableJob(targetDevice()))
{
addJob(createPartitionTableJob());
}
CreatePartitionTableOperation::~CreatePartitionTableOperation()
{
if (status() == StatusPending)

View File

@ -41,6 +41,7 @@ class CreatePartitionTableOperation : public Operation
public:
CreatePartitionTableOperation(Device& d, PartitionTable::TableType t);
CreatePartitionTableOperation(Device& d, PartitionTable* ptable);
~CreatePartitionTableOperation();
public: