[rkward-cvs] SF.net SVN: rkward: [2190] branches/KDE4_port/rkward

tfry at users.sourceforge.net tfry at users.sourceforge.net
Thu Nov 8 23:23:15 UTC 2007


Revision: 2190
          http://rkward.svn.sourceforge.net/rkward/?rev=2190&view=rev
Author:   tfry
Date:     2007-11-08 15:23:14 -0800 (Thu, 08 Nov 2007)

Log Message:
-----------
After a lot of butchering, the data editor can be compiled again, but opening an editor crashes right away...

Modified Paths:
--------------
    branches/KDE4_port/rkward/core/rcontainerobject.cpp
    branches/KDE4_port/rkward/core/rkvariable.cpp
    branches/KDE4_port/rkward/dataeditor/editlabelsdialog.cpp
    branches/KDE4_port/rkward/dataeditor/editlabelsdialog.h
    branches/KDE4_port/rkward/dataeditor/rkeditordataframe.cpp
    branches/KDE4_port/rkward/dataeditor/rkeditordataframe.h
    branches/KDE4_port/rkward/dataeditor/rkeditordataframepart.cpp
    branches/KDE4_port/rkward/dataeditor/rktextmatrix.cpp
    branches/KDE4_port/rkward/dataeditor/rktextmatrix.h
    branches/KDE4_port/rkward/dataeditor/rkvareditmodel.cpp
    branches/KDE4_port/rkward/dataeditor/rkvareditmodel.h
    branches/KDE4_port/rkward/dataeditor/twintable.cpp
    branches/KDE4_port/rkward/dataeditor/twintable.h
    branches/KDE4_port/rkward/dataeditor/twintabledatamember.cpp
    branches/KDE4_port/rkward/dataeditor/twintabledatamember.h
    branches/KDE4_port/rkward/dataeditor/twintablemember.cpp
    branches/KDE4_port/rkward/dataeditor/twintablemember.h
    branches/KDE4_port/rkward/dataeditor/twintablemetamember.cpp
    branches/KDE4_port/rkward/dataeditor/twintablemetamember.h
    branches/KDE4_port/rkward/windows/rkworkplace.cpp

Modified: branches/KDE4_port/rkward/core/rcontainerobject.cpp
===================================================================
--- branches/KDE4_port/rkward/core/rcontainerobject.cpp	2007-11-08 15:07:49 UTC (rev 2189)
+++ branches/KDE4_port/rkward/core/rcontainerobject.cpp	2007-11-08 23:23:14 UTC (rev 2190)
@@ -408,6 +408,8 @@
 	}
 	if (!unique) return ret;
 
