QGIS/src/app/qgsattributeactiondialog.cpp

319 lines
10 KiB
C++

/***************************************************************************
qgsattributeactiondialog.cpp - attribute action dialog
-------------------
This class creates and manages the Action tab of the Vector Layer
Properties dialog box. Changes made in the dialog box are propagated
back to QgsVectorLayer.
begin : October 2004
copyright : (C) 2004 by Gavin Macaulay
email : gavin at macaulay dot co dot nz
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
/* $Id$ */
#include "qgsattributeactiondialog.h"
#include "qgsattributeaction.h"
#include <QFileDialog>
#include <QHeaderView>
QgsAttributeActionDialog::QgsAttributeActionDialog(QgsAttributeAction* actions,
const QgsFieldMap& fields,
QWidget* parent):
QWidget(parent), mActions(actions)
{
setupUi(this);
QHeaderView *header = attributeActionTable->horizontalHeader();
header->setHighlightSections(false);
header->setStretchLastSection(true);
attributeActionTable->setColumnWidth(0, 100);
attributeActionTable->setColumnWidth(1, 230);
#if QT_VERSION >= 0x040300
attributeActionTable->setCornerButtonEnabled(false);
#endif
connect(attributeActionTable, SIGNAL(itemSelectionChanged()),
this, SLOT(itemSelectionChanged()));
connect(moveUpButton, SIGNAL(clicked()), this, SLOT(moveUp()));
connect(moveDownButton, SIGNAL(clicked()), this, SLOT(moveDown()));
connect(removeButton, SIGNAL(clicked()), this, SLOT(remove()));
connect(browseButton, SIGNAL(clicked()), this, SLOT(browse()));
connect(insertButton, SIGNAL(clicked()), this, SLOT(insert()));
connect(updateButton, SIGNAL(clicked()), this, SLOT(update()));
connect(insertFieldButton, SIGNAL(clicked()), this, SLOT(insertField()));
init();
// Populate the combo box with the field names. Will the field names
// change? If so, they need to be passed into the init() call, or
// some access to them retained in this class.
for (QgsFieldMap::const_iterator it = fields.begin(); it != fields.end(); it++)
fieldComboBox->insertItem(it->name());
}
void QgsAttributeActionDialog::init()
{
// Start from a fresh slate.
attributeActionTable->setRowCount(0);
// Populate with our actions.
QgsAttributeAction::AttributeActions::const_iterator
iter = mActions->begin();
int i = 0;
for (; iter != mActions->end(); ++iter, ++i)
{
insertRow(i, iter->name(), iter->action(), iter->capture());
}
}
void QgsAttributeActionDialog::insertRow(int row, const QString &name, const QString &action, bool capture)
{
attributeActionTable->insertRow(row);
attributeActionTable->setItem(row, 0, new QTableWidgetItem(name));
attributeActionTable->setItem(row, 1, new QTableWidgetItem(action));
QTableWidgetItem* item = new QTableWidgetItem();
item->setFlags(item->flags() & ~Qt::ItemIsEditable | Qt::ItemIsUserCheckable);
item->setCheckState(capture ? Qt::Checked : Qt::Unchecked);
attributeActionTable->setItem(row, 2, item);
}
void QgsAttributeActionDialog::moveUp()
{
// Swap the selected row with the one above
int row1 = -1, row2 = -1;
QList<QTableWidgetItem *> selection = attributeActionTable->selectedItems();
if (!selection.isEmpty())
{
row1 = attributeActionTable->row(selection.first());
}
if (row1 > 0)
row2 = row1 - 1;
if (row1 != -1 && row2 != -1)
{
swapRows(row1, row2);
// Move the selection to follow
attributeActionTable->selectRow(row2);
}
}
void QgsAttributeActionDialog::moveDown()
{
// Swap the selected row with the one below
int row1 = -1, row2 = -1;
QList<QTableWidgetItem *> selection = attributeActionTable->selectedItems();
if (!selection.isEmpty())
{
row1 = attributeActionTable->row(selection.first());
}
if (row1 < attributeActionTable->rowCount()-1)
row2 = row1 + 1;
if (row1 != -1 && row2 != -1)
{
swapRows(row1, row2);
// Move the selection to follow
attributeActionTable->selectRow(row2);
}
}
void QgsAttributeActionDialog::swapRows(int row1, int row2)
{
int colCount = attributeActionTable->columnCount();
for (int col = 0; col < colCount; col++)
{
QTableWidgetItem *item = attributeActionTable->takeItem(row1, col);
attributeActionTable->setItem(row1, col, attributeActionTable->takeItem(row2, col));
attributeActionTable->setItem(row2, col, item);
}
}
void QgsAttributeActionDialog::browse()
{
// Popup a file browser and place the results into the actionName
// widget
QString action = QFileDialog::getOpenFileName(
this, tr("Select an action","File dialog window title") );
if (!action.isNull())
actionAction->insert(action);
}
void QgsAttributeActionDialog::remove()
{
QList<QTableWidgetItem *> selection = attributeActionTable->selectedItems();
if (!selection.isEmpty())
{
// Remove the selected row.
int row = attributeActionTable->row(selection.first());
attributeActionTable->removeRow(row);
// And select the row below the one that was selected or the last one.
if (row >= attributeActionTable->rowCount()) row = attributeActionTable->rowCount() - 1;
attributeActionTable->selectRow(row);
}
}
void QgsAttributeActionDialog::insert()
{
// Add the action details as a new row in the table.
int pos = attributeActionTable->rowCount();
insert(pos);
}
void QgsAttributeActionDialog::insert(int pos)
{
// Get the action details and insert into the table at the given
// position. Name needs to be unique, so make it so if required.
// If the new action name is the same as the action name in the
// given pos, don't make the new name unique (because we're
// replacing it).
int numRows = attributeActionTable->rowCount();
QString name;
if (pos < numRows && actionName->text() == attributeActionTable->item(pos, 0)->text())
name = actionName->text();
else
name = uniqueName(actionName->text());
if (pos >= numRows)
{
// Expand the table to have a row with index pos
insertRow(pos, name, actionAction->text(), captureCB->isChecked());
}
else
{
// Update existing row
attributeActionTable->item(pos, 0)->setText(name);
attributeActionTable->item(pos, 1)->setText(actionAction->text());
attributeActionTable->item(pos, 2)->setCheckState(
captureCB->isChecked() ? Qt::Checked : Qt::Unchecked);
}
}
void QgsAttributeActionDialog::update()
{
// Updates the action that is selected with the
// action details.
QList<QTableWidgetItem *> selection = attributeActionTable->selectedItems();
if (!selection.isEmpty())
{
int i = attributeActionTable->row(selection.first());
insert(i);
}
}
void QgsAttributeActionDialog::insertField()
{
// Take the selected field, preprend a % and insert into the action
// field at the cursor position
if (!fieldComboBox->currentText().isNull())
{
QString field("%");
field += fieldComboBox->currentText();
actionAction->insert(field);
}
}
void QgsAttributeActionDialog::apply()
{
// Update the contents of mActions from the UI.
mActions->clearActions();
for (int i = 0; i < attributeActionTable->rowCount(); ++i)
{
const QString &name = attributeActionTable->item(i, 0)->text();
const QString &action = attributeActionTable->item(i, 1)->text();
if (!name.isEmpty() && !action.isEmpty())
{
QTableWidgetItem *item = attributeActionTable->item(i, 2);
mActions->addAction(name, action, item->checkState() == Qt::Checked);
}
}
}
void QgsAttributeActionDialog::itemSelectionChanged()
{
QList<QTableWidgetItem *> selection = attributeActionTable->selectedItems();
if (!selection.isEmpty())
{
#if QT_VERSION < 0x040400
// Supress multiple selection and select row where mouse release occurs.
// Workaround for Qt 4.3 bug which allows multiple rows to be selected if
// the user presses the mouse in one row header and releases in another.
if (attributeActionTable->row(selection.first()) != attributeActionTable->row(selection.last()))
{
attributeActionTable->selectRow(attributeActionTable->currentRow());
selection = attributeActionTable->selectedItems();
}
#endif
rowSelected(attributeActionTable->row(selection.first()));
}
}
void QgsAttributeActionDialog::rowSelected(int row)
{
// The user has selected a row. We take the contents of that row and
// populate the edit section of the dialog so that they can change
// the row if desired.
QTableWidgetItem *item = attributeActionTable->item(row, 2);
if ( item )
{
// Only if a populated row was selected
actionName->setText(attributeActionTable->item(row, 0)->text());
actionAction->setText(attributeActionTable->item(row, 1)->text());
captureCB->setChecked(item->checkState() == Qt::Checked);
}
}
QString QgsAttributeActionDialog::uniqueName(QString name)
{
// Make sure that the given name is unique, adding a numerical
// suffix if necessary.
int pos = attributeActionTable->rowCount();
bool unique = true;
for (int i = 0; i < pos; ++i)
{
if (attributeActionTable->item(i, 0)->text() == name)
unique = false;
}
if (!unique)
{
int suffix_num = 1;
QString new_name;
while (!unique)
{
QString suffix = QString::number(suffix_num);
new_name = name + "_" + suffix;
unique = true;
for (int i = 0; i < pos; ++i)
if (attributeActionTable->item(i, 0)->text() == new_name)
unique = false;
++suffix_num;
}
name = new_name;
}
return name;
}