|
|
|
/***************************************************************************
|
|
|
|
copyright : (C) 2003-2006 by Robby Stephenson
|
|
|
|
email : robby@periapsis.org
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of version 2 of the GNU General Public License as *
|
|
|
|
* published by the Free Software Foundation; *
|
|
|
|
* *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include "tablefieldwidget.h"
|
|
|
|
#include "../field.h"
|
|
|
|
#include "../tellico_utils.h"
|
|
|
|
#include "../tellico_kernel.h"
|
|
|
|
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kpopupmenu.h>
|
|
|
|
#include <kiconloader.h>
|
|
|
|
#include <kinputdialog.h>
|
|
|
|
|
|
|
|
#include <tqtable.h>
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
static const int MIN_TABLE_ROWS = 5;
|
|
|
|
static const int MAX_TABLE_COLS = 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
using Tellico::GUI::TableFieldWidget;
|
|
|
|
|
|
|
|
TableFieldWidget::TableFieldWidget(Data::FieldPtr field_, TQWidget* parent_, const char* name_/*=0*/)
|
|
|
|
: FieldWidget(field_, parent_, name_), m_field(field_), m_row(-1), m_col(-1) {
|
|
|
|
|
|
|
|
bool ok;
|
|
|
|
m_columns = Tellico::toUInt(field_->property(TQString::fromLatin1("columns")), &ok);
|
|
|
|
if(!ok) {
|
|
|
|
m_columns = 1;
|
|
|
|
} else {
|
|
|
|
m_columns = TQMIN(m_columns, MAX_TABLE_COLS); // max of 5 columns
|
|
|
|
}
|
|
|
|
|
|
|
|
m_table = new TQTable(MIN_TABLE_ROWS, m_columns, this);
|
|
|
|
labelColumns(m_field);
|
|
|
|
// allow renaming of column titles
|
|
|
|
m_table->horizontalHeader()->setClickEnabled(true);
|
|
|
|
m_table->horizontalHeader()->installEventFilter(this);
|
|
|
|
|
|
|
|
m_table->verticalHeader()->setClickEnabled(true);
|
|
|
|
m_table->verticalHeader()->installEventFilter(this);
|
|
|
|
connect(m_table->verticalHeader(), TQT_SIGNAL(indexChange(int, int, int)), TQT_SIGNAL(modified()));
|
|
|
|
|
|
|
|
m_table->setDragEnabled(false);
|
|
|
|
m_table->setFocusStyle(TQTable::FollowStyle);
|
|
|
|
m_table->setRowMovingEnabled(true); // rows can be moved
|
|
|
|
m_table->setColumnMovingEnabled(false); // columns remain fixed
|
|
|
|
|
|
|
|
m_table->setColumnStretchable(m_columns-1, true);
|
|
|
|
m_table->adjustColumn(m_columns-1);
|
|
|
|
m_table->setSelectionMode(TQTable::NoSelection);
|
|
|
|
m_table->setHScrollBarMode(TQScrollView::AlwaysOff);
|
|
|
|
|
|
|
|
connect(m_table, TQT_SIGNAL(valueChanged(int, int)), TQT_SIGNAL(modified()));
|
|
|
|
connect(m_table, TQT_SIGNAL(currentChanged(int, int)), TQT_SLOT(slotCheckRows(int, int)));
|
|
|
|
connect(m_table, TQT_SIGNAL(valueChanged(int, int)), TQT_SLOT(slotResizeColumn(int, int)));
|
|
|
|
connect(m_table, TQT_SIGNAL(contextMenuRequested(int, int, const TQPoint&)), TQT_SLOT(contextMenu(int, int, const TQPoint&)));
|
|
|
|
|
|
|
|
registerWidget();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString TableFieldWidget::text() const {
|
|
|
|
TQString text, str, rstack, cstack, rowStr;
|
|
|
|
for(int row = 0; row < m_table->numRows(); ++row) {
|
|
|
|
rowStr.truncate(0);
|
|
|
|
cstack.truncate(0);
|
|
|
|
for(int col = 0; col < m_table->numCols(); ++col) {
|
|
|
|
str = m_table->text(row, col).simplifyWhiteSpace();
|
|
|
|
if(str.isEmpty()) {
|
|
|
|
cstack += TQString::fromLatin1("::");
|
|
|
|
} else {
|
|
|
|
rowStr += cstack + str + TQString::fromLatin1("::");
|
|
|
|
cstack.truncate(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(rowStr.isEmpty()) {
|
|
|
|
rstack += TQString::fromLatin1("; ");
|
|
|
|
} else {
|
|
|
|
rowStr.truncate(rowStr.length()-2); // remove last semi-colon and space
|
|
|
|
text += rstack + rowStr + TQString::fromLatin1("; ");
|
|
|
|
rstack.truncate(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!text.isEmpty()) {
|
|
|
|
text.truncate(text.length()-2); // remove last semi-colon and space
|
|
|
|
}
|
|
|
|
|
|
|
|
// now reduce number of rows if necessary
|
|
|
|
bool loop = true;
|
|
|
|
for(int row = m_table->numRows()-1; loop && row > MIN_TABLE_ROWS; --row) {
|
|
|
|
bool empty = true;
|
|
|
|
for(int col = 0; col < m_table->numCols(); ++col) {
|
|
|
|
if(!m_table->text(row, col).isEmpty()) {
|
|
|
|
empty = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(empty) {
|
|
|
|
m_table->removeRow(row);
|
|
|
|
} else {
|
|
|
|
loop = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return text;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TableFieldWidget::setText(const TQString& text_) {
|
|
|
|
TQStringList list = Data::Field::split(text_, true);
|
|
|
|
// add additional rows if needed
|
|
|
|
if(static_cast<int>(list.count()) > m_table->numRows()) {
|
|
|
|
m_table->insertRows(m_table->numRows(), list.count()-m_table->numRows());
|
|
|
|
}
|
|
|
|
int row;
|
|
|
|
for(row = 0; row < static_cast<int>(list.count()); ++row) {
|
|
|
|
for(int col = 0; col < m_table->numCols(); ++col) {
|
|
|
|
m_table->setText(row, col, list[row].section(TQString::fromLatin1("::"), col, col));
|
|
|
|
}
|
|
|
|
m_table->showRow(row);
|
|
|
|
}
|
|
|
|
// remove any un-needed rows
|
|
|
|
int minRow = TQMAX(row, MIN_TABLE_ROWS);
|
|
|
|
for(row = m_table->numRows()-1; row >= minRow; --row) {
|
|
|
|
m_table->removeRow(row);
|
|
|
|
}
|
|
|
|
// adjust all columns
|
|
|
|
for(int col = 0; col < m_table->numCols()-1; ++col) {
|
|
|
|
m_table->adjustColumn(col);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TableFieldWidget::clear() {
|
|
|
|
bool wasEmpty = true;
|
|
|
|
for(int row = 0; row < m_table->numRows(); ++row) {
|
|
|
|
if(!emptyRow(row)) {
|
|
|
|
wasEmpty = false;
|
|
|
|
}
|
|
|
|
for(int col = 0; col < m_table->numCols(); ++col) {
|
|
|
|
m_table->setText(row, col, TQString());
|
|
|
|
}
|
|
|
|
if(row >= MIN_TABLE_ROWS) {
|
|
|
|
m_table->removeRow(row);
|
|
|
|
--row;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
editMultiple(false);
|
|
|
|
if(!wasEmpty) {
|
|
|
|
emit modified();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQWidget* TableFieldWidget::widget() {
|
|
|
|
return m_table;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TableFieldWidget::slotCheckRows(int row_, int) {
|
|
|
|
if(row_ == m_table->numRows()-1 && !emptyRow(row_)) { // if is last row and row above is not empty
|
|
|
|
m_table->insertRows(m_table->numRows());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TableFieldWidget::slotResizeColumn(int, int col_) {
|
|
|
|
m_table->adjustColumn(col_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TableFieldWidget::slotRenameColumn() {
|
|
|
|
if(m_col < 0 || m_col >= m_columns) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
TQString name = m_table->horizontalHeader()->label(m_col);
|
|
|
|
bool ok;
|
|
|
|
TQString newName = KInputDialog::getText(i18n("Rename Column"), i18n("New column name:"),
|
|
|
|
name, &ok, this);
|
|
|
|
if(ok && !newName.isEmpty()) {
|
|
|
|
Data::FieldPtr newField = new Data::Field(*m_field);
|
|
|
|
newField->setProperty(TQString::fromLatin1("column%1").arg(m_col+1), newName);
|
|
|
|
if(Kernel::self()->modifyField(newField)) {
|
|
|
|
m_field = newField;
|
|
|
|
labelColumns(m_field);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TableFieldWidget::emptyRow(int row_) const {
|
|
|
|
for(int col = 0; col < m_table->numCols(); ++col) {
|
|
|
|
if(!m_table->text(row_, col).isEmpty()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TableFieldWidget::labelColumns(Data::FieldPtr field_) {
|
|
|
|
for(int i = 0; i < m_columns; ++i) {
|
|
|
|
TQString s = field_->property(TQString::fromLatin1("column%1").arg(i+1));
|
|
|
|
if(s.isEmpty()) {
|
|
|
|
s = i18n("Column %1").arg(i+1);
|
|
|
|
}
|
|
|
|
m_table->horizontalHeader()->setLabel(i, s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TableFieldWidget::updateFieldHook(Data::FieldPtr, Data::FieldPtr newField_) {
|
|
|
|
bool ok;
|
|
|
|
m_columns = Tellico::toUInt(newField_->property(TQString::fromLatin1("columns")), &ok);
|
|
|
|
if(!ok) {
|
|
|
|
m_columns = 1;
|
|
|
|
} else {
|
|
|
|
m_columns = TQMIN(m_columns, MAX_TABLE_COLS); // max of 5 columns
|
|
|
|
}
|
|
|
|
if(m_columns != m_table->numCols()) {
|
|
|
|
m_table->setNumCols(m_columns);
|
|
|
|
}
|
|
|
|
m_table->horizontalHeader()->adjustHeaderSize();
|
|
|
|
labelColumns(newField_);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TableFieldWidget::eventFilter(TQObject* obj_, TQEvent* ev_) {
|
|
|
|
if(ev_->type() == TQEvent::MouseButtonPress
|
|
|
|
&& TQT_TQMOUSEEVENT(ev_)->button() == Qt::RightButton) {
|
|
|
|
if(TQT_BASE_OBJECT(obj_) == TQT_BASE_OBJECT(m_table->horizontalHeader())) {
|
|
|
|
TQMouseEvent* ev = TQT_TQMOUSEEVENT(ev_);
|
|
|
|
// might be scrolled
|
|
|
|
int pos = ev->x() + m_table->horizontalHeader()->offset();
|
|
|
|
int col = m_table->horizontalHeader()->sectionAt(pos);
|
|
|
|
if(col >= m_columns) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
m_row = -1;
|
|
|
|
m_col = col;
|
|
|
|
KPopupMenu menu(this);
|
|
|
|
menu.insertItem(SmallIconSet(TQString::fromLatin1("edit")), i18n("Rename Column..."),
|
|
|
|
this, TQT_SLOT(slotRenameColumn()));
|
|
|
|
menu.exec(ev->globalPos());
|
|
|
|
return true;
|
|
|
|
} else if(TQT_BASE_OBJECT(obj_) == TQT_BASE_OBJECT(m_table->verticalHeader())) {
|
|
|
|
TQMouseEvent* ev = TQT_TQMOUSEEVENT(ev_);
|
|
|
|
// might be scrolled
|
|
|
|
int pos = ev->y() + m_table->verticalHeader()->offset();
|
|
|
|
int row = m_table->verticalHeader()->sectionAt(pos);
|
|
|
|
if(row < 0 || row > m_table->numRows()-1) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
m_row = row;
|
|
|
|
m_col = -1;
|
|
|
|
// show regular right-click menu
|
|
|
|
contextMenu(m_row, m_col, ev->globalPos());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FieldWidget::eventFilter(obj_, ev_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TableFieldWidget::contextMenu(int row_, int col_, const TQPoint& p_) {
|
|
|
|
// might get called with col == -1 for clicking on vertical header
|
|
|
|
// but a negative row means clicking outside bounds of table
|
|
|
|
if(row_ < 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_row = row_;
|
|
|
|
m_col = col_;
|
|
|
|
|
|
|
|
int id;
|
|
|
|
KPopupMenu menu(this);
|
|
|
|
menu.insertItem(SmallIconSet(TQString::fromLatin1("insrow")), i18n("Insert Row"),
|
|
|
|
this, TQT_SLOT(slotInsertRow()));
|
|
|
|
menu.insertItem(SmallIconSet(TQString::fromLatin1("remrow")), i18n("Remove Row"),
|
|
|
|
this, TQT_SLOT(slotRemoveRow()));
|
|
|
|
id = menu.insertItem(SmallIconSet(TQString::fromLatin1("1uparrow")), i18n("Move Row Up"),
|
|
|
|
this, TQT_SLOT(slotMoveRowUp()));
|
|
|
|
if(m_row == 0) {
|
|
|
|
menu.setItemEnabled(id, false);
|
|
|
|
}
|
|
|
|
id = menu.insertItem(SmallIconSet(TQString::fromLatin1("1downarrow")), i18n("Move Row Down"),
|
|
|
|
this, TQT_SLOT(slotMoveRowDown()));
|
|
|
|
if(m_row == m_table->numRows()-1) {
|
|
|
|
menu.setItemEnabled(id, false);
|
|
|
|
}
|
|
|
|
menu.insertSeparator();
|
|
|
|
id = menu.insertItem(SmallIconSet(TQString::fromLatin1("edit")), i18n("Rename Column..."),
|
|
|
|
this, TQT_SLOT(slotRenameColumn()));
|
|
|
|
if(m_col < 0 || m_col > m_columns-1) {
|
|
|
|
menu.setItemEnabled(id, false);
|
|
|
|
}
|
|
|
|
menu.insertSeparator();
|
|
|
|
menu.insertItem(SmallIconSet(TQString::fromLatin1("locationbar_erase")), i18n("Clear Table"),
|
|
|
|
this, TQT_SLOT(clear()));
|
|
|
|
menu.exec(p_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TableFieldWidget::slotInsertRow() {
|
|
|
|
if(m_row > -1) {
|
|
|
|
m_table->insertRows(m_row);
|
|
|
|
emit modified();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TableFieldWidget::slotRemoveRow() {
|
|
|
|
if(m_row > -1) {
|
|
|
|
m_table->removeRow(m_row);
|
|
|
|
emit modified();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TableFieldWidget::slotMoveRowUp() {
|
|
|
|
if(m_row > 0) {
|
|
|
|
m_table->swapRows(m_row, m_row-1, true);
|
|
|
|
m_table->updateContents();
|
|
|
|
emit modified();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TableFieldWidget::slotMoveRowDown() {
|
|
|
|
if(m_row < m_table->numRows()-1) {
|
|
|
|
m_table->swapRows(m_row, m_row+1, true);
|
|
|
|
m_table->updateContents();
|
|
|
|
emit modified();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "tablefieldwidget.moc"
|