+// NOTE: this is potentially a quadratic time algorithm with respect to number of children.
+// Its only called on user actions, though, and hopefully users will not keep all objects named "varX".
 	int i=0;
 	QString postfix;
 	while (findChildByName (ret + postfix)) {

Modified: branches/KDE4_port/rkward/core/rkvariable.cpp
===================================================================
--- branches/KDE4_port/rkward/core/rkvariable.cpp	2007-11-08 15:07:49 UTC (rev 2189)
+++ branches/KDE4_port/rkward/core/rkvariable.cpp	2007-11-08 23:23:14 UTC (rev 2190)
@@ -648,7 +648,7 @@
 	RK_ASSERT (from_row <= to_row);
 
 	QString *ret = new QString[(to_row - from_row) + 1];
-	
+
 	int i = 0;
 	for (int row = from_row; row <= to_row; ++row) {
 		ret[i] = getText (row);

Modified: branches/KDE4_port/rkward/dataeditor/editlabelsdialog.cpp
===================================================================
--- branches/KDE4_port/rkward/dataeditor/editlabelsdialog.cpp	2007-11-08 15:07:49 UTC (rev 2189)
+++ branches/KDE4_port/rkward/dataeditor/editlabelsdialog.cpp	2007-11-08 23:23:14 UTC (rev 2190)
@@ -2,7 +2,7 @@
                           editlabelsdialog  -  description
                              -------------------
     begin                : Tue Sep 21 2004
-    copyright            : (C) 2004, 2006 by Thomas Friedrichsmeier
+    copyright            : (C) 2004, 2006, 2007 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -22,200 +22,201 @@
 #include <kactioncollection.h>
 #include <kvbox.h>
 
-#include <qapplication.h>
-#include <qclipboard.h>
 #include <qlabel.h>
 #include <qlayout.h>
-#include <qpushbutton.h>
-#include <qpainter.h>
-#include <qrect.h>
-#include <qpalette.h>
-#include <qstyle.h>
+#include <QHeaderView>
 //Added by qt3to4:
-#include <Q3HBoxLayout>
-#include <QResizeEvent>
-#include <Q3VBoxLayout>
+#include <QHBoxLayout>
+#include <QVBoxLayout>
 
 #include "../core/rkvariable.h"
+#include "rktextmatrix.h"
 #include "celleditor.h"
 
 #include "../debug.h"
 
-LevelsTable::LevelsTable (QWidget *parent, RObject::ValueLabels *labels) : TwinTableMember (parent, 0, 1, 0) {
+RKVarLevelsTable::RKVarLevelsTable (QWidget *parent, RObject::ValueLabels *labels) : QTableView (parent) {
 	RK_TRACE (EDITOR);
 
 	RK_ASSERT (labels);
-	storage = labels;
 
-	updating_size = false;
-
-	setNumCols (1);
-	setNumRows (storage->count () + 1);
-	horizontalHeader ()->setLabel (0, i18n ("Label"));
-	setHScrollBarMode (Q3ScrollView::AlwaysOff);
-	setLeftMargin (40);
+	setHorizontalScrollBarPolicy (Qt::ScrollBarAlwaysOff);
+	setSelectionMode (QAbstractItemView::ContiguousSelection);
+	horizontalHeader ()->setStretchLastSection (true);
+	verticalHeader ()->setFixedWidth (40);
 	setMinimumWidth (80);
 
 	KActionCollection *ac = new KActionCollection (this);
 	ac->addAction (KStandardAction::Cut, this, SLOT (cut ()));
 	ac->addAction (KStandardAction::Copy, this, SLOT (copy ()));
 	ac->addAction (KStandardAction::Paste, this, SLOT (paste ()));
+
+	setModel (lmodel = new RKVarLevelsTableModel (labels, this));
 }
 
-LevelsTable::~LevelsTable () {
+RKVarLevelsTable::~RKVarLevelsTable () {
 	RK_TRACE (EDITOR);
 }
 
-void LevelsTable::cut () {
+bool RKVarLevelsTable::getSelectionBoundaries (int* top, int* bottom) const {
 	RK_TRACE (EDITOR);
 
+	RK_ASSERT (selectionModel ());
+	QItemSelection sel = selectionModel ()->selection ();
+	if (sel.isEmpty ()){
+		QModelIndex current = currentIndex ();
+		if (!current.isValid ()) return false;
+
+		*top = current.row ();
+		*bottom = current.row ();
+	} else {
+		RK_ASSERT (sel.size () == 1);
+		*top = sel[0].top ();
+		*bottom = sel[0].bottom ();
+	}
+	return true;
+}
+
+void RKVarLevelsTable::cut () {
+	RK_TRACE (EDITOR);
+
+	int top;
+	int bottom;
+	if (!getSelectionBoundaries (&top, &bottom)) return;
+
 	copy ();
-	blankSelected ();
+
+	for (int i = top; i <= bottom; ++i) lmodel->setData (lmodel->index (i, 0), QString ());
 }
 
-void LevelsTable::paste () {
+void RKVarLevelsTable::copy () {
 	RK_TRACE (EDITOR);
 
-// Unfortunately, we need to duplicate some of TwinTable::paste () and RKEditorDataFramPart::doPaste. Those are not easy to reconcile.
+	int top;
+	int bottom;
+	if (!getSelectionBoundaries (&top, &bottom)) return;
 
-	// actually, we don't care, whether tsv or plain gets pasted - it's both
-	// treated the same. We should however encourage external senders to
-	// provided the two in order.
-	QString pasted;
-	const QMimeData* data = QApplication::clipboard ()->mimeData ();
-	if (data->hasFormat ("text/tab-separated-values")) {
-		pasted = QString::fromLocal8Bit (data->data ("text/tab-separated-values"));
-	} else if (data->hasText ()) {
-		pasted = data->text ();
-	} else {
-		RK_DO (qDebug ("no suitable format for pasting"), EDITOR, DL_INFO);
-		return;
+	RKTextMatrix mat;
+	int trow = 0;
+	for (int i = top; i <= bottom; ++i) {
+		mat.setText (trow++, 0, lmodel->data (lmodel->index (i, 0)).toString ());
 	}
+	mat.copyToClipboard ();
+}
 
-	int content_offset = 0;
-	int content_length = pasted.length ();
-	bool look_for_tabs;			// break on tabs or on lines?
-	int next_delim;
+void RKVarLevelsTable::paste () {
+	RK_TRACE (EDITOR);
 
-	int first_tab = pasted.find ('\t', 0);
-	if (first_tab < 0) first_tab = content_length;
-	int first_line = pasted.find ('\n', 0);
-	if (first_line < 0) first_line = content_length;
-	if (first_tab < first_line) {
-		look_for_tabs = true;
-		next_delim = first_tab;
-	} else {
-		look_for_tabs = false;
-		next_delim = first_line;
-	}
+// Unfortunately, we need to duplicate some of TwinTable::paste () and RKEditorDataFramPart::doPaste. Those are not easy to reconcile.
+	QModelIndex current = currentIndex ();
+	if (!current.isValid ()) return;
+	int row = current.row ();
+	RK_ASSERT (current.column () == 0);
 
-	int row = currentRow ();
-	do {
-		if (row >= numTrueRows ()) insertRows (row);
-		setText (row, 0, pasted.mid (content_offset, next_delim - content_offset));
+	RKTextMatrix pasted = RKTextMatrix::matrixFromClipboard ();
+	if (pasted.isEmpty ()) return;
 
-		++row;
-		content_offset = next_delim + 1;
-		if (look_for_tabs) {
-			next_delim = pasted.find ('\t', content_offset);
-		} else {
-			next_delim = pasted.find ('\n', content_offset);
+	if (pasted.numColumns () > 1) {		// there were tabs in the pasted text. Let's transpose the first row
+		for (int i = 0; i < pasted.numColumns (); ++i) {
+			lmodel->setData (lmodel->index (row++, 0), pasted.getText (0, i));
 		}
-		if (next_delim < 0) next_delim = content_length;
-	} while (content_offset < content_length);
+	} else {		// else paste the first column
+		for (int i = 0; i < pasted.numRows (); ++i) {
+			lmodel->setData (lmodel->index (row++, 0), pasted.getText (i, 0));
+		}
+	}
 }
 
-void LevelsTable::setText (int row, int col, const QString &text) {
+/////////////// RKVarLevelsTableModel /////////////////
+
+RKVarLevelsTableModel::RKVarLevelsTableModel (RObject::ValueLabels* labels, QObject* parent) : QAbstractTableModel (parent) {
 	RK_TRACE (EDITOR);
-	RK_ASSERT (col == 0);
 
-	storage->insert (QString::number (row+1), text);
-	if (text.isEmpty ()) {
-		int maxrow = numTrueRows ()-1;
-		while ((maxrow >= 0) && LevelsTable::text (maxrow, 1).isEmpty ()) {
-			storage->remove (QString::number (maxrow + 1));
-			--maxrow;
-		}
-		setNumRows (maxrow + 2);
-	}
+	RKVarLevelsTableModel::labels = labels;
+}
 
-	updateCell (row, col);
+RKVarLevelsTableModel::~RKVarLevelsTableModel () {
+	RK_TRACE (EDITOR);
 }
 
-QString LevelsTable::text (int row, int) const {
+int RKVarLevelsTableModel::rowCount (const QModelIndex& parent) const {
 	RK_TRACE (EDITOR);
 
-	if (row < numTrueRows ()) {
-		return ((*storage)[QString::number (row+1)]);
-	}
-	return QString ();
+	if (parent.isValid ()) return 0;
+	return labels->count () + 1;
 }
 
-void LevelsTable::paintCell (QPainter *p, int row, int col, const QRect &cr, bool selected, const QColorGroup &cg) {
-	// no trace for paint operations
+int RKVarLevelsTableModel::columnCount (const QModelIndex& parent) const {
+	RK_TRACE (EDITOR);
 
-	paintCellInternal (p, row, col, cr, selected, cg, 0, 0, text (row, col), 0);
+	if (parent.isValid ()) return 0;
+	return 1;
 }
 
-QWidget *LevelsTable::beginEdit (int row, int col, bool) {
+QVariant RKVarLevelsTableModel::data (const QModelIndex& index, int role) const {
 	RK_TRACE (EDITOR);
-	RK_ASSERT (!tted);
 
-	if (col != 0) return 0;
+	if (!index.isValid ()) return QVariant ();
+	if (index.column () != 0) return QVariant ();
+	if ((role == Qt::BackgroundRole) && (index.row () == labels->count ())) return QBrush (Qt::gray);
+	if (index.row () >= labels->count ()) return QVariant ();
 
-	if (row >= numTrueRows ()) {
-		insertRows (numRows (), 1);
-	}
-	
-	tted = new CellEditor (this, text (row, col), 0, 0);
+	if ((role != Qt::DisplayRole) || (role != Qt::EditRole)) return QVariant ();
 
-	QRect cr = cellGeometry (row, col);
-	tted->resize (cr.size ());
-	moveChild (tted, cr.x (), cr.y ());
-	tted->show ();
-	
-	tted->setActiveWindow ();
-	tted->setFocus ();
-	connect (tted, SIGNAL (lostFocus ()), this, SLOT (editorLostFocus ()));
-
-	updateCell (row, col);
-	return (tted);
+	return labels->value (QString::number (index.row ()+1));
 }
 
-void LevelsTable::resizeEvent (QResizeEvent *e) {
+Qt::ItemFlags RKVarLevelsTableModel::flags (const QModelIndex& index) const {
 	RK_TRACE (EDITOR);
 
-	updating_size = true;
-	int nwidth = e->size ().width () - leftMargin ();
-	if (nwidth < 40) {
-		setLeftMargin (e->size ().width () - 40);
-		nwidth = 40;
-	}
-	setColumnWidth (0, nwidth);
-	updating_size = false;
-
-	Q3Table::resizeEvent (e);
+	if (!index.isValid ()) return 0;
+	if (index.column () != 0) return 0;
+	if (index.row () >= labels->count ()) return (Qt::ItemIsEditable | Qt::ItemIsEnabled);
+	return (Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
 }
 
-void LevelsTable::columnWidthChanged (int col) {
+bool RKVarLevelsTableModel::setData (const QModelIndex& index, const QVariant& value, int role) {
 	RK_TRACE (EDITOR);
 
-	if (updating_size) return;
+	if (role != Qt::EditRole) return false;
+	if (!index.isValid ()) return false;
+	if (index.column () != 0) return false;
+	if (!value.isValid ()) return false;
+	if (index.row () > labels->count ()) return false;
 
-	updating_size = true;
+	QString text = value.toString ();
+	if (index.row () == labels->count ()) {
+		beginInsertRows (QModelIndex (), index.row (), index.row ());
+		labels->insert (QString::number (index.row () + 1), value.toString ());
+		endInsertRows ();
+	} else {
+		labels->insert (QString::number (index.row () + 1), value.toString ());
+		emit (dataChanged (index, index));
+	}
 
-	if (columnWidth (0) < 40) {
-		setColumnWidth (0, 40);
+	if (text.isEmpty ()) {	// remove trailing empty rows
+		while ((!labels->isEmpty ()) && labels->value (QString::number (labels->size ())).isEmpty ()) {
+			int row = labels->size () - 1;
+			beginRemoveRows (QModelIndex (), row, row);
+			labels->remove (QString::number (row + 1));
+			endRemoveRows ();
+		}
 	}
-	setLeftMargin (width () - columnWidth (0));
 
-	updating_size = false;
-
-	Q3Table::columnWidthChanged (col);
+	return true;
 }
 
+QVariant RKVarLevelsTableModel::headerData (int section, Qt::Orientation orientation, int role) const {
+	RK_TRACE (EDITOR);
 
+	if (role != Qt::DisplayRole) return QVariant ();
+	if (orientation == Qt::Vertical) return QString::number (section + 1);
+	if (section != 0) return QVariant ();
+	return i18n ("Label");
+}
 
+//////////////// EditLabelsDialog ///////////////////////
+
 EditLabelsDialog::EditLabelsDialog (QWidget *parent, RKVariable *var, int mode) : KDialog (parent) {
 	RK_TRACE (EDITOR);
 	RK_ASSERT (var);
@@ -229,26 +230,14 @@
 	QLabel *label = new QLabel (i18n ("Levels can be assigned only to consecutive integers starting with 1 (the index column is read only). To remove levels at the end of the list, just set them to empty."), mainvbox);
 	label->setWordWrap (true);
 
-	Q3HBoxLayout *hbox = new Q3HBoxLayout (mainvbox, KDialog::spacingHint ());
-
 	RObject::ValueLabels *labels = var->getValueLabels ();
 	if (!labels) {
 		labels = new RObject::ValueLabels;
 	}
 
-	table = new LevelsTable (this, labels);
-	hbox->addWidget (table);
+	table = new RKVarLevelsTable (mainvbox, labels);
 
-	Q3HBoxLayout *buttonbox = new Q3HBoxLayout (mainvbox, KDialog::spacingHint ());
-
-	QPushButton *ok_button = new QPushButton (i18n ("Ok"), this);
-	connect (ok_button, SIGNAL (clicked ()), this, SLOT (accept ()));
-	buttonbox->addWidget (ok_button);
-
-	QPushButton *cancel_button = new QPushButton (i18n ("Cancel"), this);
-	connect (cancel_button, SIGNAL (clicked ()), this, SLOT (reject ()));
-	buttonbox->addWidget (cancel_button);
-	
+	setButtons (KDialog::Ok | KDialog::Cancel);
 	setCaption (i18n ("Levels / Value labels for '%1'", var->getShortName ()));
 }
 
@@ -259,8 +248,10 @@
 void EditLabelsDialog::accept () {
 	RK_TRACE (EDITOR);
 
-	table->stopEditing ();
-	RObject::ValueLabels *labels = table->storage;
+#warning do we need something like this? how to achieve it?
+//	table->stopEditing ();
+
+	RObject::ValueLabels *labels = table->lmodel->labels;
 	if (labels->isEmpty ()) {
 		var->setValueLabels (0);
 	} else {

Modified: branches/KDE4_port/rkward/dataeditor/editlabelsdialog.h
===================================================================
--- branches/KDE4_port/rkward/dataeditor/editlabelsdialog.h	2007-11-08 15:07:49 UTC (rev 2189)
+++ branches/KDE4_port/rkward/dataeditor/editlabelsdialog.h	2007-11-08 23:23:14 UTC (rev 2190)
@@ -2,7 +2,7 @@
                           editlabelsdialog  -  description
                              -------------------
     begin                : Tue Sep 21 2004
-    copyright            : (C) 2004, 2006 by Thomas Friedrichsmeier
+    copyright            : (C) 2004, 2006, 2007 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -18,49 +18,56 @@
 #define EDITLABELSDIALOG_H
 
 #include <kdialog.h>
-//Added by qt3to4:
-#include <QResizeEvent>
 
+#include <QTableView>
+#include <QAbstractTableModel>
+
 #include "../core/robject.h"
 
 class RKVariable;
+class RKVarLevelsTableModel;
 
-#include "twintablemember.h"
-
 /** special mini class provides the table in EditLabelsDialog
 TODO: make copy/paste work
 
 @author Thomas Friedrichsmeier
 */
-class LevelsTable : public TwinTableMember {
+class RKVarLevelsTable : public QTableView {
 	Q_OBJECT
 public:
-	LevelsTable (QWidget *parent, RObject::ValueLabels *labels);
-	~LevelsTable ();
-/** reimplemented form QTable not to add trailing rows/cols if needed */
-	QWidget *beginEdit (int row, int col, bool replace);
-/** reimplemented form QTable  to work on RObject::ValueLabels instead of QTableItems */
-	void paintCell (QPainter *p, int row, int col, const QRect &cr, bool selected, const QColorGroup &cg);
-/** reimplemented form QTable to work on RObject::ValueLabels instead of QTableItems */
-	void setText (int row, int col, const QString &text);
-/** reimplemented form QTable to work on RObject::ValueLabels instead of QTableItems */
-	QString text (int row, int col) const;
+	RKVarLevelsTable (QWidget *parent, RObject::ValueLabels *labels);
+	~RKVarLevelsTable ();
 public slots:
 /** cut */
-	void cut();
+	void cut ();
+/** cut */
+	void copy ();
 /** paste */
-	void paste();
-protected:
-/** reimplemented to resize the table columns so that there's no unused space to the right */
-	void resizeEvent (QResizeEvent *e);
-/** reimplemented to resize the table columns so that there's no unused space to the right */
-	void columnWidthChanged (int col);
+	void paste ();
 private:
+	bool getSelectionBoundaries (int* top, int* bottom) const;
 friend class EditLabelsDialog;
-	RObject::ValueLabels *storage;
+	RKVarLevelsTableModel* lmodel;
 	bool updating_size;
 };
 
+/** Data model for the RKVarLevelsTable */
+class RKVarLevelsTableModel : public QAbstractTableModel {
+public:
+	RKVarLevelsTableModel (RObject::ValueLabels* labels, QObject* parent);
+	~RKVarLevelsTableModel ();
+
+	int rowCount (const QModelIndex& parent = QModelIndex()) const;
+	int columnCount (const QModelIndex& parent = QModelIndex()) const;
+	QVariant data (const QModelIndex& index, int role = Qt::DisplayRole) const;
+	Qt::ItemFlags flags (const QModelIndex& index) const;
+	bool setData (const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
+	QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+private:
+friend class EditLabelsDialog;
+	RObject::ValueLabels* labels;
+};
+
 /**
 Allows editing of value labels / factor levels for an (edited) RKVariable
 
@@ -80,7 +87,7 @@
 /// reimplemented to submit the changes to the backend
 	void accept ();
 private:
-	LevelsTable *table;
+	RKVarLevelsTable *table;
 	RKVariable *var;
 	int mode;
 };

Modified: branches/KDE4_port/rkward/dataeditor/rkeditordataframe.cpp
===================================================================
--- branches/KDE4_port/rkward/dataeditor/rkeditordataframe.cpp	2007-11-08 15:07:49 UTC (rev 2189)
+++ branches/KDE4_port/rkward/dataeditor/rkeditordataframe.cpp	2007-11-08 23:23:14 UTC (rev 2190)
@@ -23,13 +23,11 @@
 #include "../rkglobals.h"
 #include "twintable.h"
 #include "twintablemember.h"
-#include "twintabledatamember.h"
-#include "twintablemetamember.h"
+#include "rkvareditmodel.h"
 #include "../core/robject.h"
 #include "../core/robjectlist.h"
 #include "../core/rkvariable.h"
 #include "../core/rcontainerobject.h"
-#include "../core/rkmodificationtracker.h"
 #include "rkeditordataframepart.h"
 #include "../windows/rkworkplace.h"
 #include "../misc/rkstandardicons.h"
@@ -40,13 +38,19 @@
 // warning! numbers above GET_DATA_OFFSET are used to determine, which row, the data should go to!
 #define GET_DATA_OFFSET 10
 
-RKEditorDataFrame::RKEditorDataFrame (RObject* object, QWidget *parent) : TwinTable (parent) {
+RKEditorDataFrame::RKEditorDataFrame (RContainerObject* object, QWidget *parent) : TwinTable (parent) {
 	RK_TRACE (EDITOR);
 
 	commonInit ();
 
 	RK_ASSERT (!object->isPending ());
-	openObject (object);
+	RKEditor::object = object;
+	RK_ASSERT (object->isDataFrame ());
+
+	RKVarEditDataFrameModel* model = new RKVarEditDataFrameModel (object, this);
+	initTable (model);
+
+	waitForLoad ();
 }
 
 RKEditorDataFrame::RKEditorDataFrame (const QString& new_object_name, QWidget* parent) : TwinTable (parent) {
@@ -56,21 +60,15 @@
 
 	QString valid = RObjectList::getObjectList ()->validizeName (new_object_name);
 	if (valid != new_object_name) KMessageBox::sorry (this, i18n ("The name you specified was already in use or not valid. Renamed to %1", valid), i18n ("Invalid Name"));
-	RObject *object = RObjectList::getObjectList ()->createPendingChild (valid, -1, true, true);
 
-// initialize the new object
-#warning TODO: call model->insertColumns() instead.
-	for (int i=0; i < numTrueCols (); ++i) {
-		RObject *child = static_cast<RContainerObject *> (object)->createPendingChild (static_cast<RContainerObject *> (object)->validizeName (QString ()), i);
-		if (child->isVariable ()) {
-			static_cast<RKVariable*> (child)->setLength (dataview->numTrueRows ());
-		} else {
-			RK_ASSERT (false);
-		}
-	}
-	pushTable (open_chain);
+	RKVarEditDataFrameModel* model = new RKVarEditDataFrameModel (valid, RObjectList::getObjectList (), open_chain, 5, this);
+	initTable (model);
 
-	openObject (object);
+	RKEditor::object = model->getObject ();;
+	RK_ASSERT (object->isDataFrame ());
+
+#warning is this needed? Of is it enough to close the chain?
+	waitForLoad ();
 }
 
 void RKEditorDataFrame::commonInit () {
@@ -89,10 +87,10 @@
 	if (on) {
 		connect (this, SIGNAL (deleteColumnRequest (int)), this, SLOT (columnDeletionRequested (int)));
 		connect (this, SIGNAL (addedColumn (int)), this, SLOT (columnAdded (int)));
-		varview->setEnabled (true);
+		metaview->setEnabled (true);
 		dataview->setEnabled (true);
 	} else {
-		varview->setEnabled (false);
+		metaview->setEnabled (false);
 		dataview->setEnabled (false);
 		disconnect (this, SIGNAL (deleteColumnRequest (int)), this, SLOT (columnDeletionRequested (int)));
 		disconnect (this, SIGNAL (addedColumn (int)), this, SLOT (columnAdded (int)));
@@ -108,18 +106,12 @@
 	flushEdit ();
 }
 
-void RKEditorDataFrame::openObject (RObject *object) {
+void RKEditorDataFrame::waitForLoad () {
 	RK_TRACE (EDITOR);
 	flushEdit ();
-	RKEditor::object = object;
-	RK_ASSERT (object->isDataFrame ());
 
 	enableEditing (false);
 
-	// trigger fetching of the edit data
-	object->markDataDirty ();
-	object->updateFromR (open_chain);
-
 	RCommand *command = new RCommand (QString (), RCommand::EmptyCommand | RCommand::Sync | RCommand::GetStringVector, QString (), this, LOAD_COMPLETE_COMMAND);
 	RKGlobals::rInterface ()->issueCommand (command, open_chain);
 }
@@ -135,72 +127,11 @@
 	}
 }
 
-void RKEditorDataFrame::pushTable (RCommandChain *sync_chain) {
-	RK_TRACE (EDITOR);
-	flushEdit ();
-	QString command;
-#warning TODO: move to model
-	// first push the data-table
-	TwinTableMember *table = dataview;
-	command = getObject ()->getFullName ();
-	command.append (" <- data.frame (");
-	
-	QString na_vector = "=as.numeric (rep (NA, " + QString::number (getColObject (0)->getLength ()) + "))";
-	for (int col=0; col < table->numTrueCols (); col++) {
-		if (col != 0) command.append (", ");
-		command.append (getColObject (col)->getShortName () + na_vector);
-	}
-	command.append (")");
-
-	RKGlobals::rInterface ()->issueCommand (new RCommand (command, RCommand::Sync | RCommand::ObjectListUpdate), sync_chain);
-	for (int col=0; col < table->numTrueCols (); col++) {
-		getColObject (col)->restore (sync_chain);
-	}
-
-	// now store the meta-data
-	getObject ()->writeMetaData (sync_chain);
-}
-
-void RKEditorDataFrame::columnDeletionRequested (int col) {
-	RK_TRACE (EDITOR);
-	RObject *obj = getColObject (col);
-	RK_ASSERT (obj);
-	// for now:
-	if (!obj) return;
-
-	RKGlobals::tracker ()->removeObject (obj);
-}
-
 void RKEditorDataFrame::restoreObject (RObject *object) {
 	RK_TRACE (EDITOR);
-	// for now, simply sync the whole table unconditionally.
-	if (object == getObject ()) {
-		pushTable (0);
-	} else {
-		RK_ASSERT (object->isVariable ());
-		static_cast<RKVariable*> (object)->restore ();
-	}
-}
 
-void RKEditorDataFrame::updateObjectMeta (RObject *object) {
-	RK_TRACE (EDITOR);
-	if (object == getObject ()) return;	// for now: can't update meta on the table itself
-	
-	int col = getObjectCol (object);
-	for (int i=0; i < varview->numTrueRows (); ++i) {
-		varview->updateCell (i, col);
-	}
+#warning TODO: this interface should be moved to the model for good.
+	datamodel->restoreObject (object, 0);
 }
 
-void RKEditorDataFrame::updateObjectData (RObject *object, RObject::ChangeSet *changes) {
-	RK_TRACE (EDITOR);
-	
-	if (object != getObject ()) {
-		int col = getObjectCol (object);
-		for (int i=0; i < dataview->numTrueRows (); ++i) {
-			dataview->updateCell (i, col);
-		}
-	}
-}
-
 #include "rkeditordataframe.moc"

Modified: branches/KDE4_port/rkward/dataeditor/rkeditordataframe.h
===================================================================
--- branches/KDE4_port/rkward/dataeditor/rkeditordataframe.h	2007-11-08 15:07:49 UTC (rev 2189)
+++ branches/KDE4_port/rkward/dataeditor/rkeditordataframe.h	2007-11-08 23:23:14 UTC (rev 2190)
@@ -31,12 +31,11 @@
 @author Thomas Friedrichsmeier
 */
 class RKEditorDataFrame : public TwinTable, public RCommandReceiver {
-	Q_OBJECT
 public:
 /** constructor.
 @param object an existing R object
 @param parent parent widget */
-	RKEditorDataFrame (RObject* object, QWidget *parent);
+	RKEditorDataFrame (RContainerObject* object, QWidget *parent);
 /** This constructor creates a new (empty) data.frame with the given name and then opens it for editing.
 @param new_object_name name of the new data.frame
 @param parent parent widget */
@@ -51,23 +50,14 @@
 
 /** Tells the editor to restore the given object in the R-workspace from its copy of the data */
 	void restoreObject (RObject *object);
-/** Tell the editor to (unconditionally) update its representation of the object meta data */
-	void updateObjectMeta (RObject *object);
-/** Tell the editor to (unconditionally) update its representation of the object data (in the range given in the ChangeSet) */
-	void updateObjectData (RObject *object, RObject::ChangeSet *changes);
-public slots:
-	void columnDeletionRequested (int col);
 private:
 /// syncs the whole table.
 	void pushTable (RCommandChain *sync_chain);
 	void commonInit ();
 	RCommandChain *open_chain;
 	void enableEditing (bool on);
-	void updateMetaValue (RObject *obj, int row, int col, bool sync=true);
-
-	void modifyObjectMeta (RObject *object, int column);
+	void waitForLoad ();
 protected:
-	void openObject (RObject *object);
 	void rCommandDone (RCommand *command);
 };
 

Modified: branches/KDE4_port/rkward/dataeditor/rkeditordataframepart.cpp
===================================================================
--- branches/KDE4_port/rkward/dataeditor/rkeditordataframepart.cpp	2007-11-08 15:07:49 UTC (rev 2189)
+++ branches/KDE4_port/rkward/dataeditor/rkeditordataframepart.cpp	2007-11-08 23:23:14 UTC (rev 2190)
@@ -103,17 +103,7 @@
 
 	RKWardMainWindow::getMain ()->slotSetStatusBarText (i18n ("Inserting clipboard contents..."));
 
-	const QMimeData* data = QApplication::clipboard ()->mimeData ();
-	// actually, we don't care, whether tsv or plain gets pasted - it's both
-	// treated the same. We should however encourage external senders to
-	// provided the two in order.
-	if (data->hasFormat ("text/tab-separated-values")) {
-		RK_DO (qDebug ("paste tsv"), EDITOR, DL_DEBUG);
-		editor->paste (QString::fromLocal8Bit (data->data ("text/tab-separated-values")), mode);
-	} else if (data->hasText ()) {
-		RK_DO (qDebug ("paste plain text"), EDITOR, DL_DEBUG);
-		editor->paste (data->text (), mode);
-	}
+	editor->paste (mode);
 
 	RKWardMainWindow::getMain ()->slotSetStatusReady ();
 }

Modified: branches/KDE4_port/rkward/dataeditor/rktextmatrix.cpp
===================================================================
--- branches/KDE4_port/rkward/dataeditor/rktextmatrix.cpp	2007-11-08 15:07:49 UTC (rev 2189)
+++ branches/KDE4_port/rkward/dataeditor/rktextmatrix.cpp	2007-11-08 23:23:14 UTC (rev 2190)
@@ -144,18 +144,15 @@
 	return (columns[col][row]);
 }
 
-QString* RKTextMatrix::getColumn (int col, int* col_length) const {
+QString* RKTextMatrix::getColumn (int col) const {
 	RK_TRACE (EDITOR);
 
 	if (col > colcount) {
-		*col_length = 0;
 		return 0;
 	}
 
 	TextColumn column = columns[col];
 	QString* ret = new QString[column.size ()];
-	*col_length = column.size ();
-	RK_ASSERT (*col_length == rowcount);
 	for (int i = 0; i < column.size (); ++i) {
 		ret[i] = column[i];
 	}

Modified: branches/KDE4_port/rkward/dataeditor/rktextmatrix.h
===================================================================
--- branches/KDE4_port/rkward/dataeditor/rktextmatrix.h	2007-11-08 15:07:49 UTC (rev 2189)
+++ branches/KDE4_port/rkward/dataeditor/rktextmatrix.h	2007-11-08 23:23:14 UTC (rev 2190)
@@ -39,13 +39,18 @@
 	void copyToClipboard () const;
 
 	void setText (int row, int col, const QString& text);
+	/** set an entire column at once. This takes a copy of the data, so you will still have to delete it when done. */
 	void setColumn (int column, const QString* textarray, int length);
 
 	QString getText (int row, int col) const;
-	QString* getColumn (int col, int* col_length) const;
+	/** get the contents of an entire column at once. It's your responsibility to delete the data when done. The returned array has length numRows() */
+	QString* getColumn (int col) const;
 
 	void clear ();
 	bool isEmpty () const;
+
+	int numColumns () const { return colcount; }
+	int numRows () const { return rowcount; }
 private:
 	typedef QVector<QString> TextColumn;
 	QVector<TextColumn> columns;

Modified: branches/KDE4_port/rkward/dataeditor/rkvareditmodel.cpp
===================================================================
--- branches/KDE4_port/rkward/dataeditor/rkvareditmodel.cpp	2007-11-08 15:07:49 UTC (rev 2189)
+++ branches/KDE4_port/rkward/dataeditor/rkvareditmodel.cpp	2007-11-08 23:23:14 UTC (rev 2190)
@@ -26,7 +26,7 @@
 
 #include "../debug.h"
 
-RKVarEditModel::RKVarEditModel (QObject *parent) : QAbstractTableModel (parent), RObjectListener (RObjectListener::DataModel) {
+RKVarEditModel::RKVarEditModel (QObject *parent) : RKVarEditModelBase (parent), RObjectListener (RObjectListener::DataModel) {
 	RK_TRACE (EDITOR);
 
 	meta_model = 0;
@@ -75,7 +75,7 @@
 	}
 }
 
-void RKVarEditModel::doInsertColumn (int) {
+void RKVarEditModel::doInsertColumns (int, int) {
 	RK_TRACE (EDITOR);
 	RK_ASSERT (false);	// should be implemented in a subclass, or never called
 }
@@ -233,7 +233,7 @@
 
 	if (col >= objects.size ()) {		// trailing col
 		// somebody should add a column for us
-		doInsertColumn (objects.size ());
+		doInsertColumns (objects.size (), 1);
 
 		if (col >= objects.size ()) {
 			// apparently, no column has been added in the above signal
@@ -264,10 +264,95 @@
 	return QString::number (section);
 }
 
+RKTextMatrix RKVarEditModel::getTextMatrix (const QItemSelectionRange& range) const {
+	RK_TRACE (EDITOR);
 
+	if ((!range.isValid ()) || objects.isEmpty ()) return RKTextMatrix ();
+
+// NOTE: of course, when the range is small, this is terribly inefficient. On the other hand, it doesn't really matter, then, either.
+	QItemSelectionRange erange = range.intersected (QItemSelectionRange (index (0, 0), index (trueRows () - 1, trueCols () - 1)));
+	int top = erange.top ();
+	int bottom = erange.bottom ();
+	int left = erange.left ();
+	int right = erange.right ();
+
+	RKTextMatrix ret;
+	int tcol = 0;
+	for (int col = left; col <= right; ++col) {
+		QString* data = objects[col]->getCharacter (top, bottom);
+		RK_ASSERT (data);
+		ret.setColumn (tcol, data, top - bottom + 1);
+		delete [] data;
+		++tcol;
+	}
+
+	return ret;
+}
+
+void RKVarEditModel::blankRange (const QItemSelectionRange& range) {
+	RK_TRACE (EDITOR);
+
+	if ((!range.isValid ()) || objects.isEmpty ()) return;
+
+// NOTE: of course, when the range is small, this is terribly inefficient. On the other hand, it doesn't really matter, then, either.
+	QItemSelectionRange erange = range.intersected (QItemSelectionRange (index (0, 0), index (trueRows () - 1, trueCols () - 1)));
+	int top = erange.top ();
+	int bottom = erange.bottom ();
+	int left = erange.left ();
+	int right = erange.right ();
+
+	for (int col = left; col <= right; ++col) {
+		RKVariable* var = objects[col];
+		for (int row = top; row <= bottom; ++row) {
+			var->setText (row, QString ());
+		}
+	}
+}
+
+void RKVarEditModel::setTextMatrix (const QModelIndex& offset, const RKTextMatrix& text, const QItemSelectionRange& confine_to) {
+	RK_TRACE (EDITOR);
+
+// NOTE: of course, when the range is small, this is terribly inefficient. On the other hand, it doesn't really matter, then, either. Single cells will be set using setData()
+	if ((!offset.isValid ()) || text.isEmpty ()) return;
+
+	int top = offset.row ();
+	int left = offset.column ();
+	int bottom = top + text.numRows () - 1;
+	int right = left + text.numColumns () - 1;
+	if (confine_to.isValid ()) {
+		if (confine_to.top () > top) return;	// can't confine top-left. Should have been set by caller
+		if (confine_to.left () > left) return;
+		bottom = qMin (confine_to.bottom (), bottom);
+		right = qMin (confine_to.right (), right);
+	}
+
+// TODO: some models might not support column addition.
+	if (right >= trueCols ()) doInsertColumns (objects.size (), right - trueCols () + 1);
+	RK_ASSERT (right < trueCols ());
+	int current_rows = objects[0]->getLength ();
+	if (bottom >= current_rows) insertRows (current_rows, bottom - current_rows + 1);
+
+	int tcol = 0;
+	for (int col = left; col <= right; ++col) {
+		RKVariable* var = objects[col];
+		QString* data = text.getColumn (tcol);
+		RK_ASSERT (data);
+		var->setCharacter (top, bottom, data);
+		delete [] data;		// hm, why doesn't RKVariable take ownership?
+		++tcol;
+	}
+}
+
+void RKVarEditModel::restoreObject (RObject* object, RCommandChain* chain) {
+	RK_TRACE (EDITOR);
+
+	RK_ASSERT (objects.contains (static_cast<RKVariable*> (object)));
+	static_cast<RKVariable*> (object)->restore (chain);
+}
+
 /////////////////// RKVarEditMetaModel ////////////////////////
 
-RKVarEditMetaModel::RKVarEditMetaModel (RKVarEditModel* data_model) : QAbstractTableModel (data_model) {
+RKVarEditMetaModel::RKVarEditMetaModel (RKVarEditModel* data_model) : RKVarEditModelBase (data_model) {
 	RK_TRACE (EDITOR);
 	RK_ASSERT (data_model);
 
@@ -382,7 +467,7 @@
 
 	if (col >= data_model->objects.size ()) {		// trailing col
 		// somebody should add a column for us
-		data_model->doInsertColumn (data_model->objects.size ());
+		data_model->doInsertColumns (data_model->objects.size (), 1);
 
 		if (col >= data_model->objects.size ()) {
 			// apparently, no column has been added in the above signal
@@ -431,13 +516,126 @@
 	return QVariant ();
 }
 
+RKTextMatrix RKVarEditMetaModel::getTextMatrix (const QItemSelectionRange& range) const {
+	RK_TRACE (EDITOR);
 
+	if ((!range.isValid ()) || data_model->objects.isEmpty ()) return RKTextMatrix ();
+
+// NOTE: of course, when the range is small, this is terribly inefficient. On the other hand, it doesn't really matter, then, either.
+	QItemSelectionRange erange = range.intersected (QItemSelectionRange (index (0, 0), index (trueRows () - 1, trueCols () - 1)));
+	int top = erange.top ();
+	int bottom = erange.bottom ();
+	int left = erange.left ();
+	int right = erange.right ();
+
+	RKTextMatrix ret;
+	int tcol = 0;
+	for (int col = left; col <= right; ++col) {
+		int trow = 0;
+		for (int row = top; row <= bottom; ++row) {
+			QVariant celldata = data (index (row, col), Qt::EditRole);
+			if (!celldata.isValid ()) {
+				RK_ASSERT (false);
+				break;
+			}
+			ret.setText (trow, tcol, celldata.toString ());
+			++trow;
+		}
+		++tcol;
+	}
+
+	return ret;
+}
+
+void RKVarEditMetaModel::blankRange (const QItemSelectionRange& range) {
+	RK_TRACE (EDITOR);
+
+	if ((!range.isValid ()) || data_model->objects.isEmpty ()) return;
+
+// NOTE: of course, when the range is small, this is terribly inefficient. On the other hand, it doesn't really matter, then, either.
+	QItemSelectionRange erange = range.intersected (QItemSelectionRange (index (0, 0), index (trueRows () - 1, trueCols () - 1)));
+	int top = erange.top ();
+	int bottom = erange.bottom ();
+	int left = erange.left ();
+	int right = erange.right ();
+
+	for (int col = left; col <= right; ++col) {
+		RKVariable* var = data_model->objects[col];
+		var->setSyncing (false);
+		for (int row = top; row <= bottom; ++row) {
+			setData (createIndex (row, col), QString (), Qt::EditRole);
+		}
+		var->setSyncing (true);
+	}
+}
+
+void RKVarEditMetaModel::setTextMatrix (const QModelIndex& offset, const RKTextMatrix& text, const QItemSelectionRange& confine_to) {
+	RK_TRACE (EDITOR);
+
+	if ((!offset.isValid ()) || text.isEmpty ()) return;
+
+	int top = offset.row ();
+	int left = offset.column ();
+	int bottom = top + text.numRows () - 1;
+	int right = left + text.numColumns () - 1;
+	if (confine_to.isValid ()) {
+		if (confine_to.top () > top) return;	// can't confine top-left. Should have been set by caller
+		if (confine_to.left () > left) return;
+		bottom = qMin (confine_to.bottom (), bottom);
+		right = qMin (confine_to.right (), right);
+	}
+
+// TODO: some models might not support column addition.
+	if (right >= trueCols ()) data_model->doInsertColumns (trueCols (), right - trueCols () + 1);
+	RK_ASSERT (right < data_model->objects.size ());
+	bottom = qMin (bottom, trueRows () - 1);
+
+	int tcol = 0;
+	for (int col = left; col <= right; ++col) {
+		int trow = 0;
+		RKVariable* var = data_model->objects[col];
+		var->setSyncing (false);
+		for (int row = top; row <= bottom; ++row) {
+			setData (index (row, col), text.getText (trow, tcol), Qt::EditRole);
+			++trow;
+		}
+		var->setSyncing (true);
+		++tcol;
+	}
+}
+
+
 /////////////////// RKVarEditDataFrameModel ////////////////////////
 
 
-RKVarEditDataFrameModel::RKVarEditDataFrameModel (RContainerObject* dataframe, QObject *parent) : RKVarEditModel (parent) {
+RKVarEditDataFrameModel::RKVarEditDataFrameModel (RContainerObject* dataframe, QObject* parent) : RKVarEditModel (parent) {
 	RK_TRACE (EDITOR);
 
+	init (dataframe);
+}
+
+RKVarEditDataFrameModel::RKVarEditDataFrameModel (const QString& validized_name, RContainerObject* parent_object, RCommandChain* chain, int initial_cols, QObject* parent) : RKVarEditModel (parent) {
+	RK_TRACE (EDITOR);
+
+	RObject *object = parent_object->createPendingChild (validized_name, -1, true, true);
+	RK_ASSERT (object->isDataFrame ());
+	RContainerObject* df = static_cast<RContainerObject*> (object);
+
+// initialize the new object
+	for (int i = 0; i < initial_cols; ++i) {
+		RObject* child = df->createPendingChild (QString (), -1, false, false);
+		RK_ASSERT (child->isVariable ());
+	}
+
+	init (df);
+
+	// creates the pending object in the backend
+	pushTable (chain);
+}
+
+void RKVarEditDataFrameModel::init (RContainerObject* dataframe) {
+	RK_TRACE (EDITOR);
+
 	RKVarEditDataFrameModel::dataframe = dataframe;
 
 	trailing_rows = 1;
@@ -559,10 +757,47 @@
 	}
 }
 
-void RKVarEditDataFrameModel::doInsertColumn (int index) {
+void RKVarEditDataFrameModel::doInsertColumns (int index, int count) {
 	RK_TRACE (EDITOR);
 
-	insertColumns (index, 1);
+	insertColumns (index, count);
 }
 
+void RKVarEditDataFrameModel::pushTable (RCommandChain *sync_chain) {
+	RK_TRACE (EDITOR);
+
+	// first push real data
+	QString command = dataframe->getFullName ();
+	command.append (" <- data.frame (");
+
+	RK_ASSERT (objects.size ());
+	RKVariable* child = objects[0];
+	QString na_vector = "=as.numeric (rep (NA, " + QString::number (child->getLength ()) + "))";
+	for (int col=0; col < objects.size (); ++col) {
+		if (col != 0) command.append (", ");
+		command.append (objects[col]->getShortName () + na_vector);
+	}
+	command.append (")");
+
+	// push all children
+	RKGlobals::rInterface ()->issueCommand (new RCommand (command, RCommand::Sync | RCommand::ObjectListUpdate), sync_chain);
+	for (int col=0; col < objects.size (); ++col) {
+		objects[col]->restore (sync_chain);
+	}
+
+	// now store the meta-data
+	dataframe->writeMetaData (sync_chain);
+}
+
+void RKVarEditDataFrameModel::restoreObject (RObject* object, RCommandChain* chain) {
+	RK_TRACE (EDITOR);
+
+	if (object == dataframe) {
+		pushTable (chain);
+	} else {
+		RKVarEditModel::restoreObject (object, chain);
+	}
+}
+
+
 #include "rkvareditmodel.moc"

Modified: branches/KDE4_port/rkward/dataeditor/rkvareditmodel.h
===================================================================
--- branches/KDE4_port/rkward/dataeditor/rkvareditmodel.h	2007-11-08 15:07:49 UTC (rev 2189)
+++ branches/KDE4_port/rkward/dataeditor/rkvareditmodel.h	2007-11-08 23:23:14 UTC (rev 2190)
@@ -19,16 +19,34 @@
 #define RKVAREDITMODEL
 
 #include <QAbstractTableModel>
+#include <QItemSelectionRange>
 #include <QList>
 
+#include "rktextmatrix.h"
 #include "../core/rkvariable.h"
 #include "../core/rkmodificationtracker.h"
 
 class RKVarEditMetaModel;
+class RCommandChain;
 class RKEditor;
 
+/** Base class for RKVarEditModel and RKVarEditMetaModel. Defines a common interface for copy and paste operations. Models might reimplement these functions for more efficiency.
+ at author Thomas Friedrichsmeier */
+class RKVarEditModelBase : public QAbstractTableModel {
+public:
+	RKVarEditModelBase (QObject *parent) : QAbstractTableModel (parent) {};
+	virtual ~RKVarEditModelBase () {};
+
+	virtual RKTextMatrix getTextMatrix (const QItemSelectionRange& range) const = 0;
+	virtual void blankRange (const QItemSelectionRange& range) = 0;
+	virtual void setTextMatrix (const QModelIndex& offset, const RKTextMatrix& text, const QItemSelectionRange& confine_to = QItemSelectionRange ()) = 0;
+
+	virtual int trueRows () const = 0;
+	virtual int trueCols () const = 0;
+};
+
 /** This class represents a collection of RKVariables of uniform length (typically a data.frame) suitable for editing in a model/view editor such as QTableView. Probably it will only ever support editing a single RKVariable, though, as it is not possible to ensure uniform length outside of a data.frame. For a data.frame use RKVarEditDataFrameModel . Since the real data storage is in RKVariable, it is ok (and recommended) to create separate models for separate editors/viewers, even if the objects in question are the same. */
-class RKVarEditModel : public QAbstractTableModel, public RObjectListener {
+class RKVarEditModel : public RKVarEditModelBase, public RObjectListener {
 	Q_OBJECT
 public:
 	RKVarEditModel (QObject *parent);
@@ -55,6 +73,15 @@
 	Qt::ItemFlags flags (const QModelIndex& index) const;
 	bool setData (const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
 	QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+
+	RKTextMatrix getTextMatrix (const QItemSelectionRange& range) const;
+	void blankRange (const QItemSelectionRange& range);
+	void setTextMatrix (const QModelIndex& offset, const RKTextMatrix& text, const QItemSelectionRange& confine_to = QItemSelectionRange ());
+
+	int trueCols () const { return objects.size (); };
+	int trueRows () const { return (objects.isEmpty () ? 0 : objects[0]->getLength ()); };
+
+	virtual void restoreObject (RObject* object, RCommandChain* chain);
 protected:
 friend class RKVarEditMetaModel;
 	QList<RKVariable*> objects;
@@ -67,8 +94,8 @@
 	/** Receives notifications of object removals. Takes care of removing the object from the list. */
 	void objectRemoved (RObject* object);
 
-	/** insert a new column at index. Default implementation does nothing. To be implemented in subclasses */
-	virtual void doInsertColumn (int index);
+	/** insert new columns at index. Default implementation does nothing. To be implemented in subclasses */
+	virtual void doInsertColumns (int index, int count);
 
 	virtual void doInsertRowsInBackend (int row, int count);
 	virtual void doRemoveRowsInBackend (int row, int count);
@@ -83,7 +110,7 @@
 };
 
 /** Represents the meta information portion belonging to an RKVarEditModel. Implemented in a separate class for technical reasons, only (so this info can be displayed in a separate QTableView). This model mostly acts as a slave of an RKVarEditModel. You will not need to call any functions directly except from the RKVarEditModel, or an item view. */
-class RKVarEditMetaModel : public QAbstractTableModel {
+class RKVarEditMetaModel : public RKVarEditModelBase {
 	Q_OBJECT
 public:
 	enum Rows {
@@ -102,6 +129,13 @@
 	Qt::ItemFlags flags (const QModelIndex& index) const;
 	bool setData (const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
 	QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+
+	RKTextMatrix getTextMatrix (const QItemSelectionRange& range) const;
+	void blankRange (const QItemSelectionRange& range);
+	void setTextMatrix (const QModelIndex& offset, const RKTextMatrix& text, const QItemSelectionRange& confine_to = QItemSelectionRange ());
+
+	int trueCols () const { return data_model->trueCols (); };
+	int trueRows () const { return RowCount; };
 protected:
 friend class RKVarEditModel;
 	RKVarEditMetaModel (RKVarEditModel* data_model);
@@ -119,13 +153,19 @@
 class RKVarEditDataFrameModel : public RKVarEditModel {
 	Q_OBJECT
 public:
-	RKVarEditDataFrameModel (RContainerObject* dataframe, QObject *parent);
+	RKVarEditDataFrameModel (RContainerObject* dataframe, QObject* parent);
+/** ctor that constructs a new empty data frame */
+	RKVarEditDataFrameModel (const QString& validized_name, RContainerObject* parent_object, RCommandChain* chain, int initial_cols, QObject* parent);
 	~RKVarEditDataFrameModel ();
 
 	bool insertColumns (int column, int count, const QModelIndex& parent = QModelIndex());
 	bool removeColumns (int column, int count, const QModelIndex& parent = QModelIndex());
+
+	RContainerObject* getObject () const { return dataframe; };
+
+	void restoreObject (RObject* object, RCommandChain* chain);
 protected:
-	void doInsertColumn (int index);
+	void doInsertColumns (int index, int count);
 	/** reimplemented from RKVarEditModel to listen for the dataframe object as well */
 	void objectRemoved (RObject* object);
 	/** receives notifications of new objects added to this data.frame */
@@ -137,6 +177,9 @@
 	void doRemoveRowsInBackend (int row, int count);
 
 	RContainerObject* dataframe;
+
+	void init (RContainerObject* dataframe);
+	void pushTable (RCommandChain* sync_chain);
 };
 
 #endif

Modified: branches/KDE4_port/rkward/dataeditor/twintable.cpp
===================================================================
--- branches/KDE4_port/rkward/dataeditor/twintable.cpp	2007-11-08 15:07:49 UTC (rev 2189)
+++ branches/KDE4_port/rkward/dataeditor/twintable.cpp	2007-11-08 23:23:14 UTC (rev 2190)
@@ -2,7 +2,7 @@
                           twintable.cpp  -  description
                              -------------------
     begin                : Tue Oct 29 2002
-    copyright            : (C) 2002, 2006 by Thomas Friedrichsmeier
+    copyright            : (C) 2002, 2006, 2007 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -16,99 +16,70 @@
  ***************************************************************************/
 
 #include "twintable.h"
+
 #include <klocale.h>
 
 #include <qvariant.h>
 #include <qsplitter.h>
 #include <qlayout.h>
-#include <qtooltip.h>
-#include <q3whatsthis.h>
-#include <qimage.h>
-#include <qpixmap.h>
-#include <q3popupmenu.h>
-#include <q3cstring.h>
-//Added by qt3to4:
-#include <Q3GridLayout>
-#include <Q3ValueList>
+#include <QMenu>
+#include <QVBoxLayout>
+#include <QHeaderView>
 
-#include "twintabledatamember.h"
-#include "twintablemetamember.h"
 #include "twintablemember.h"
+#include "rkvareditmodel.h"
 
 #include "../debug.h"
 
-#include "../core/robject.h"
-#include "../core/rkvariable.h"
-
-#define HEADER_MENU_ID_ADD_COL_LEFT 0
-#define HEADER_MENU_ID_ADD_COL_RIGHT 1
-#define HEADER_MENU_ID_DEL_COL 2
-
-#define HEADER_MENU_ID_ADD_ROW_ABOVE 0
-#define HEADER_MENU_ID_ADD_ROW_BELOW 1
-#define HEADER_MENU_ID_DEL_ROW 2
-#define HEADER_MENU_ID_DEL_ROWS 3
-
-
 TwinTable::TwinTable (QWidget *parent) : RKEditor (parent) {
 	RK_TRACE (EDITOR);
 
-	Q3GridLayout *grid_layout = new Q3GridLayout(this);
+	QVBoxLayout *layout = new QVBoxLayout(this);
+	layout->setContentsMargins (0, 0, 0, 0);
 	
 	QSplitter *splitter = new QSplitter(this);
 	splitter->setOrientation(Qt::Vertical);
+
+	metaview = new TwinTableMember (splitter, this);
+	splitter->setResizeMode (metaview, QSplitter::KeepSize);
+	metaview->verticalHeader()->setResizeMode (QHeaderView::Fixed);
+
+#warning TODO set item delegates
 	
-	varview = new TwinTableMetaMember (splitter, this);
-	varview->setNumRows (5);
-	varview->setNumCols (5);
-	varview->verticalHeader ()->setLabel (LABEL_ROW, i18n ("Label"));
-	varview->verticalHeader ()->setLabel (TYPE_ROW, i18n ("Type"));
-	varview->verticalHeader ()->setLabel (LEVELS_ROW, i18n ("Levels"));
-	varview->verticalHeader ()->setLabel (FORMAT_ROW, i18n ("Format"));
-	varview->verticalHeader ()->setLabel (NAME_ROW, i18n ("Name"));
-	varview->setMinimumHeight (varview->horizontalHeader ()->height ());
-	varview->setMaximumHeight (varview->rowPos (NAME_ROW) + varview->rowHeight (NAME_ROW) + varview->horizontalHeader ()->height () + 5);
-	splitter->setResizeMode (varview, QSplitter::KeepSize);
-	varview->verticalHeader()->setResizeEnabled (false);
+	dataview = new TwinTableMember (splitter, this);
+	dataview->verticalHeader()->setResizeMode (QHeaderView::Fixed);
 	
-	dataview = new TwinTableDataMember (splitter, this);
-	dataview->setNumRows (1);
-	dataview->setNumCols (5);
-	dataview->verticalHeader()->setResizeEnabled (false);
-	
 	dataview->horizontalHeader ()->hide ();
-	dataview->setTopMargin (0);
-	dataview->setLeftMargin (varview->leftMargin ());
-	varview->setHScrollBarMode (Q3ScrollView::AlwaysOff);
+#warning is this needed?
+//	dataview->setTopMargin (0);
+//	dataview->setLeftMargin (metaview->leftMargin ());
+	metaview->setHorizontalScrollBarPolicy (Qt::ScrollBarAlwaysOff);
 	
-	grid_layout->addWidget (splitter, 0, 0);
+	layout->addWidget (splitter);
 	
 	// these are to keep the two tables in sync
-	varview->setTwin (dataview);
-	dataview->setTwin (varview);
-	connect (dataview, SIGNAL (contentsMoving (int, int)), this, SLOT (scrolled (int, int)));
-	connect (varview, SIGNAL (contentsMoving (int, int)), this, SLOT (autoScrolled (int, int)));
-	connect (varview->horizontalHeader (), SIGNAL (clicked (int)), dataview, SLOT (columnClicked (int)));
-	connect (varview->horizontalHeader (), SIGNAL (clicked (int)), this, SLOT (headerClicked (int)));
-	connect (varview, SIGNAL (selectionChanged ()), this, SLOT (dataClearSelection ()));
-	connect (dataview, SIGNAL (selectionChanged ()), this, SLOT (viewClearSelection ()));
+	metaview->setTwin (dataview);
+	dataview->setTwin (metaview);
+	connect (metaview->horizontalHeader (), SIGNAL (sectionClicked(int)), dataview, SLOT (selectColumn(int)));
+	connect (metaview->horizontalHeader (), SIGNAL (sectionPressed(int)), dataview, SLOT (selectColumn(int)));
+	connect (metaview, SIGNAL (selectionChanged (const QItemSelection&, const QItemSelection&)), this, SLOT (metaSelectionChanged (const QItemSelection&, const QItemSelection&)));
+	connect (dataview, SIGNAL (selectionChanged (const QItemSelection&, const QItemSelection&)), this, SLOT (dataSelectionChanged (const QItemSelection&, const QItemSelection&)));
 	
-	// this is to catch right-clicks on the top header
-	connect (varview, SIGNAL (headerRightClick (int, int)), this, SLOT (varviewHeaderRightClicked (int, int)));
+	// catch header context menu requests
+	connect (dataview, SIGNAL (contextMenuRequest(int,int)), this, SLOT (dataHeaderContextMenu(int,int)));
+	connect (metaview, SIGNAL (contextMenuRequest(int,int)), this, SLOT (metaHeaderContextMenu(int,int)));
 	
 	// which will be reacted upon by the following popup-menu:
-	top_header_menu = new Q3PopupMenu (this);
-	top_header_menu->insertItem (i18n ("Insert new variable left"), this, SLOT (insertColumnLeft ()), 0, HEADER_MENU_ID_ADD_COL_LEFT);
-	top_header_menu->insertItem (i18n ("Insert new variable right"), this, SLOT (insertColumnRight ()), 0, HEADER_MENU_ID_ADD_COL_RIGHT);
-	top_header_menu->insertItem (i18n ("Delete this variable"), this, SLOT (requestDeleteColumn ()), 0, HEADER_MENU_ID_DEL_COL);
+	top_header_menu = new QMenu (this);
+	action_insert_col_left = top_header_menu->addAction (QString (), this, SLOT (insertColumn()));
+	action_insert_col_right = top_header_menu->addAction (QString (), this, SLOT (insertColumn()));
+	action_delete_col = top_header_menu->addAction (QString (), this, SLOT (deleteColumn()));
 	
-	// and the same for the left header
-	connect (dataview, SIGNAL (headerRightClick (int, int)), this, SLOT (dataviewHeaderRightClicked (int, int)));
-	left_header_menu = new Q3PopupMenu (this);
-	left_header_menu->insertItem (i18n ("Insert new case above"), this, SLOT (insertRowAbove ()), 0, HEADER_MENU_ID_ADD_ROW_ABOVE);
-	left_header_menu->insertItem (i18n ("Insert new case below"), this, SLOT (insertRowBelow ()), 0, HEADER_MENU_ID_ADD_ROW_BELOW);
-	left_header_menu->insertItem (QString::null, this, SLOT (deleteRow ()), 0, HEADER_MENU_ID_DEL_ROW);
-	left_header_menu->insertItem (QString::null, this, SLOT (deleteRows ()), 0, HEADER_MENU_ID_DEL_ROWS);
+	left_header_menu = new QMenu (this);
+	action_insert_row_above = left_header_menu->addAction (QString (), this, SLOT (insertRow()));
+	action_insert_row_below = left_header_menu->addAction (QString (), this, SLOT (insertRow()));
+	action_delete_row = left_header_menu->addAction (QString (), this, SLOT (deleteRow()));
+	action_delete_rows = left_header_menu->addAction (QString (), this, SLOT (deleteSelectedRows()));
 
 	setFocusPolicy (Qt::StrongFocus);
 }
@@ -116,220 +87,170 @@
 TwinTable::~TwinTable() {
 	RK_TRACE (EDITOR);
 
-	delete top_header_menu;
-	delete left_header_menu;
-	
-/*	for (int i=0; i < numTrueCols (); ++i) {
-		RObject *object = getColObject (i);
-		if (object) object->setObjectOpened (this, false);
-		else RK_ASSERT (false);
-	} */
+// TODO: are the models auto-destructed?
 }
 
-void TwinTable::scrolled (int x, int) {
+void TwinTable::initTable (RKVarEditDataFrameModel* model) {
 	RK_TRACE (EDITOR);
 
-	disconnect (varview, SIGNAL (contentsMoving (int, int)), this, SLOT (autoScrolled (int, int)));
-	varview->setContentsPos (x, varview->contentsY ());
-	connect (varview, SIGNAL (contentsMoving (int, int)), this, SLOT (autoScrolled (int, int)));
+	datamodel = model;
+	dataview->setModel (model);
+	metaview->setModel (model->getMetaModel ());
+
+	metaview->setMinimumHeight (metaview->horizontalHeader ()->height ());
+	metaview->setMaximumHeight (metaview->rowHeight (0) * 5 + metaview->horizontalHeader ()->height () + 5);
 }
 
-void TwinTable::autoScrolled (int x, int) {
+// TODO: handle situation when several entire cols are selected!
+void TwinTable::metaHeaderContextMenu (int row, int col) {
 	RK_TRACE (EDITOR);
 
-	disconnect (dataview, SIGNAL (contentsMoving (int, int)), this, SLOT (scrolled (int, int)));
-	dataview->setContentsPos (x, dataview->contentsY ());
-	connect (dataview, SIGNAL (contentsMoving (int, int)), this, SLOT (scrolled (int, int)));
-}
+	if (col >= 0) {
+		RK_ASSERT (row == -1);
+		RK_ASSERT (col <= datamodel->trueCols ());
 
-void TwinTable::deleteColumn (int column) {
-	RK_TRACE (EDITOR);
+		action_insert_col_left->setVisible (true);
+		action_insert_col_left->setText (i18n ("Insert new variable left"));	// TODO: show name
+		action_insert_col_left->setData (col);
+		action_insert_col_right->setVisible (col < datamodel->trueCols ());
+		action_insert_col_right->setText (i18n ("Insert new variable right"));	// TODO: show name
+		action_insert_col_right->setData (col+1);
+		action_delete_col->setVisible (col < datamodel->trueCols ());
+		action_delete_col->setText (i18n ("Delete this variable"));	// TODO: show name
+		action_delete_col->setData (col);
 
-	flushEdit ();
-	if ((column >= 0) && (column < numTrueCols ())) {
-		varview->removeColumn (column);
-		dataview->removeColumn (column);
-		varview->updateContents ();
-		dataview->updateContents ();
+		// TODO: should be passed as a parameter, instead
+		top_header_menu->popup (metaview->mouse_at);
 	}
 }
 
-void TwinTable::insertNewColumn (int where) {
+void TwinTable::dataHeaderContextMenu (int row, int col) {
 	RK_TRACE (EDITOR);
 
-	flushEdit ();
-	if ((where < 0) || (where > varview->numCols ())) {
-		where = varview->numCols ();
-	}
+	RK_ASSERT (col < 0);
+	if (row >= 0) {
+		RK_ASSERT (row <= datamodel->trueRows ());
 
-	varview->insertColumns (where);
-	dataview->insertColumns (where);
+		action_insert_row_above->setVisible (true);
+		action_insert_row_above->setText (i18n ("Insert new case above (at %1)", col + 1));
+		action_insert_row_above->setData (col);
+		action_insert_row_below->setVisible (row < datamodel->trueRows ());
+		action_insert_row_above->setText (i18n ("Insert new case below (at %1)", col + 2));
+		action_insert_row_below->setData (col + 1);
 
-	if (where >= varview->numTrueCols ()) {		// the new addition was acutally not the new trailing row, but the one to the left - for all practical purposes
-		where = varview->numTrueCols () - 1;
+		QItemSelectionRange sel = dataview->getSelectionBoundaries ();
+		if (sel.isValid ()) {
+			int top = sel.top ();
+			int bottom = sel.bottom ();
+			if (bottom >= datamodel->trueRows ()) bottom = datamodel->trueRows () - 1;
+			if (top > bottom) top = bottom;
+
+			action_delete_rows->setVisible (true);
+			action_delete_rows->setText (i18n ("Delete marked rows (%1-%2)", (top+1), (bottom+1)));
+		} else {
+			action_delete_rows->setVisible (false);
+		}
+
+		action_delete_row->setVisible (row < datamodel->trueRows ());
+		action_delete_row->setText (i18n ("Delete this row (%1)", (row+1)));
+		action_delete_row->setData (row);
+
+		left_header_menu->popup (dataview->mouse_at);
 	}
-	emit (addedColumn (where));
 }
 
-void TwinTable::insertNewRow (int where, TwinTableMember *table) {
+void TwinTable::deleteColumn () {
 	RK_TRACE (EDITOR);
 
-	flushEdit ();
-	if (!table) table = dataview;
-	
-	if ((where < 0) || (where > table->numTrueRows ())) {
-		where = table->numRows ();
-	}
-	
-	if (table == dataview) {
-		emit (dataAddingRow (where));
-	} else if (table == varview) {
+	QObject *s = sender ();
+	int col;
+	if (s == action_delete_col) col = action_delete_col->data ().toInt ();
+	else {
 		RK_ASSERT (false);
+		return;
 	}
 
-	table->insertRows (where);
+	flushEdit ();
+
+	datamodel->removeColumns (col, 1);
 }
 
-void TwinTable::deleteRow (int where, TwinTableMember *table) {
+void TwinTable::insertColumn () {
 	RK_TRACE (EDITOR);
 
-	flushEdit ();
-	if (!table) table = dataview;
-	
-	if ((where < 0) || (where > table->numTrueRows ())) {
-		where = table->numRows () - 1;
-	}
-	
-	if (table == dataview) {
-		emit (dataRemovingRow (where));
-	} else if (table == varview) {
+	QObject *s = sender ();
+	int where;
+	if (s == action_insert_col_left) where = action_insert_col_left->data ().toInt ();
+	else if (s == action_insert_col_right) where = action_insert_col_right->data ().toInt ();
+	else {
 		RK_ASSERT (false);
+		return;
 	}
 
-	table->removeRow (where);
-}
+	flushEdit ();
 
-void TwinTable::headerClicked (int col) {
-	RK_TRACE (EDITOR);
-
-	Q3TableSelection selection;
-	selection.init (0, col);
-	selection.expandTo (dataview->numTrueRows (), col);
-
-	dataview->addSelection (selection);
+	datamodel->insertColumns (where, 1);
 }
 
-// TODO: handle situation when several entire rows/cols are selected!
-void TwinTable::varviewHeaderRightClicked (int, int col) {
+void TwinTable::deleteRow () {
 	RK_TRACE (EDITOR);
 
-	if (col >= 0) {
-		header_pos = col;
-		if (col < varview->numTrueCols ()) {
-			top_header_menu->setItemVisible (HEADER_MENU_ID_ADD_COL_LEFT, true);
-			top_header_menu->setItemVisible (HEADER_MENU_ID_ADD_COL_RIGHT, true);
-			top_header_menu->setItemVisible (HEADER_MENU_ID_DEL_COL, true);
-			top_header_menu->popup (varview->mouse_at);
-		} else if (col == varview->numTrueCols ()) {		// trailing col
-			top_header_menu->setItemVisible (HEADER_MENU_ID_ADD_COL_LEFT, true);
-			top_header_menu->setItemVisible (HEADER_MENU_ID_ADD_COL_RIGHT, false);
-			top_header_menu->setItemVisible (HEADER_MENU_ID_DEL_COL, false);
-			top_header_menu->popup (varview->mouse_at);
-		} else {
-			RK_ASSERT (false);
-		}
+	QObject *s = sender ();
+	int where;
+	if (s == action_delete_row) where = action_delete_row->data ().toInt ();
+	else {
+		RK_ASSERT (false);
+		return;
 	}
-}
 
-void TwinTable::dataviewHeaderRightClicked (int row, int col) {
-	RK_TRACE (EDITOR);
+	flushEdit ();
 
-	RK_ASSERT (col < 0);
-	if (row >= 0) {
-		header_pos = row;
-		left_header_menu->setItemVisible (HEADER_MENU_ID_ADD_ROW_ABOVE, true);
-		int top, bottom, left, right;
-		dataview->getSelectionBoundaries (&top, &left, &bottom, &right);
-		if (top >= 0 && bottom <= dataview->numTrueRows () && top != bottom) {
-			left_header_menu->setItemVisible (HEADER_MENU_ID_DEL_ROWS, true);
-			left_header_menu->changeItem (HEADER_MENU_ID_DEL_ROWS, i18n ("Delete marked rows (%1-%2)", (top+1), (bottom+1)));
-		} else {
-			left_header_menu->setItemVisible (HEADER_MENU_ID_DEL_ROWS, false);
-		}
-		if (row < dataview->numTrueRows ()) {
-			left_header_menu->setItemVisible (HEADER_MENU_ID_ADD_ROW_BELOW, true);
-			left_header_menu->setItemVisible (HEADER_MENU_ID_DEL_ROW, true);
-			left_header_menu->changeItem (HEADER_MENU_ID_DEL_ROW, i18n ("Delete this row (%1)", (row+1)));
-			left_header_menu->popup (dataview->mouse_at);
-		} else if (row == dataview->numTrueRows ()) {		// trailing row
-			left_header_menu->setItemVisible (HEADER_MENU_ID_ADD_ROW_BELOW, false);
-			left_header_menu->setItemVisible (HEADER_MENU_ID_DEL_ROW, false);
-			left_header_menu->popup (dataview->mouse_at);
-		} else {
-			RK_ASSERT (false);
-		}
-	}
+	datamodel->removeRows (where, 1);
 }
 
-void TwinTable::viewClearSelection () {
+void TwinTable::deleteSelectedRows () {
 	RK_TRACE (EDITOR);
-	
-	disconnect (varview, SIGNAL (selectionChanged ()), this, SLOT (dataClearSelection ()));
-	varview->clearSelection ();
-	connect (varview, SIGNAL (selectionChanged ()), this, SLOT (dataClearSelection ()));
-}
 
-void TwinTable::dataClearSelection () {
-	RK_TRACE (EDITOR);
+	QItemSelectionRange sel = dataview->getSelectionBoundaries ();
+	if (sel.isValid ()) {
+		int top = sel.top ();
+		int bottom = sel.bottom ();
+		if (bottom >= datamodel->trueRows ()) bottom = datamodel->trueRows () - 1;
+		if (top > bottom) top = bottom;
 
-	disconnect (dataview, SIGNAL (selectionChanged ()), this, SLOT (viewClearSelection ()));
-	dataview->clearSelection ();
-	connect (dataview, SIGNAL (selectionChanged ()), this, SLOT (viewClearSelection ()));
+		datamodel->removeRows (top, bottom - top + 1);
+	} else {
+		RK_ASSERT (false);
+	}
 }
 
-QString TwinTable::getSelectedText () {
+void TwinTable::insertRow () {
 	RK_TRACE (EDITOR);
-	return (activeTable ()->getSelectionText ());
-}
 
-void TwinTable::insertColumnRight () {
-	RK_TRACE (EDITOR);
-	insertNewColumn (header_pos+1);
-}
+	QObject *s = sender ();
+	int where;
+	if (s == action_insert_row_above) where = action_insert_row_above->data ().toInt ();
+	else if (s == action_insert_row_below) where = action_insert_row_below->data ().toInt ();
+	else {
+		RK_ASSERT (false);
+		return;
+	}
 
-void TwinTable::insertColumnLeft () {
-	RK_TRACE (EDITOR);
-	insertNewColumn (header_pos);
-}
+	flushEdit ();
 
-void TwinTable::requestDeleteColumn () {
-	RK_TRACE (EDITOR);
-	emit (deleteColumnRequest (header_pos));
+	datamodel->insertRows (where, 1);
 }
 
-void TwinTable::insertRowBelow () {
+void TwinTable::metaSelectionChanged (const QItemSelection& selected, const QItemSelection&) {
 	RK_TRACE (EDITOR);
-	insertNewRow (header_pos+1);
-}
 
-void TwinTable::insertRowAbove () {
-	RK_TRACE (EDITOR);
-	insertNewRow (header_pos);
+	if (!selected.isEmpty ()) dataview->clearSelection ();
 }
 
-void TwinTable::deleteRow () {
+void TwinTable::dataSelectionChanged (const QItemSelection& selected, const QItemSelection&) {
 	RK_TRACE (EDITOR);
-	deleteRow (header_pos);
-}
 
-void TwinTable::deleteRows () {
-	RK_TRACE (EDITOR);
-// TODO: this is inefficient. Remove all rows at once
-	int top, bottom, left, right;
-	dataview->getSelectionBoundaries (&top, &left, &bottom, &right);
-	for (; bottom >= top; --bottom) {
-		deleteRow (bottom);
-	}
+	if (!selected.isEmpty ()) metaview->clearSelection ();
 }
 
 void TwinTable::copy () {
@@ -341,7 +262,7 @@
 	table->copy ();
 }
 
-void TwinTable::paste (const QString& pasted, RKEditor::PasteMode paste_mode) {
+void TwinTable::paste (RKEditor::PasteMode paste_mode) {
 	RK_TRACE (EDITOR);
 
 	flushEdit ();
@@ -349,77 +270,14 @@
 	TwinTableMember *table = activeTable ();
 	if (!table) return;
 
-	int top_row, left_col, bottom_row, right_col;
-	table->getSelectionBoundaries (&top_row, &left_col, &bottom_row, &right_col);
-	if (paste_mode == RKEditor::PasteToSelection) {
-		// ok, we got our values
-	} else if (paste_mode == RKEditor::PasteToTable) {
-		bottom_row = table->numTrueRows () - 1;
-		right_col = table->numTrueCols () - 1;
-		if (right_col < left_col) return;			// may happen, if the current cell is in the trailing cols/rows
-		if (bottom_row < top_row) return;
-	} else if (paste_mode == RKEditor::PasteEverywhere) {
-		bottom_row = INT_MAX;
-		right_col = INT_MAX;
-	}
-	if (table == varview) {			// do not allow new rows in the varview
-		if (bottom_row >= varview->numTrueRows ()) bottom_row = varview->numTrueRows () - 1;
-	}
-
-	Q3ValueList<RKVariable*> col_list;
-
-	int row = top_row;
-	int col = left_col;
-	int content_offset = 0;
-	int content_length = pasted.length ();
-	do {
-		// first add new rows/cols if needed. Range check is done below, and on first iteration, we're always inside the valid range
-		if (row >= table->numTrueRows ()) insertNewRow (-1, table);
-		if (col >= table->numTrueCols ()) insertNewColumn ();
-
-		if (!col_list.contains (getColObject (col))) {		// avoid syncing while doing the paste
-			col_list.append (getColObject (col));
-			getColObject (col)->setSyncing (false);
-		}
-
-		int next_tab = pasted.find ('\t', content_offset);
-		if (next_tab < 0) next_tab = content_length;
-		int next_delim = next_tab;
-		int next_line = pasted.find ('\n', content_offset);
-		if (next_line < 0) next_line = content_length;
-		if (next_line < next_tab) next_delim = next_line;
-
-		table->setText (row, col, pasted.mid (content_offset, next_delim - content_offset));
-
-		if (next_delim == next_tab) {						// move to next row/column
-			++col;
-		} else if (next_delim == next_line) {
-			col = left_col;
-			++row;
-		}
-
-		if (col > right_col) {										// check boundaries for next iteration
-			next_delim = next_line;
-			col = left_col;
-			++row;
-		}
-		if (row > bottom_row) break;
-
-		content_offset = next_delim + 1;
-	} while (content_offset < content_length);
-
-	// now do the syncing
-	for (Q3ValueList<RKVariable*>::ConstIterator it = col_list.constBegin (); it != col_list.constEnd (); ++it) {
-		(*it)->syncDataToR ();
-		(*it)->setSyncing (true);
-	}
+	table->paste (paste_mode);
 }
 
 TwinTableMember *TwinTable::activeTable () {
 	RK_TRACE (EDITOR);
 
-	if (varview->hasFocus ()) {
-		return varview;
+	if (metaview->hasFocus ()) {
+		return metaview;
 	} else if (dataview->hasFocus ()) {
 		return dataview;
 	} else {
@@ -431,75 +289,17 @@
 	RK_TRACE (EDITOR);
 
 	TwinTableMember *table = activeTable ();
- 	if (!table) return;
+	if (!table) return;
 
 	table->blankSelected ();
 }
 
-void TwinTable::setRow (TwinTableMember* table, int row, int start_col, int end_col, char **data) {
-	RK_TRACE (EDITOR);
-
-	flushEdit ();
-	while (numTrueCols () <= end_col) {
-		insertNewColumn ();
-	}
-	
-	int i=0;
-	for (int col=start_col; col <= end_col; ++col) {
-		table->setText (row, col, data[i++]);
-	}
-}
-
-void TwinTable::setColumn (TwinTableMember* table, int col, int start_row, int end_row, char **data) {
-	RK_TRACE (EDITOR);
-
-	flushEdit ();
-	while (table->numTrueRows () <= end_row) {
-		insertNewRow (table->numTrueRows (), table);
-	}
-	
-	int i=0;
-	for (int row=start_row; row <= end_row; ++row) {
-		table->setText (row, col, data[i++]);
-	}
-}
-
 void TwinTable::flushEdit () {
 	RK_TRACE (EDITOR);
 
 	// flush pending edit operations
-	varview->stopEditing ();
+	metaview->stopEditing ();
 	dataview->stopEditing ();
 }
 
-int TwinTable::numTrueCols () {
-//	RK_TRACE (EDITOR);
-	return varview->numTrueCols ();
-}
-
-void TwinTable::setColObject (long int column, RKVariable *object) {
-	RK_TRACE (EDITOR);
-	if (object) {
-		col_map.replace (column, object);		// will insert, if not already in dict
-	} else {
-		col_map.remove (column);
-	}
-}
-
-RKVariable *TwinTable::getColObject (long int col) {
-	// do not trace. called very often
-	//RK_TRACE (EDITOR);
-	return col_map.find (col);
-}
-
-long int TwinTable::getObjectCol (RObject *object) {
-	RK_TRACE (EDITOR);
-	for (Q3IntDictIterator<RKVariable> it (col_map); it.current (); ++it) {
-		if (it.current () == object) return it.currentKey ();
-	}
-	
-	RK_ASSERT (false);
-	return -1;
-}
-
 #include "twintable.moc"

Modified: branches/KDE4_port/rkward/dataeditor/twintable.h
===================================================================
--- branches/KDE4_port/rkward/dataeditor/twintable.h	2007-11-08 15:07:49 UTC (rev 2189)
+++ branches/KDE4_port/rkward/dataeditor/twintable.h	2007-11-08 23:23:14 UTC (rev 2190)
@@ -2,7 +2,7 @@
                           twintable.h  -  description
                              -------------------
     begin                : Tue Oct 29 2002
-    copyright            : (C) 2002, 2006 by Thomas Friedrichsmeier
+    copyright            : (C) 2002, 2006, 2007 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -20,29 +20,12 @@
 
 #include "rkeditor.h"
 
-#include <qvariant.h>
 #include <qstring.h>
-#include <q3intdict.h>
-//Added by qt3to4:
-#include <Q3GridLayout>
-#include <Q3HBoxLayout>
-#include <Q3VBoxLayout>
-#include <Q3PopupMenu>
+#include <QItemSelection>
 
-class Q3VBoxLayout;
-class Q3HBoxLayout;
-class Q3GridLayout;
-class QSplitter;
 class TwinTableMember;
-class TwinTableDataMember;
-class TwinTableMetaMember;
-class TableColumn;
-class Q3PopupMenu;
-class Q3Table;
-class RKDrag;
-class RObject;
-struct RObject::ChangeSet;
-class RKVariable;
+class QMenu;
+class RKVarEditDataFrameModel;
 
 /**
   *@author Thomas Friedrichsmeier
@@ -51,16 +34,10 @@
 class TwinTable : public RKEditor {
 	Q_OBJECT
 public: 
-	TwinTable(QWidget *parent=0);
-	~TwinTable();
-/** Inserts a new column at the given position (or at the end for -1) */
-	void insertNewColumn (int where=-1);
-/** Inserts a new row at the given position (or at the end for -1) in the given table. Don't try to do this in the varview, yet! */
-	void insertNewRow (int where=-1, TwinTableMember *table=0);
-/** Inserts the row at the given position (or at the end for -1) in the given table. Don't try to do this in the varview, yet! */
-	void deleteRow (int where, TwinTableMember *table=0);
-/** Pastes content to the current table */
-	void paste (const QString& pasted, RKEditor::PasteMode paste_mode);
+	TwinTable (QWidget *parent=0);
+	~TwinTable ();
+/** Pastes clipboard content to the current table */
+	void paste (RKEditor::PasteMode paste_mode);
 /** Copy selection in the current table to clipboard */
 	void copy ();
 /** Same as above, but flips the data (i.e. row <-> cols) */
@@ -72,67 +49,48 @@
 /** Flushes pending edit-operations */
 	void flushEdit ();
 
-/** Returns the number of (true) columns in the tables. See TwinTableMember::numTrueCols () */
-	int numTrueCols ();
+	void initTable (RKVarEditDataFrameModel* model);
 	
-	TwinTableMetaMember* varview;
-	TwinTableDataMember* dataview;
-/** get the object at the given column (0 if there is no object for the column) */
-	RKVariable *getColObject (long int col);
-signals:
-	void deleteColumnRequest (int);
-/** emitted so the RKEditorDataFrame can add a corresponding object */
-	void addedColumn (int);
-/** emitted so the RKEditorDataFrame can update the R workspace accordingly. Only signals row additions in the data table, not the meta table */
-	void dataAddingRow (int);
-/** emitted so the RKEditorDataFrame can update the R workspace accordingly. Only signals row deletions in the data table, not the meta table */
-	void dataRemovingRow (int);
+	RKVarEditDataFrameModel* datamodel;
 public slots:
-	void dataviewHeaderRightClicked (int row, int col);
-	void varviewHeaderRightClicked (int row, int col);
+	void dataHeaderContextMenu (int row, int col);
+	void metaHeaderContextMenu (int row, int col);
+/*
 	void headerClicked (int col);
-	void viewClearSelection ();
-	void dataClearSelection ();
+	void headerPressed (int col); */
+	void metaSelectionChanged (const QItemSelection& selected, const QItemSelection& deselected);
+	void dataSelectionChanged (const QItemSelection& selected, const QItemSelection& deselected);
 private:
 /** PopupMenu shown when top header is right-clicked */
-	Q3PopupMenu *top_header_menu;
+	QMenu *top_header_menu;
 /** PopupMenu shown when top header is right-clicked */
-	Q3PopupMenu *left_header_menu;
-/** position (row or col) the header_menu is operating on */
-	int header_pos;
-
-	typedef Q3IntDict<RKVariable> ColMap;
-	ColMap col_map;
+	QMenu *left_header_menu;
 protected:	
-/** set a row of cells, expanding the table if necessary. Assumes you provide the correct amount of data! */
-	void setRow (TwinTableMember* table, int row, int start_col, int end_col, char **data);
-/** set a column of cells, expanding the table if necessary. Assumes you provide the correct amount of data! */
-	void setColumn (TwinTableMember* table, int col, int start_row, int end_row, char **data);
-/** deletes the given column. To be called only from RKEditorDataFrame, in order to take care of object-removal! */
-	void deleteColumn (int column);
 /** Returns the active Table (of the two members), 0 if no table active */
 	TwinTableMember *activeTable ();
 
-	long int getObjectCol (RObject *object);
-/// if object == 0, removes the column from the list
-	void setColObject (long int column, RKVariable *object);
+	TwinTableMember* metaview;
+	TwinTableMember* dataview;
+
+	QAction* action_insert_col_left;
+	QAction* action_insert_col_right;
+	QAction* action_delete_col;
+
+	QAction* action_insert_row_above;
+	QAction* action_insert_row_below;
+	QAction* action_delete_row;
+	QAction* action_delete_rows;
 private slots:
-	void scrolled (int x, int y);
-	void autoScrolled (int x, int y);
-/** inserts a new column to the right of the current header_pos */
-	void insertColumnRight ();
-/** inserts a new column to the left of the current header_pos */
-	void insertColumnLeft ();
-/** inserts a new row below the current header_pos */
-	void insertRowBelow ();
-/** inserts a new row above the current header_pos */
-	void insertRowAbove ();
-/** deletes the current row (in the data view) */
+/** inserts a new column (NOTE the action connected to this signal carries the info, where the column is to be inserted) */
+	void insertColumn ();
+/** inserts a new row in the dataview (NOTE the action connected to this signal carries the info, where the column is to be inserted) */
+	void insertRow ();
+/** deletes the current row (in the dataview) */
 	void deleteRow ();
-/** deletes all marked rows (in the data view) */
-	void deleteRows ();
-/** deletes the column at the current header_pos. Actually it does not really delete the column, but requests object-removal from the RKEditorDataFrame. That will take care of calling deleteColumn (int) */
-	void requestDeleteColumn ();
+/** deletes all marked rows (in the dataview) */
+	void deleteSelectedRows ();
+/** deletes the column at the current header_pos. Actually it does not really delete the column, but requests object-removal from the model, which will pass the request to RKModifcationTracker */
+	void deleteColumn ();
 };
 
 #endif

Modified: branches/KDE4_port/rkward/dataeditor/twintabledatamember.cpp
===================================================================
--- branches/KDE4_port/rkward/dataeditor/twintabledatamember.cpp	2007-11-08 15:07:49 UTC (rev 2189)
+++ branches/KDE4_port/rkward/dataeditor/twintabledatamember.cpp	2007-11-08 23:23:14 UTC (rev 2190)
@@ -27,6 +27,9 @@
 
 #include "../debug.h"
 
+#warning TODO remove
+#if 0
+
 TwinTableDataMember::TwinTableDataMember (QWidget *parent, TwinTable *table) : TwinTableMember (parent, table, 1, 1) {
 }
 
@@ -150,3 +153,4 @@
 }
 
 #include "twintabledatamember.moc"
+#endif
\ No newline at end of file

Modified: branches/KDE4_port/rkward/dataeditor/twintabledatamember.h
===================================================================
--- branches/KDE4_port/rkward/dataeditor/twintabledatamember.h	2007-11-08 15:07:49 UTC (rev 2189)
+++ branches/KDE4_port/rkward/dataeditor/twintabledatamember.h	2007-11-08 23:23:14 UTC (rev 2190)
@@ -18,7 +18,7 @@
 #define TWINTABLEDATAMEMBER_H
 
 #include "twintablemember.h"
-
+#if 0
 /**
 The TwinTableMember responsible for storing the data (i.e. the bottom half of the TwinTable). See TwinTable and TwinTableMember.
 
@@ -49,5 +49,5 @@
 /** reimplemented form TwinTableDataMember to use information from RKVariable for proper treatment of values */
 	QString rText (int row, int col) const;
 };
-
 #endif
+#endif

Modified: branches/KDE4_port/rkward/dataeditor/twintablemember.cpp
===================================================================
--- branches/KDE4_port/rkward/dataeditor/twintablemember.cpp	2007-11-08 15:07:49 UTC (rev 2189)
+++ branches/KDE4_port/rkward/dataeditor/twintablemember.cpp	2007-11-08 23:23:14 UTC (rev 2190)
@@ -2,7 +2,7 @@
                           twintablemember.cpp  -  description
                              -------------------
     begin                : Tue Oct 29 2002
-    copyright            : (C) 2002, 2006 by Thomas Friedrichsmeier
+    copyright            : (C) 2002, 2006, 2007 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -17,108 +17,47 @@
 
 #include "twintablemember.h"
 
-#include <qevent.h>
-#include <qpainter.h>
-#include <qstyle.h>
-#include <qapplication.h>
-#include <qclipboard.h>
-//Added by qt3to4:
-#include <QMouseEvent>
 #include <QKeyEvent>
-#include <Q3MemArray>
 
 #include "celleditor.h"
 #include "twintable.h"
+#include "rktextmatrix.h"
+#include "rkvareditmodel.h"
+
 #include "../debug.h"
 
-TwinTableMember::TwinTableMember (QWidget *parent, TwinTable *table, int trailing_rows, int trailing_cols) : Q3Table (parent){
+TwinTableMember::TwinTableMember (QWidget *parent, TwinTable *table) : QTableView (parent){
+	RK_TRACE (EDITOR);
+
 	twin = 0;
 	TwinTableMember::table = table;
-	setRowMovingEnabled (false);
-	setVScrollBarMode (Q3ScrollView::AlwaysOn);
-	horizontalHeader()->installEventFilter (this);
-	verticalHeader()->installEventFilter (this);
-	setSelectionMode (Q3Table::Single);
+	setVerticalScrollBarPolicy (Qt::ScrollBarAlwaysOn);
+	setSelectionMode (QAbstractItemView::ContiguousSelection);
+	setContextMenuPolicy (Qt::CustomContextMenu);
+	connect (this, SIGNAL (customContextMenuRequested (const QPoint&)), this, SLOT (headerContextMenuRequested (const QPoint&)));
 	
-	TwinTableMember::trailing_cols = trailing_cols;
-	TwinTableMember::trailing_rows = trailing_rows;
-	
 	tted = 0;
+#warning tted and changing width currently unused, but likey will be used.
 	changing_width = false;
+	changing_scroll = false;
 
 	connect (this, SIGNAL (currentChanged (int, int)), this, SLOT (currentCellChanged (int, int)));
 }
 
 TwinTableMember::~TwinTableMember(){
+	RK_TRACE (EDITOR);
 }
 
-int TwinTableMember::numTrueCols () const {
-	return numCols () - trailing_cols;
-}
+void TwinTableMember::setRKModel (RKVarEditModelBase* model) {
+	RK_TRACE (EDITOR);
+	mymodel = model; setModel (model);
+};
 
-int TwinTableMember::numTrueRows () const {
-	return Q3Table::numRows () - trailing_rows;
-}
-
 void TwinTableMember::setTwin (TwinTableMember * new_twin) {
+	RK_TRACE (EDITOR);
 	twin = new_twin;
 }
 
-void TwinTableMember::columnWidthChanged (int col) {
-	// does all repainting and stuff ...
-	Q3Table::columnWidthChanged (col);
-
-	// syncs the twin
-	if (twin) {
-		if (!changing_width) {
-			changing_width = true;
-			twin->setColumnWidth (col, columnWidth (col));
-		}
-		changing_width = false;
-	}
-}
-
-bool TwinTableMember::eventFilter (QObject *object, QEvent *event) {
-	// filter out right mouse button events of the varview-header
-	if (event && (event->type () == QEvent::MouseButtonPress)) {
-		QMouseEvent  *mouseEvent = (QMouseEvent *) event;
-		if (mouseEvent && (mouseEvent->button () == Qt::RightButton)) {
-			mouse_at = mouseEvent->globalPos ();
-			if (object == horizontalHeader ()) {
-				emit headerRightClick (-1, horizontalHeader ()->sectionAt (contentsX () + mouseEvent->x ()));
-				return (true); // got it
-			}
-			if (object == verticalHeader ()) {
-				emit headerRightClick (verticalHeader ()->sectionAt (contentsY () + mouseEvent->y ()), -1);
-				return (true); // got it
-			}
-		}
-		setFocus ();
-	}
-
-    // default processing
-    return (Q3Table::eventFilter (object, event));
-}
-
-// virtual
-QString TwinTableMember::rText (int row, int col) const {
-	return (RObject::rQuote (text (row, col)));
-}
-
-void TwinTableMember::removeRows (const Q3MemArray<int> &) {
-	RK_ASSERT (false);
-}
-
-void TwinTableMember::swapRows (int, int, bool) {
-}
-
-void TwinTableMember::swapCells (int, int, int, int) {
-	RK_ASSERT (false);
-}
-
-void TwinTableMember::swapColumns (int, int, bool) {
-}
-
 void TwinTableMember::editorLostFocus () {
 	RK_TRACE (EDITOR);
 	stopEditing ();
@@ -126,35 +65,20 @@
 
 void TwinTableMember::stopEditing () {
 	RK_TRACE (EDITOR);
-	if (tted) endEdit (currEditRow (), currEditCol (), true, false);
+#warning todo
+//	if (tted) endEdit (currEditRow (), currEditCol (), true, false);
 	RK_ASSERT (!tted);
 }
 
-QWidget *TwinTableMember::cellWidget (int row, int col) const {
-	if (tted && (currEditRow () == row) && (currEditCol () == col)) return tted;
-	return 0;
-}
-
-void TwinTableMember::currentCellChanged (int row, int col) {
-	RK_TRACE (EDITOR);
-	if ((row == currEditRow ()) && (col == currEditCol ())) return;
-	if (tted) stopEditing ();
-
-/*	if (numSelections ()) {
-		QTableSelection sel = selection (currentSelection ());
-		if (sel.bottomRow () != sel.topRow ()) return;
-		if (sel.leftCol () != sel.rightCol ()) return;
-	}
-
-	editCell (row, col); */
-}
-
+#if 0
 void TwinTableMember::endEdit (int row, int col, bool, bool) {
 	RK_TRACE (EDITOR);
 	if (tted) setCellContentFromEditor (row, col);
 	setEditMode (NotEditing, -1, -1);
 }
+#endif
 
+#if 0
 void TwinTableMember::setCellContentFromEditor (int row, int col) {
 	RK_TRACE (EDITOR);
 	RK_ASSERT (tted);
@@ -173,150 +97,80 @@
 	
 	viewport ()->setFocus ();
 }
+#endif
 
 void TwinTableMember::copy () {
 	RK_TRACE (EDITOR);
 
-	QString text = getSelectionText ();
-	QMimeData* data = new QMimeData ();
-	data->setText (text);
-	data->setData ("text/tab-separated-values", text.toLocal8Bit ());
-	QApplication::clipboard()->setMimeData (data);
+	QItemSelectionRange range = getSelectionBoundaries ();
+	if (range.isValid ()) {
+		RKTextMatrix mat = mymodel->getTextMatrix (range);
+		mat.copyToClipboard ();
+	}
 }
 
-QString TwinTableMember::getSelectionText () {
+void TwinTableMember::blankSelected () {
 	RK_TRACE (EDITOR);
 
-	int top_row, left_col, bottom_row, right_col;
-	getSelectionBoundaries (&top_row, &left_col, &bottom_row, &right_col);
-	return (getRangeText (top_row, left_col, bottom_row, right_col));
+	QItemSelectionRange range = getSelectionBoundaries ();
+	if (range.isValid ()) mymodel->blankRange (range);
 }
 
-QString TwinTableMember::getRangeText (int top_row, int left_col, int bottom_row, int right_col) {
+void TwinTableMember::paste (RKEditor::PasteMode mode) {
 	RK_TRACE (EDITOR);
 
-	QString data;
-	for (int row=top_row; row <= bottom_row; ++row) {
-		for (int col=left_col; col <= right_col; ++col) {
-			data.append (text (row, col));
-			if (col != right_col) {
-				data.append ("\t");
-			}
-		}
-		if (row != bottom_row) {
-			data.append ("\n");
-		}
-	}
-	return data;
+	RKTextMatrix pasted = RKTextMatrix::matrixFromClipboard ();
+	QItemSelectionRange range;
+	if (mode == RKEditor::PasteToSelection) {
+		range = getSelectionBoundaries ();
+	} else if (mode == RKEditor::PasteToTable) {
+		range = QItemSelectionRange (mymodel->index (0, 0), mymodel->index (mymodel->trueRows (), mymodel->trueCols ()));
+	} // else: range not set means not confined = PasteAnywhere
+	mymodel->setTextMatrix (currentIndex (), pasted, range);
 }
 
-void TwinTableMember::blankSelected () {
+QItemSelectionRange TwinTableMember::getSelectionBoundaries () {
 	RK_TRACE (EDITOR);
 
-	int top_row, left_col, bottom_row, right_col;
-	getSelectionBoundaries (&top_row, &left_col, &bottom_row, &right_col);
+	RK_ASSERT (selectionModel ());
+	QItemSelection sel = selectionModel ()->selection ();
+	if (sel.isEmpty ()){
+		QModelIndex current = currentIndex ();
+		if (!current.isValid ()) return (QItemSelectionRange ());
 
-	for (int row=top_row; row <= bottom_row; ++row) {
-		for (int col=left_col; col <= right_col; ++col) {
-			setText (row, col, QString::null);
-		}
+		return (QItemSelectionRange (currentIndex (), currentIndex ()));
+	} else {
+		RK_ASSERT (sel.size () == 1);
+		return (sel[0]);
 	}
 }
 
-void TwinTableMember::getSelectionBoundaries (int *top_row, int *left_col, int *bottom_row, int *right_col) {
+void TwinTableMember::keyPressEvent (QKeyEvent *e) {
 	RK_TRACE (EDITOR);
 
-	RK_ASSERT (top_row);
-	RK_ASSERT (bottom_row);
-	RK_ASSERT (left_col);
-	RK_ASSERT (right_col);
-
-	int selnum = -1;
-	if (currentSelection () >= 0) selnum = currentSelection ();
-	else if (numSelections () >= 1) selnum = 0;		// this is the one and only selection, as we only allow one single selection. Unfortunately, QTable does not regard a selection as current, if it was added programatically, instead of user-selected.
-	if (selnum >= 0) {
-		Q3TableSelection sel = selection (selnum);
-		*top_row = sel.topRow ();
-		*left_col = sel.leftCol ();
-		*bottom_row = sel.bottomRow ();
-		*right_col = sel.rightCol ();
+	if ((e->key () == Qt::Key_Delete) || (e->key () == Qt::Key_Backspace)) {
+		blankSelected ();
+		e->accept ();
 	} else {
-		// Nothing selected. Set current cell coordinates
-		*top_row = *bottom_row = currentRow ();
-		*left_col = *right_col = currentColumn ();
+		QTableView::keyPressEvent (e);
 	}
 }
 
-void TwinTableMember::paintCellInternal (QPainter *p, int row, int col, const QRect &cr, bool selected, const QColorGroup &cg, QBrush *brush_override, QPen *pen_override, const QString &text, int alignment) {
-	// no trace for paint operations
+void TwinTableMember::scrollContentsBy (int dx, int dy) {
+	RK_TRACE (EDITOR);
 
-	// draw background
-	QBrush brush = cg.brush (QColorGroup::Base);
-	if (!brush_override) {
-		if (selected) {
-			brush = cg.brush(QColorGroup::Highlight);
-			if ((row >= numTrueRows ()) || (col >= numTrueCols ())) {
-				brush = QBrush (QColor (127, 127, 255));
-			}
-		} else {
-			if ((row >= numTrueRows ()) || (col >= numTrueCols ())) {
-				brush = QBrush (Qt::gray);
-			}
-		}
-	} else {
-		brush = *brush_override;
-	}
-	p->fillRect(0, 0, cr.width(), cr.height(), brush);
-
-	// draw grid
-	QPen pen (p->pen ());
-	int gridColor = style ()->styleHint (QStyle::SH_Table_GridLineColor, 0, this);
-	if (gridColor != -1) {
-		const QPalette &pal = palette ();
-		if (cg != colorGroup () && cg != pal.disabled () && cg != pal.inactive ()) p->setPen (cg.mid ());
-		else p->setPen ((QRgb) gridColor);
-	} else {
-		p->setPen (cg.mid ());
-	}
-	int x2 = cr.width () - 1;
-	int y2 = cr.height () - 1;
-	p->drawLine (x2, 0, x2, y2);
-	p->drawLine (0, y2, x2, y2);
-	p->setPen (pen);
-
-	if (tted && (currEditRow () == row) && (currEditCol () == col)) {
-		tted->raise ();
-		return;
-	}
-
-	if (text.isNull ()) return;
-
-	if (!pen_override) {
-		if (selected) {
-			p->setPen (cg.highlightedText());
-		} else {
-			p->setPen (cg.text ());
-		}
-	} else {
-		p->setPen (*pen_override);
-	}
-
-	if (alignment == 1) {
-		p->drawText (2, 0, cr.width () - 4, cr.height (), Qt::AlignRight, text);
-	} else {
-		p->drawText (2, 0, cr.width () - 4, cr.height (), Qt::AlignLeft, text);
-	}
+	if (changing_scroll) return;
+	changing_scroll = true;
+	RK_ASSERT (twin);
+	twin->scrollContentsBy (dx, 0);
+	changing_scroll = false;
 }
 
-void TwinTableMember::keyPressEvent (QKeyEvent *e) {
+void TwinTableMember::headerContextMenuRequested (const QPoint& pos) {
 	RK_TRACE (EDITOR);
 
-	if ((e->key () == Qt::Key_Delete) || (e->key () == Qt::Key_Backspace)) {
-		blankSelected ();
-		e->accept ();
-	} else {
-		Q3Table::keyPressEvent (e);
-	}
+	mouse_at = pos;
+#warning TODO
 }
 
 #include "twintablemember.moc"

Modified: branches/KDE4_port/rkward/dataeditor/twintablemember.h
===================================================================
--- branches/KDE4_port/rkward/dataeditor/twintablemember.h	2007-11-08 15:07:49 UTC (rev 2189)
+++ branches/KDE4_port/rkward/dataeditor/twintablemember.h	2007-11-08 23:23:14 UTC (rev 2190)
@@ -2,7 +2,7 @@
                           twintablemember.h  -  description
                              -------------------
     begin                : Tue Oct 29 2002
-    copyright            : (C) 2002, 2006 by Thomas Friedrichsmeier
+    copyright            : (C) 2002, 2006, 2007 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -18,110 +18,73 @@
 #ifndef TWINTABLEMEMBER_H
 #define TWINTABLEMEMBER_H
 
-#include <q3table.h>
+#include <QTableView>
+#include <QItemSelectionRange>
 #include <qpoint.h>
 //Added by qt3to4:
 #include <QEvent>
-#include <Q3MemArray>
 #include <QMouseEvent>
 #include <QKeyEvent>
 
-#define LABEL_ROW 0
-#define TYPE_ROW 1
-#define LEVELS_ROW 2
-#define FORMAT_ROW 3
-#define NAME_ROW 4
-
 class QMouseEvent;
 class TwinTable;
 class CellEditor;
+class RKVarEditModelBase;
 
-/**
-  *@author Thomas Friedrichsmeier
-  */
+#include "rkeditor.h"
 
-class TwinTableMember : public Q3Table {
+/** One of the tables used in a TwinTable.
+ at author Thomas Friedrichsmeier
+*/
+class TwinTableMember : public QTableView {
 	Q_OBJECT
 public: 
-	TwinTableMember (QWidget *parent, TwinTable *table, int trailing_rows=0, int trailing_cols=0);
+	TwinTableMember (QWidget *parent, TwinTable *table);
 	~TwinTableMember();
-/** stores the position of the mouse, when headerRightClick gets emitted */
-	QPoint mouse_at;
-/// TODO: can this be removed?
-	virtual TwinTableMember *varTable () { return this; };
-/** returns cell-value in a form suitable for submission to R (e.g. quoted for strings). Default implementation simply quotes the result of text () */
-	virtual QString rText (int row, int col) const;
 	TwinTableMember *getTwin () { return twin; };
 /** like QTable::numRows (), but returns only the "true", i.e. active rows (excluding the trailing_rows) */
 	int numTrueRows () const;
 /** like QTable::numCols (), but returns only the "true", i.e. active columns (excluding the trailing_cols) */
 	int numTrueCols () const;
-/** reimplemented form QTable not to use QTableItems. This one raises an assert (should never be called) */
-	void removeRows (const Q3MemArray<int> &rows);
-/** reimplemented form QTable not to use QTableItems. This one has no effect */
-	void swapRows (int row1, int row2, bool swapHeader);
-/** reimplemented form QTable not to use QTableItems. This one raises an assert (should never be called) */
-	void swapCells (int row1, int col1, int row2, int col2);
-/** reimplemented form QTable not to use QTableItems. This one has no effect */
-	void swapColumns (int col1, int col2, bool swapHeader);
-/** reimplemented form QTable not to use QTableItems. This one always returns 0 */
-	Q3TableItem *item (int, int) { return 0; }
-/** reimplemented form QTable not to use QTableItems. This one has no effect */
-	void setItem (int, int, Q3TableItem *) {};
-/** reimplemented form QTable not to use QTableItems. This one has no effect */
-	void takeItem (Q3TableItem *) {};
-/** reimplemented form QTable not to use QTableItems. This one always returns 0 or tted */
-	QWidget *cellWidget (int row, int col) const;
-/** reimplemented form QTable not to use QTableItems. This one has no effect */
-	void clearCellWidget (int, int) {};
-/** reimplemented form QTable not to use QTableItems. This one has no effect */
-	void setCellWidget (int, int, QWidget *) {};
 /** ends editing. Actually it's just a simple wrapper around QTable::endEdit () */
 	void stopEditing ();
-/** reimplemented form QTable not to work on TableColumns instead of QTableItems. */
-	void endEdit (int row, int col, bool accept, bool replace);
-/** reimplemented form QTable not to work on TableColumns instead of QTableItems */
-	void setCellContentFromEditor (int row, int col);
+#warning maybe still needed?
 /** needed to detect right mouse clicks in the header and tab-keypresses in the CellEditor */
-	bool eventFilter (QObject *object, QEvent *event);
+//	bool eventFilter (QObject *object, QEvent *event);
 /** reimplemented to delete cell contents on DEL and BACKSPACE. Placed in public, here, so CellEditor can have access */
 	void keyPressEvent (QKeyEvent *e);
-/** get contents of current selection as text (tab-separated-values) */
-	QString getSelectionText ();
-/** get contents of the specified range as text (tab-separated-values) */
-	QString getRangeText (int top_row, int left_col, int bottom_row, int right_col);
+
+	void copy ();
+	void paste (RKEditor::PasteMode mode);
+
 /** blanks out the currently selected cells (or the currently active cell, if there is no selection) */
 	void blankSelected ();
 /** shortcut to get the boundaries of the current selection */
-	void getSelectionBoundaries (int *top_row, int *left_col, int *bottom_row, int *right_col);
-/** internal function to paint the cell. Accepts the parameters of QTable::paintCell, and also:
- at param brush_override If not null, the cell-background will be painted in this brush
- at param pen_override If not null, the cell text will be painted in this pen
- at param text The text to draw
- at param aligment Alignment of the text. 0 = Left, 1=Right */
-	void paintCellInternal (QPainter *p, int row, int col, const QRect &cr, bool selected, const QColorGroup &cg, QBrush *brush_override, QPen *pen_override, const QString &text, int alignment);
+	QItemSelectionRange getSelectionBoundaries ();
+
+	void setRKModel (RKVarEditModelBase* model);
 signals:
-	void headerRightClick (int row, int col);
+	void contextMenuRequest (int row, int col);
 protected:
-/** reimplemented form QTable not to use QTableItems. This one has no effect */
-	void resizeData (int) {};
-/** reimplemented form QTable not to use QTableItems. This one has no effect */
-	void insertWidget (int, int, QWidget *) {};
 	TwinTableMember *twin;
 	TwinTable *table;
 	bool changing_width;
-	int trailing_rows;
-	int trailing_cols;
+	bool changing_scroll;
 	CellEditor *tted;
+/** stores the position of the mouse, when headerRightClick gets emitted */
+	QPoint mouse_at;
+/** reimplemented from QTableView to also adjust the twin */
+	void scrollContentsBy (int dx, int dy);
+
+	RKVarEditModelBase* mymodel;
 friend class TwinTable;
 	void setTwin (TwinTableMember *new_twin);
 public slots:
 	void editorLostFocus ();
-	void copy ();
 /** called when the current cell is changed. If no selection is in place, will (does not do it yet) pop up the value-list */
-	void currentCellChanged (int row, int col);
+//	void currentCellChanged (int row, int col);
 protected slots:
-	void columnWidthChanged (int col);
+	void headerContextMenuRequested (const QPoint& pos);
 };
 
 #endif

Modified: branches/KDE4_port/rkward/dataeditor/twintablemetamember.cpp
===================================================================
--- branches/KDE4_port/rkward/dataeditor/twintablemetamember.cpp	2007-11-08 15:07:49 UTC (rev 2189)
+++ branches/KDE4_port/rkward/dataeditor/twintablemetamember.cpp	2007-11-08 23:23:14 UTC (rev 2190)
@@ -32,6 +32,8 @@
 
 #include "../debug.h"
 
+#warning TODO remove
+#if 0
 TwinTableMetaMember::TwinTableMetaMember (QWidget *parent, TwinTable *table) : TwinTableMember (parent, table, 0, 1) {
 	type_values.insert (QString::number (RObject::DataNumeric), RObject::typeToText (RObject::DataNumeric));
 	type_values.insert (QString::number (RObject::DataFactor), RObject::typeToText (RObject::DataFactor));
@@ -166,3 +168,4 @@
 }
 
 #include "twintablemetamember.moc"
+#endif

Modified: branches/KDE4_port/rkward/dataeditor/twintablemetamember.h
===================================================================
--- branches/KDE4_port/rkward/dataeditor/twintablemetamember.h	2007-11-08 15:07:49 UTC (rev 2189)
+++ branches/KDE4_port/rkward/dataeditor/twintablemetamember.h	2007-11-08 23:23:14 UTC (rev 2190)
@@ -23,7 +23,7 @@
 
 class QWidget;
 class TwinTable;
-
+#if 0
 /**
 The TwinTableMember responsible for storing the meta-information (i.e. the top half of the TwinTable). See TwinTable and TwinTableMember.
 
@@ -53,5 +53,5 @@
 private:
 	RObject::ValueLabels type_values;
 };
-
 #endif
+#endif

Modified: branches/KDE4_port/rkward/windows/rkworkplace.cpp
===================================================================
--- branches/KDE4_port/rkward/windows/rkworkplace.cpp	2007-11-08 15:07:49 UTC (rev 2189)
+++ branches/KDE4_port/rkward/windows/rkworkplace.cpp	2007-11-08 23:23:14 UTC (rev 2190)
@@ -327,7 +327,7 @@
 			}
 		}
 
-		ed = new RKEditorDataFrame (iobj, 0);
+		ed = new RKEditorDataFrame (static_cast<RContainerObject*> (iobj), 0);
 		addWindow (ed);
 	} else {
 		ed = existing_editor;


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the rkward-tracker mailing list