[rkward-cvs] SF.net SVN: rkward:[3473] trunk/rkward
tfry at users.sourceforge.net
tfry at users.sourceforge.net
Sat Mar 12 11:09:52 UTC 2011
Revision: 3473
http://rkward.svn.sourceforge.net/rkward/?rev=3473&view=rev
Author: tfry
Date: 2011-03-12 11:09:51 +0000 (Sat, 12 Mar 2011)
Log Message:
-----------
Add support for S4 slots in object name completion and workspace browswer.
This required changes in many areas, because it changed an important assumption that we used so far. Previously, the parent of an RObject
was guaranteed to be a RContainerObject. Now, it can be any RObject.
In the long term, it may be a good idea to re-think RObject / inheritance.
Modified Paths:
--------------
trunk/rkward/ChangeLog
trunk/rkward/rkward/core/CMakeLists.txt
trunk/rkward/rkward/core/rcontainerobject.cpp
trunk/rkward/rkward/core/rcontainerobject.h
trunk/rkward/rkward/core/rfunctionobject.cpp
trunk/rkward/rkward/core/rfunctionobject.h
trunk/rkward/rkward/core/rkmodificationtracker.cpp
trunk/rkward/rkward/core/rkmodificationtracker.h
trunk/rkward/rkward/core/robject.cpp
trunk/rkward/rkward/core/robject.h
trunk/rkward/rkward/core/robjectlist.cpp
trunk/rkward/rkward/dataeditor/rkvareditmodel.cpp
trunk/rkward/rkward/misc/rkobjectlistview.cpp
trunk/rkward/rkward/plugin/rkformula.cpp
trunk/rkward/rkward/rbackend/rkstructuregetter.cpp
trunk/rkward/rkward/rbackend/rkstructuregetter.h
trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R
trunk/rkward/rkward/scriptbackends/rkcomponentscripting.cpp
trunk/rkward/rkward/windows/rkworkplace.cpp
trunk/rkward/rkward/windows/robjectbrowser.cpp
Modified: trunk/rkward/ChangeLog
===================================================================
--- trunk/rkward/ChangeLog 2011-03-11 10:25:52 UTC (rev 3472)
+++ trunk/rkward/ChangeLog 2011-03-12 11:09:51 UTC (rev 3473)
@@ -1,3 +1,4 @@
+- Support S4 slots in object name completion and workspace browser TODO: more testing, better icon
- More correct handling of quotes in object name completion
- Support plot history for ggplot2 plots
- Be less pro-active about fetching structure information on R objects in the workspace TODO: verify that this fixes our issues with rXML
Modified: trunk/rkward/rkward/core/CMakeLists.txt
===================================================================
--- trunk/rkward/rkward/core/CMakeLists.txt 2011-03-11 10:25:52 UTC (rev 3472)
+++ trunk/rkward/rkward/core/CMakeLists.txt 2011-03-12 11:09:51 UTC (rev 3473)
@@ -12,6 +12,7 @@
rfunctionobject.cpp
renvironmentobject.cpp
rkrownames.cpp
+ rslotspseudoobject.cpp
)
QT4_AUTOMOC(${core_STAT_SRCS})
Modified: trunk/rkward/rkward/core/rcontainerobject.cpp
===================================================================
--- trunk/rkward/rkward/core/rcontainerobject.cpp 2011-03-11 10:25:52 UTC (rev 3472)
+++ trunk/rkward/rkward/core/rcontainerobject.cpp 2011-03-12 11:09:51 UTC (rev 3473)
@@ -20,6 +20,7 @@
#include "../rbackend/rinterface.h"
#include "robjectlist.h"
+#include "rslotspseudoobject.h"
#include "rkvariable.h"
#include "rfunctionobject.h"
#include "renvironmentobject.h"
@@ -30,7 +31,7 @@
#include "../debug.h"
-RContainerObject::RContainerObject (RContainerObject *parent, const QString &name) : RObject (parent, name) {
+RContainerObject::RContainerObject (RObject *parent, const QString &name) : RObject (parent, name) {
RK_TRACE (OBJECTS);
type = Container;
rownames_object = 0;
@@ -60,7 +61,7 @@
delete child;
return 0;
} else {
- int child_index = getIndexOf (child);
+ int child_index = childmap.indexOf (child);
RK_ASSERT (child_index >= 0);
if (RKGlobals::tracker ()->removeObject (child, 0, true)) {
RData *child_name_data = new_data->getStructureVector ()[StoragePositionName];
@@ -131,20 +132,15 @@
RK_ASSERT (false);
return 0;
}
- RKGlobals::tracker ()->addObject (child_object, this, position);
+ RKGlobals::tracker ()->beginAddObject (child_object, this, position);
+ childmap.insert (position, child_object);
+ RKGlobals::tracker ()->endAddObject (child_object, this, position);
return child_object;
}
void RContainerObject::updateChildren (RData *new_children) {
RK_TRACE (OBJECTS);
- if (type & Incomplete) {
- // If the (new!) type is "Incomplete", it means, the structure getter simply stopped at this point.
- // In case we already have child info, we should update it (TODO: perhaps only, if anything is listening for child objects?)
- if (!(childmap.isEmpty () || isType (Updating))) updateFromR (0);
- return;
- }
-
RK_ASSERT (new_children->getDataType () == RData::StructureVector);
unsigned int new_child_count = new_children->getDataLength ();
@@ -263,9 +259,10 @@
}
}
-int RContainerObject::getIndexOf (RObject *child) const {
+int RContainerObject::getObjectModelIndexOf(RObject *child) const {
RK_TRACE (OBJECTS);
+ if (child == slots_pseudo_object) return childmap.size ();
return childmap.indexOf (child);
}
@@ -316,7 +313,9 @@
if ((position < 0) || (position > childmap.size ())) position = childmap.size ();
- RKGlobals::tracker ()->addObject (ret, this, position);
+ RKGlobals::tracker ()->beginAddObject (ret, this, position);
+ childmap.insert (position, ret);
+ RKGlobals::tracker ()->endAddObject (ret, this, position);
return ret;
}
@@ -332,23 +331,18 @@
object->name = new_name;
}
-void RContainerObject::insertChild (RObject* child, int position) {
+void RContainerObject::removeChildNoDelete (RObject *object) {
RK_TRACE (OBJECTS);
- RK_ASSERT (child->getContainer () == this);
- if ((position < 0) || (position > childmap.size ())) position = childmap.size ();
- childmap.insert (position, child);
+ if (!childmap.removeOne (object)) RK_ASSERT (false);
}
-void RContainerObject::removeChildNoDelete (RObject *object) {
+void RContainerObject::insertChild (RObject* child, int position) {
RK_TRACE (OBJECTS);
- int i = getIndexOf (object);
- if (i < 0) {
- RK_ASSERT (false);
- return;
- }
- childmap.removeAt (i);
+ RK_ASSERT (child->parentObject () == this);
+ if ((position < 0) || (position > childmap.size ())) position = childmap.size ();
+ childmap.insert (position, child);
}
void RContainerObject::removeChild (RObject *object, bool removed_in_workspace) {
Modified: trunk/rkward/rkward/core/rcontainerobject.h
===================================================================
--- trunk/rkward/rkward/core/rcontainerobject.h 2011-03-11 10:25:52 UTC (rev 3472)
+++ trunk/rkward/rkward/core/rcontainerobject.h 2011-03-12 11:09:51 UTC (rev 3473)
@@ -31,7 +31,7 @@
class RContainerObject : public RObject {
public:
- RContainerObject (RContainerObject *parent, const QString &name);
+ RContainerObject (RObject *parent, const QString &name);
~RContainerObject ();
@@ -51,7 +51,7 @@
/** fetches the child at the given position. This is very fast. */
RObject *findChildByIndex (int position) const;
/** return the index of the given child, or -1 if there is no such child */
- int getIndexOf (RObject *child) const;
+ int getObjectModelIndexOf (RObject *child) const;
/** creates a new child. Right now only RKVariables (false, false), or data.frames (true, true), or unspecified containers (true, false) can be created.
API will likely change. The child is NOT created in the workspace. That's your resonsibility. All this function returns is a new RObject* of the given
Modified: trunk/rkward/rkward/core/rfunctionobject.cpp
===================================================================
--- trunk/rkward/rkward/core/rfunctionobject.cpp 2011-03-11 10:25:52 UTC (rev 3472)
+++ trunk/rkward/rkward/core/rfunctionobject.cpp 2011-03-12 11:09:51 UTC (rev 3473)
@@ -22,7 +22,7 @@
#include "../rkglobals.h"
#include "../debug.h"
-RFunctionObject::RFunctionObject (RContainerObject *parent, const QString &name) : RObject (parent, name) {
+RFunctionObject::RFunctionObject (RObject *parent, const QString &name) : RObject (parent, name) {
RK_TRACE (OBJECTS);
type = Function;
}
Modified: trunk/rkward/rkward/core/rfunctionobject.h
===================================================================
--- trunk/rkward/rkward/core/rfunctionobject.h 2011-03-11 10:25:52 UTC (rev 3472)
+++ trunk/rkward/rkward/core/rfunctionobject.h 2011-03-12 11:09:51 UTC (rev 3473)
@@ -29,7 +29,7 @@
class RFunctionObject : public RObject {
public:
- RFunctionObject (RContainerObject *parent, const QString &name);
+ RFunctionObject (RObject *parent, const QString &name);
~RFunctionObject ();
/** reimplemented from RObject to handle function arguments */
Modified: trunk/rkward/rkward/core/rkmodificationtracker.cpp
===================================================================
--- trunk/rkward/rkward/core/rkmodificationtracker.cpp 2011-03-11 10:25:52 UTC (rev 3472)
+++ trunk/rkward/rkward/core/rkmodificationtracker.cpp 2011-03-12 11:09:51 UTC (rev 3473)
@@ -61,37 +61,39 @@
RK_ASSERT (!((editor) && (!ed)));
RK_ASSERT (!(removed_in_workspace && editor));
- if (removed_in_workspace) {
- if (ed) {
- if (KMessageBox::questionYesNo (0, i18n ("The object '%1' was removed from workspace or changed to a different type of object, but is currently opened for editing. Do you want to restore it?", object->getFullName ()), i18n ("Restore object?")) == KMessageBox::Yes) {
- ed->restoreObject (object);
- return false;
+ if (!object->isPseudoObject ()) {
+ if (removed_in_workspace) {
+ if (ed) {
+ if (KMessageBox::questionYesNo (0, i18n ("The object '%1' was removed from workspace or changed to a different type of object, but is currently opened for editing. Do you want to restore it?", object->getFullName ()), i18n ("Restore object?")) == KMessageBox::Yes) {
+ ed->restoreObject (object);
+ return false;
+ }
}
- }
- } else {
- if (editor || ed) {
- if (KMessageBox::questionYesNo (0, i18n ("Do you really want to remove the object '%1'? The object is currently opened for editing, it will be removed in the editor, too. There's no way to get it back.", object->getFullName ()), i18n ("Remove object?")) != KMessageBox::Yes) {
- return false;
- }
} else {
- // TODO: check for other editors editing this object
- if (KMessageBox::questionYesNo (0, i18n ("Do you really want to remove the object '%1'? There's no way to get it back.", object->getFullName ()), i18n ("Remove object?")) != KMessageBox::Yes) {
- return false;
+ if (editor || ed) {
+ if (KMessageBox::questionYesNo (0, i18n ("Do you really want to remove the object '%1'? The object is currently opened for editing, it will be removed in the editor, too. There's no way to get it back.", object->getFullName ()), i18n ("Remove object?")) != KMessageBox::Yes) {
+ return false;
+ }
+ } else {
+ // TODO: check for other editors editing this object
+ if (KMessageBox::questionYesNo (0, i18n ("Do you really want to remove the object '%1'? There's no way to get it back.", object->getFullName ()), i18n ("Remove object?")) != KMessageBox::Yes) {
+ return false;
+ }
}
}
}
RK_ASSERT (object);
- RK_ASSERT (object->getContainer ());
+ RK_ASSERT (object->parentObject ());
if (!updates_locked) {
- QModelIndex object_index = indexFor (object->getContainer ());
- int object_row = object->getContainer ()->getIndexOf (object);
+ QModelIndex object_index = indexFor (object->parentObject ());
+ int object_row = object->parentObject ()->getObjectModelIndexOf (object);
RK_ASSERT (object_row >= 0);
beginRemoveRows (object_index, object_row, object_row);
}
- if (!updates_locked) sendListenerNotification (RObjectListener::ObjectRemoved, object, 0, 0, 0);
+ if (!(updates_locked || object->isPseudoObject ())) sendListenerNotification (RObjectListener::ObjectRemoved, object, 0, 0, 0);
object->remove (removed_in_workspace);
@@ -102,6 +104,7 @@
void RKModificationTracker::moveObject (RContainerObject *parent, RObject* child, int old_index, int new_index) {
RK_TRACE (OBJECTS);
+ RK_ASSERT (!child->isPseudoObject ());
QModelIndex parent_index;
@@ -137,18 +140,20 @@
}
}
-void RKModificationTracker::addObject (RObject *object, RContainerObject* parent, int position) {
+void RKModificationTracker::beginAddObject (RObject *object, RObject* parent, int position) {
RK_TRACE (OBJECTS);
if (!updates_locked) {
QModelIndex parent_index = indexFor (parent);
beginInsertRows (parent_index, position, position);
}
+}
- parent->insertChild (object, position);
+void RKModificationTracker::endAddObject (RObject *object, RObject* parent, int position) {
+ RK_TRACE (OBJECTS);
if (!updates_locked) {
- sendListenerNotification (RObjectListener::ChildAdded, parent, position, 0, 0);
+ if (!object->isPseudoObject ()) sendListenerNotification (RObjectListener::ChildAdded, parent, position, 0, 0);
endInsertRows ();
}
}
@@ -259,11 +264,9 @@
}
RObject* parent_object = static_cast<RObject*> (parent.internalPointer ());
- RK_ASSERT (parent_object->isContainer ());
- RContainerObject* container = static_cast<RContainerObject*> (parent_object);
- RK_ASSERT (row < container->numChildren ());
+ RK_ASSERT (row < parent_object->numChildrenForObjectModel ());
- return (createIndex (row, column, container->findChildByIndex (row)));
+ return (createIndex (row, column, parent_object->findChildByObjectModelIndex (row)));
}
QModelIndex RKObjectListModel::parent (const QModelIndex& index) const {
@@ -272,7 +275,7 @@
if (!index.isValid ()) return QModelIndex ();
RObject* child = static_cast<RObject*> (index.internalPointer ());
RK_ASSERT (child);
- return (indexFor (child->getContainer ()));
+ return (indexFor (child->parentObject ()));
}
int RKObjectListModel::rowCount (const QModelIndex& parent) const {
@@ -282,9 +285,8 @@
if (parent.isValid ()) parent_object = static_cast<RObject*> (parent.internalPointer ());
else return 1; // the root item
- if (!(parent_object && parent_object->isContainer ())) return 0;
-
- return (static_cast<RContainerObject*> (parent_object)->numChildren ());
+ if (!parent_object) return 0;
+ return (parent_object->numChildrenForObjectModel ());
}
int RKObjectListModel::columnCount (const QModelIndex&) const {
@@ -313,6 +315,12 @@
}
if (col == ClassColumn) return object->makeClassString ("; ");
RK_ASSERT (false);
+ } else if (role == Qt::FontRole) {
+ if (col == NameColumn && object->isPseudoObject ()) {
+ QFont font;
+ font.setItalic (true);
+ return (font);
+ }
} else if (role == Qt::DecorationRole) {
if (col == NameColumn) return RKStandardIcons::iconForObject (object);
} else if (role == Qt::ToolTipRole) {
@@ -344,8 +352,8 @@
if (parent.isValid ()) parent_object = static_cast<RObject*> (parent.internalPointer ());
else return true; // the root item
- if (!(parent_object && parent_object->isContainer ())) return false;
- return (parent_object->isType (RObject::Incomplete) || static_cast<RContainerObject*> (parent_object)->numChildren ());
+ if (!parent_object) return false;
+ return (parent_object->isType (RObject::Incomplete) || parent_object->numChildrenForObjectModel ());
}
bool RKObjectListModel::canFetchMore (const QModelIndex &parent) const {
@@ -369,11 +377,11 @@
if (!object) return QModelIndex ();
if (object->isType (RObject::NonVisibleObject)) return QModelIndex ();
- RContainerObject *parent = object->getContainer ();
+ RObject *parent = object->parentObject ();
// must cast to RObject, here. Else casting to void* and back will confuse the hell out of GCC 4.2
if (!parent) return createIndex (0, 0, static_cast<RObject*> (RObjectList::getObjectList ()));
- int row = parent->getIndexOf (object);
+ int row = parent->getObjectModelIndexOf (object);
if (row < 0) {
RK_ASSERT (false);
return QModelIndex ();
Modified: trunk/rkward/rkward/core/rkmodificationtracker.h
===================================================================
--- trunk/rkward/rkward/core/rkmodificationtracker.h 2011-03-11 10:25:52 UTC (rev 3472)
+++ trunk/rkward/rkward/core/rkmodificationtracker.h 2011-03-12 11:09:51 UTC (rev 3473)
@@ -144,9 +144,11 @@
QMultiHash<RObject*, RObjectListener*> listeners;
friend class RContainerObject;
+friend class RObject;
friend class RObjectList;
/** essentially like the above function(s). All objects listening for child additions on the parent will be notified */
- void addObject (RObject *object, RContainerObject* parent, int position);
+ void beginAddObject (RObject *object, RObject* parent, int position);
+ void endAddObject (RObject *object, RObject* parent, int position);
/** essentially like the above function(s). All objects listening for child position changed on the parent will be notified */
void moveObject (RContainerObject *parent, RObject* child, int old_index, int new_index);
};
Modified: trunk/rkward/rkward/core/robject.cpp
===================================================================
--- trunk/rkward/rkward/core/robject.cpp 2011-03-11 10:25:52 UTC (rev 3472)
+++ trunk/rkward/rkward/core/robject.cpp 2011-03-12 11:09:51 UTC (rev 3473)
@@ -26,6 +26,7 @@
#include "../rkglobals.h"
#include "robjectlist.h"
#include "rcontainerobject.h"
+#include "rslotspseudoobject.h"
#include "rkvariable.h"
#include "renvironmentobject.h"
#include "rfunctionobject.h"
@@ -38,13 +39,14 @@
QVector<qint32> dim_null (1, 0);
}
-RObject::RObject (RContainerObject *parent, const QString &name) {
+RObject::RObject (RObject *parent, const QString &name) {
RK_TRACE (OBJECTS);
-
+
RObject::parent = parent;
RObject::name = name;
type = 0;
meta_map = 0;
+ slots_pseudo_object = 0;
dimensions = RObjectPrivate::dim_null; // safe initialization
}
@@ -52,6 +54,7 @@
RK_TRACE (OBJECTS);
cancelOutstandingCommands ();
+ delete slots_pseudo_object;
}
bool RObject::irregularShortName (const QString &name) {
@@ -75,13 +78,22 @@
return getMetaProperty ("label");
}
-RObject* RObject::findObjects (const QStringList &, RObjectSearchMap *, const QString &) {
+RObject* RObject::findObjects (const QStringList &path, RObjectSearchMap *matches, const QString &op) {
RK_TRACE (OBJECTS);
// not a container
- // TODO: handle '@'
+ if (op == "@") {
+ if (slots_pseudo_object) return (slots_pseudo_object->findObjects (path, matches, "$"));
+ }
return 0;
}
+int RObject::getObjectModelIndexOf (RObject *child) const {
+ RK_TRACE (OBJECTS);
+
+ if (child == slots_pseudo_object) return 0;
+ return -1;
+}
+
QString RObject::getMetaProperty (const QString &id) const {
RK_TRACE (OBJECTS);
if (meta_map) return (meta_map->value (id));
@@ -213,7 +225,7 @@
RK_TRACE (OBJECTS);
RCommand *command;
- if (getContainer () == RObjectList::getGlobalEnv ()) {
+ if (parentObject () == RObjectList::getGlobalEnv ()) {
#warning TODO: find a generic solution
// We handle objects directly in .GlobalEnv differently. That's to avoid forcing promises, when addressing the object directly. In the long run, .rk.get.structure should be reworked to simply not need the value-argument in any case.
command = new RCommand (".rk.get.structure.global (" + rQuote (getShortName ()) + ')', RCommand::App | RCommand::Sync | RCommand::GetStructuredData, QString::null, this, ROBJECT_UDPATE_STRUCTURE_COMMAND);
@@ -231,7 +243,11 @@
RK_TRACE (OBJECTS);
if (isType (Updating)) return;
- if (isType (Incomplete)) updateFromR (0);
+ if (isType (Incomplete)) {
+ updateFromR (0);
+ return;
+ }
+ if (slots_pseudo_object) slots_pseudo_object->fetchMoreIfNeeded (levels);
if (levels <= 0) return;
if (!isContainer ()) return;
const RObjectMap children = static_cast<RContainerObject*> (this)->childmap;
@@ -250,8 +266,8 @@
RKGlobals::tracker ()->removeObject (this, 0, true);
return;
}
- if (parent) parent->updateChildStructure (this, command); // this may result in a delete, so nothing after this!
- else updateStructure (command); // if we have no parent, likely we're the RObjectList
+ if (parent && parent->isContainer ()) static_cast<RContainerObject*> (parent)->updateChildStructure (this, command); // this may result in a delete, so nothing after this!
+ else updateStructure (command); // no (container) parent can happen for RObjectList and pseudo objects
return;
} else {
RK_ASSERT (false);
@@ -276,11 +292,19 @@
properties_change = updateClasses (new_data->getStructureVector ()[StoragePositionClass]);
properties_change = updateMeta (new_data->getStructureVector ()[StoragePositionMeta]);
properties_change = updateDimensions (new_data->getStructureVector ()[StoragePositionDims]);
+ properties_change = updateSlots (new_data->getStructureVector ()[StoragePositionSlots]);
if (properties_change) RKGlobals::tracker ()->objectMetaChanged (this);
if (type & NeedDataUpdate) updateDataFromR (0);
if (isPending ()) type -= Pending;
+ if (type & Incomplete) {
+ // If the (new!) type is "Incomplete", it means, the structure getter simply stopped at this point.
+ // In case we already have child info, we should update it (TODO: perhaps only, if anything is listening for child objects?)
+ if (numChildrenForObjectModel () && (!isType (Updating))) updateFromR (0);
+ return true;
+ }
+
return true;
}
@@ -438,18 +462,75 @@
return (false);
}
+bool RObject::updateSlots (RData *new_data) {
+ RK_TRACE (OBJECTS);
+
+ if (new_data->getDataLength ()) {
+ RK_ASSERT (new_data->getDataType () == RData::StructureVector);
+ bool added = false;
+ if (!slots_pseudo_object) {
+ slots_pseudo_object = new RSlotsPseudoObject (this, QString ());
+ added = true;
+ RKGlobals::tracker ()->lockUpdates (true);
+ }
+ bool ret = slots_pseudo_object->updateStructure (new_data->getStructureVector ()[0]);
+ if (added) {
+ RKGlobals::tracker ()->lockUpdates (false);
+
+ int index = getObjectModelIndexOf (slots_pseudo_object);
+ RSlotsPseudoObject *spo = slots_pseudo_object;
+ slots_pseudo_object = 0; // HACK: Must not be included in the count during the call to beginAddObject
+ RKGlobals::tracker ()->beginAddObject (slots_pseudo_object, this, index);
+ slots_pseudo_object = spo;
+ RKGlobals::tracker ()->endAddObject (slots_pseudo_object, this, index);
+ }
+ return ret;
+ } else if (slots_pseudo_object) {
+ RKGlobals::tracker ()->removeObject (slots_pseudo_object, 0, true);
+ }
+ return false;
+}
+
+int RObject::numChildrenForObjectModel () const {
+ RK_TRACE (OBJECTS);
+
+ int ret = isContainer () ? static_cast<const RContainerObject*>(this)->numChildren () : 0;
+ if (slots_pseudo_object) return ret + 1;
+ return ret;
+}
+
+RObject *RObject::findChildByObjectModelIndex (int index) const {
+ int offset = index;
+ if (isContainer ()) {
+ const RContainerObject *container = static_cast<const RContainerObject*>(this);
+ if (index < container->numChildren ()) return container->findChildByIndex (index);
+ offset -= container->numChildren ();
+ }
+ if (offset == 0) return slots_pseudo_object;
+ return 0;
+}
+
RKEditor *RObject::editor () const {
return (RKGlobals::tracker ()->objectEditor (this));
}
void RObject::rename (const QString &new_short_name) {
RK_TRACE (OBJECTS);
- parent->renameChild (this, new_short_name);
+ RK_ASSERT (canRename ());
+ static_cast<RContainerObject*> (parent)->renameChild (this, new_short_name);
}
void RObject::remove (bool removed_in_workspace) {
RK_TRACE (OBJECTS);
- parent->removeChild (this, removed_in_workspace);
+ RK_ASSERT (canRemove ());
+
+ if (isSlotsPseudoObject ()) {
+ RK_ASSERT (removed_in_workspace);
+ parent->slots_pseudo_object = 0;
+ delete this;
+ } else {
+ static_cast<RContainerObject*> (parent)->removeChild (this, removed_in_workspace);
+ }
}
//static
@@ -588,10 +669,12 @@
return (this != RObjectList::getObjectList ());
}
-
+
bool RObject::canRename () const {
RK_TRACE (OBJECTS);
+ if (isPseudoObject ()) return false;
+ if (parent && parent->isSlotsPseudoObject ()) return false;
// TODO: find out, if binding is locked:
// if (isLocked ()) return false;
return (isInGlobalEnv ());
@@ -600,6 +683,8 @@
bool RObject::canRemove () const {
RK_TRACE (OBJECTS);
+ if (isPseudoObject ()) return false;
+ if (parent && parent->isSlotsPseudoObject ()) return false;
// TODO: find out, if binding is locked:
// if (isLocked ()) return false;
return (isInGlobalEnv ());
Modified: trunk/rkward/rkward/core/robject.h
===================================================================
--- trunk/rkward/rkward/core/robject.h 2011-03-11 10:25:52 UTC (rev 3472)
+++ trunk/rkward/rkward/core/robject.h 2011-03-12 11:09:51 UTC (rev 3473)
@@ -24,6 +24,7 @@
#include "../rbackend/rcommandreceiver.h"
+class RSlotsPseudoObject;
class RContainerObject;
class RCommandChain;
class RKEditor;
@@ -39,7 +40,7 @@
class RObject : public RCommandReceiver {
public:
- RObject (RContainerObject *parent, const QString &name);
+ RObject (RObject *parent, const QString &name);
virtual ~RObject ();
/** types of objects, RKWard knows about */
@@ -57,11 +58,13 @@
ToplevelEnv=1 << 10,
PackageEnv=1 << 11,
Misplaced=1 << 12, /** < the object is not in the namespace where it would be expected */
- Numeric=1 << 13,
- Factor=2 << 13,
- Character=3 << 13,
- Logical=4 << 13,
+ S4Object=1 << 13,
+ Numeric=1 << 14,
+ Factor=2 << 14,
+ Character=3 << 14,
+ Logical=4 << 14,
DataTypeMask=Numeric | Factor | Character | Logical,
+ PseudoObject = 1 << 26, /** < The object is an internal representation, only, and does not exist in R. Currently, this is the case only for the slots-pseudo object */
Updating=1 << 27, /** < The object is about to be updated from R */
Incomplete=1 << 28, /** < The information on this object is not complete (typically, it's children have not been scanned, yet). */
NonVisibleObject=1 << 29, /** < the object is not listed in the object list. Currently, this is only the case for row.names()-objects */
@@ -87,10 +90,11 @@
StoragePositionClass = 2,
StoragePositionMeta = 3,
StoragePositionDims = 4,
- StoragePositionChildren = 5,
- StoragePositionFunArgs = 5,
- StoragePositionFunValues = 6,
- StorageSizeBasicInfo = 5,
+ StoragePositionSlots = 5,
+ StoragePositionChildren = 6,
+ StoragePositionFunArgs = 6,
+ StoragePositionFunValues = 7,
+ StorageSizeBasicInfo = 6,
};
#define ROBJECT_TYPE_INTERNAL_MASK (RObject::Container | RObject::Variable | RObject::Workspace | RObject::Environment | RObject::Function)
@@ -112,6 +116,8 @@
bool isVariable () const { return (type & Variable); };
/** see RObjectType */
bool isType (int type) const { return (RObject::type & type); };
+ bool isPseudoObject () const { return isType (PseudoObject); };
+ bool isSlotsPseudoObject () const { return (this && parent && ((void*) parent->slots_pseudo_object == (void*) this)); };
bool hasMetaObject () const { return (meta_map); };
/** see RObjectType::Pending */
bool isPending () const { return type & Pending; };
@@ -145,6 +151,11 @@
/** short hand for getDimension (0). Meaningful for one-dimensional objects */
int getLength () const { return dimensions[0]; };
+ /** return the index of the given child, or -1 if there is no such child */
+ virtual int getObjectModelIndexOf (RObject *child) const;
+ int numChildrenForObjectModel () const;
+ RObject *findChildByObjectModelIndex (int) const;
+
/** A QList of RObjects. Internally the same as RObjectMap, but can be considered "public" */
typedef QList<RObject*> ObjectList;
typedef QMap<QString, RObject*> RObjectSearchMap;
@@ -155,15 +166,15 @@
/** write the MetaData to the backend. Commands will be issued in the given chain */
virtual void writeMetaData (RCommandChain *chain);
-/** Returns the parent / container of this object. All objects have a parent except for the RObjectList (which returns 0) */
- RContainerObject *getContainer () const { return (parent); };
+/** Returns the parent of this object. All objects have a parent except for the RObjectList (which returns 0) */
+ RObject *parentObject () const { return (parent); };
RDataType getDataType () const { return (typeToDataType (type)); };
int getType () const { return type; };
- static RDataType typeToDataType (int ftype) { return ((RDataType) ((ftype & DataTypeMask) >> 13)); };
+ static RDataType typeToDataType (int ftype) { return ((RDataType) ((ftype & DataTypeMask) >> 14)); };
void setDataType (RDataType new_type) {
int n_type = type - (type & DataTypeMask);
- type = n_type + (new_type << 13);
+ type = n_type + (new_type << 14);
};
/** returns a textual representation of the given RDataType */
static QString typeToText (RDataType);
@@ -206,7 +217,8 @@
/** A map of objects accessible by index. Used in RContainerObject. Defined here for technical reasons. */
typedef QList<RObject*> RObjectMap;
- RContainerObject *parent;
+ RObject *parent;
+ RSlotsPseudoObject *slots_pseudo_object;
QString name;
int type;
QVector<qint32> dimensions;
@@ -248,6 +260,10 @@
@param new_data The command. Make sure it really is the dims field of an .rk.get.structure-command to update classes *before* calling this function! WARNING: the new_data object may get changed during this call. Call canAccommodateStructure () before calling this function!
@returns whether this caused any changes */
bool updateDimensions (RData *new_data);
+/** update information on slots of this object (if it is an S4 object)
+ at param new_data The command. Make sure it really is the slots field of an .rk.get.structure-command to update classes *before* calling this function! WARNING: the new_data object may get changed during this call. Call canAccommodateStructure () before calling this function!
+ at returns whether this caused any changes */
+ bool updateSlots (RData *new_data);
friend class RKModificationTracker;
/** Notify the object that some model needs its data. The object should take care of fetching the data from the backend, unless it already has the data. The default implementation does nothing (raises an assert). */
Modified: trunk/rkward/rkward/core/robjectlist.cpp
===================================================================
--- trunk/rkward/rkward/core/robjectlist.cpp 2011-03-11 10:25:52 UTC (rev 3472)
+++ trunk/rkward/rkward/core/robjectlist.cpp 2011-03-12 11:09:51 UTC (rev 3473)
@@ -52,7 +52,11 @@
type = RObject::Workspace;
update_chain = 0;
- RKGlobals::tracker ()->addObject (createTopLevelEnvironment (".GlobalEnv"), this, 0);
+
+ RObject *globalenv = createTopLevelEnvironment (".GlobalEnv");
+ RKGlobals::tracker ()->beginAddObject (globalenv, this, 0);
+ childmap.insert (0, globalenv);
+ RKGlobals::tracker ()->endAddObject (globalenv, this, 0);
}
RObjectList::~RObjectList () {
@@ -178,7 +182,9 @@
}
} else {
obj = createTopLevelEnvironment (name);
- RKGlobals::tracker ()->addObject (obj, this, i);
+ RKGlobals::tracker ()->beginAddObject (obj, this, i);
+ childmap.insert (i, obj);
+ RKGlobals::tracker ()->endAddObject (obj, this, i);
}
newchildmap.insert (i, obj);
}
Modified: trunk/rkward/rkward/dataeditor/rkvareditmodel.cpp
===================================================================
--- trunk/rkward/rkward/dataeditor/rkvareditmodel.cpp 2011-03-11 10:25:52 UTC (rev 3472)
+++ trunk/rkward/rkward/dataeditor/rkvareditmodel.cpp 2011-03-12 11:09:51 UTC (rev 3473)
@@ -617,7 +617,10 @@
if (row == NameRow) {
if (var->getShortName () != value.toString ()) {
- RKGlobals::tracker ()->renameObject (var, var->getContainer ()->validizeName (value.toString ()));
+ if (!var->canRename ()) return false;
+ if (var->parentObject ()->isContainer ()) {
+ RKGlobals::tracker ()->renameObject (var, static_cast<RContainerObject*> (var->parentObject ())->validizeName (value.toString ()));
+ } else return false;
}
} else if (row == LabelRow) {
var->setLabel (value.toString (), true);
Modified: trunk/rkward/rkward/misc/rkobjectlistview.cpp
===================================================================
--- trunk/rkward/rkward/misc/rkobjectlistview.cpp 2011-03-11 10:25:52 UTC (rev 3472)
+++ trunk/rkward/rkward/misc/rkobjectlistview.cpp 2011-03-12 11:09:51 UTC (rev 3473)
@@ -227,8 +227,7 @@
if (!source_parent.isValid ()) return true;
RObject* object = static_cast<RObject*> (source_parent.internalPointer ());
- RK_ASSERT (object->isContainer ());
- object = static_cast<RContainerObject*> (object)->findChildByIndex (source_row);
+ object = object->findChildByObjectModelIndex (source_row);
RK_ASSERT (object);
// always show the global env
@@ -263,12 +262,13 @@
// for top-level environments, always use the search order
if (left_object->isType (RObject::ToplevelEnv) && right_object->isType (RObject::ToplevelEnv)) {
- RContainerObject* left_parent = left_object->getContainer ();
- RContainerObject* right_parent = right_object->getContainer ();
+ RObject* left_parent = left_object->parentObject ();
+ RObject* right_parent = right_object->parentObject ();
if (!(left_parent && right_parent)) return false;
- return (left_parent->getIndexOf (left_object) < right_parent->getIndexOf (right_object));
- }
+ return (left_parent->getObjectModelIndexOf (left_object) < right_parent->getObjectModelIndexOf (right_object));
+ } else if (left_object->isPseudoObject ()) return false;
+ else if (right_object->isPseudoObject ()) return true;
return (QSortFilterProxyModel::lessThan (left, right));
}
Modified: trunk/rkward/rkward/plugin/rkformula.cpp
===================================================================
--- trunk/rkward/rkward/plugin/rkformula.cpp 2011-03-11 10:25:52 UTC (rev 3472)
+++ trunk/rkward/rkward/plugin/rkformula.cpp 2011-03-12 11:09:51 UTC (rev 3473)
@@ -166,12 +166,12 @@
model_ok = false;
}
if (dep_var) {
- container = dep_var->getContainer ();
+ container = dep_var->parentObject ();
} else if (!vlist.empty ()) {
- container = vlist.first ()->getContainer ();
+ container = vlist.first ()->parentObject ();
}
for (RObject::ObjectList::const_iterator it = vlist.begin (); it != vlist.end (); ++it) {
- if ((*it)->getContainer () != container) {
+ if ((*it)->parentObject () != container) {
multitable = true;
break;
}
Modified: trunk/rkward/rkward/rbackend/rkstructuregetter.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rkstructuregetter.cpp 2011-03-11 10:25:52 UTC (rev 3472)
+++ trunk/rkward/rkward/rbackend/rkstructuregetter.cpp 2011-03-12 11:09:51 UTC (rev 3473)
@@ -51,6 +51,7 @@
dims_fun = prefetch_fun ("dim");
names_fun = prefetch_fun ("names");
length_fun = prefetch_fun ("length");
+ rk_get_slots_fun = prefetch_fun (".rk.get.slots", false);
get_formals_fun = prefetch_fun (".rk.get.formals", false);
}
@@ -100,7 +101,7 @@
RData *ret = new RData;
- getStructureSafe (toplevel, name_string, false, ret, INTEGER (envlevel)[0]);
+ getStructureSafe (toplevel, name_string, 0, ret, INTEGER (envlevel)[0]);
if (with_namespace) {
UNPROTECT (1); /* namespace_envir */
@@ -109,13 +110,13 @@
return ret;
}
-void RKStructureGetter::getStructureSafe (SEXP value, const QString &name, bool misplaced, RData *storage, int nesting_depth) {
+void RKStructureGetter::getStructureSafe (SEXP value, const QString &name, int add_type_flags, RData *storage, int nesting_depth) {
RK_TRACE (RBACKEND);
GetStructureWorkerArgs args;
args.toplevel = value;
args.name = name;
- args.misplaced = misplaced;
+ args.add_type_flags = add_type_flags;
args.storage = storage;
args.getter = this;
args.nesting_depth = nesting_depth;
@@ -125,14 +126,14 @@
if (ok != TRUE) {
storage->discardData();
Rf_warning ("failure to get object %s", name.toLatin1().data ());
- getStructureWorker (R_NilValue, name, misplaced, storage, nesting_depth);
+ getStructureWorker (R_NilValue, name, add_type_flags, storage, nesting_depth);
}
}
void RKStructureGetter::getStructureWrapper (GetStructureWorkerArgs *data) {
RK_TRACE (RBACKEND);
- data->getter->getStructureWorker (data->toplevel, data->name, data->misplaced, data->storage, data->nesting_depth);
+ data->getter->getStructureWorker (data->toplevel, data->name, data->add_type_flags, data->storage, data->nesting_depth);
}
SEXP RKStructureGetter::resolvePromise (SEXP from) {
@@ -163,7 +164,7 @@
extern "C" {
// TODO: split out some of the large blocks into helper functions, to make this easier to read
-void RKStructureGetter::getStructureWorker (SEXP val, const QString &name, bool misplaced, RData *storage, int nesting_depth) {
+void RKStructureGetter::getStructureWorker (SEXP val, const QString &name, int add_type_flags, RData *storage, int nesting_depth) {
RK_TRACE (RBACKEND);
bool is_function = false;
@@ -235,7 +236,8 @@
else if (RKRSupport::callSimpleBool (is_logical_fun, value, R_BaseEnv)) type |= RObject::Logical;
}
}
- if (misplaced) type |= RObject::Misplaced;
+ type |= add_type_flags;
+
if (is_container) {
if (no_recurse) {
type |= RObject::Incomplete;
@@ -254,10 +256,6 @@
metadata->setData (QStringList ());
}
- // store type
- RData *typedata = new RData;
- typedata->setData (RData::IntStorage (1, type));
-
// get dims
RData::IntStorage dims;
SEXP dims_s = RKRSupport::callSimpleFun (dims_fun, value, R_BaseEnv);
@@ -283,6 +281,30 @@
RData *dimdata = new RData;
dimdata->setData (dims);
+ RData *slotsdata = new RData ();
+ // does it have slots?
+ if (Rf_isS4 (value)) {
+ type |= RObject::S4Object;
+ if (no_recurse) {
+ type |= RObject::Incomplete;
+ RK_DO (qDebug ("Depth limit reached. Will not recurse into slots of %s", name.toLatin1().data ()), RBACKEND, DL_DEBUG);
+ } else {
+ RData::RDataStorage dummy (1, 0);
+ dummy[0] = new RData ();
+
+ SEXP slots_pseudo_object = RKRSupport::callSimpleFun (rk_get_slots_fun, value, R_GlobalEnv);
+ PROTECT (slots_pseudo_object);
+ getStructureSafe (slots_pseudo_object, "SLOTS", RObject::PseudoObject, dummy[0], nesting_depth); // do not increase depth for this pseudo-object
+ UNPROTECT (1);
+
+ slotsdata->setData (dummy);
+ }
+ }
+
+ // store type
+ RData *typedata = new RData;
+ typedata->setData (RData::IntStorage (1, type));
+
// store everything we have so far
int storage_length = RObject::StorageSizeBasicInfo;
if (is_container) {
@@ -296,6 +318,7 @@
res[RObject::StoragePositionClass] = classdata;
res[RObject::StoragePositionMeta] = metadata;
res[RObject::StoragePositionDims] = dimdata;
+ res[RObject::StoragePositionSlots] = slotsdata;
// now add the extra info for containers and functions
if (is_container) {
@@ -341,7 +364,7 @@
}
}
- getStructureSafe (child, childnames[i], child_misplaced, children[i], nesting_depth + 1);
+ getStructureSafe (child, childnames[i], child_misplaced ? RObject::Misplaced : 0, children[i], nesting_depth + 1);
UNPROTECT (2); /* current_childname, child */
}
} else if (do_cont) {
@@ -352,13 +375,13 @@
if (Rf_isList (value) && (!may_be_special)) { // old style list
for (int i = 0; i < childcount; ++i) {
SEXP child = CAR (value);
- getStructureSafe (child, childnames[i], false, children[i], nesting_depth + 1);
+ getStructureSafe (child, childnames[i], 0, children[i], nesting_depth + 1);
CDR (value);
}
} else if (Rf_isNewList (value) && (!may_be_special)) { // new style list
for (int i = 0; i < childcount; ++i) {
SEXP child = VECTOR_ELT(value, i);
- getStructureSafe (child, childnames[i], false, children[i], nesting_depth + 1);
+ getStructureSafe (child, childnames[i], 0, children[i], nesting_depth + 1);
}
} else { // probably an S4 object disguised as a list
SEXP index = Rf_allocVector(INTSXP, 1);
@@ -366,7 +389,7 @@
for (int i = 0; i < childcount; ++i) {
INTEGER (index)[0] = (i + 1);
SEXP child = RKRSupport::callSimpleFun2 (double_brackets_fun, value, index, R_BaseEnv);
- getStructureSafe (child, childnames[i], false, children[i], nesting_depth + 1);
+ getStructureSafe (child, childnames[i], 0, children[i], nesting_depth + 1);
}
UNPROTECT (1); /* index */
}
Modified: trunk/rkward/rkward/rbackend/rkstructuregetter.h
===================================================================
--- trunk/rkward/rkward/rbackend/rkstructuregetter.h 2011-03-11 10:25:52 UTC (rev 3472)
+++ trunk/rkward/rkward/rbackend/rkstructuregetter.h 2011-03-12 11:09:51 UTC (rev 3473)
@@ -35,16 +35,16 @@
struct GetStructureWorkerArgs {
SEXP toplevel;
QString name;
- bool misplaced;
+ int add_type_flags;
RData *storage;
int nesting_depth;
RKStructureGetter *getter;
};
- void getStructureWorker (SEXP value, const QString &name, bool misplaced, RData *storage, int nesting_depth);
+ void getStructureWorker (SEXP value, const QString &name, int add_type_flags, RData *storage, int nesting_depth);
/** needed to wrap things inside an R_ToplevelExec */
static void getStructureWrapper (GetStructureWorkerArgs *data);
- void getStructureSafe (SEXP value, const QString &name, bool misplaced, RData *storage, int nesting_depth);
+ void getStructureSafe (SEXP value, const QString &name, int add_type_flags, RData *storage, int nesting_depth);
SEXP resolvePromise (SEXP from);
SEXP prefetch_fun (const char *name, bool from_base=true);
@@ -70,6 +70,7 @@
SEXP get_formals_fun;
SEXP double_brackets_fun;
SEXP length_fun;
+ SEXP rk_get_slots_fun;
int num_prefetched_funs;
bool keep_evalled_promises;
Modified: trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R
===================================================================
--- trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R 2011-03-11 10:25:52 UTC (rev 3472)
+++ trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R 2011-03-12 11:09:51 UTC (rev 3473)
@@ -271,6 +271,13 @@
r
}
+".rk.get.slots" <- function (x) {
+ slotnames <- methods::slotNames (class (x))
+ ret <- lapply (slotnames, function (slotname) slot (x, slotname))
+ names (ret) <- slotnames
+ ret
+}
+
".rk.get.environment.children" <- function (x, envlevel=0, namespacename=NULL) {
ret <- list ()
Modified: trunk/rkward/rkward/scriptbackends/rkcomponentscripting.cpp
===================================================================
--- trunk/rkward/rkward/scriptbackends/rkcomponentscripting.cpp 2011-03-11 10:25:52 UTC (rev 3472)
+++ trunk/rkward/rkward/scriptbackends/rkcomponentscripting.cpp 2011-03-12 11:09:51 UTC (rev 3473)
@@ -200,7 +200,7 @@
RObject* object = RObjectList::getObjectList ()->findObject (name);
if (object) {
- if (object->getContainer ()) return (object->getContainer ()->getFullName ());
+ if (object->parentObject ()) return (object->parentObject ()->getFullName ());
}
return (QString ());
}
Modified: trunk/rkward/rkward/windows/rkworkplace.cpp
===================================================================
--- trunk/rkward/rkward/windows/rkworkplace.cpp 2011-03-11 10:25:52 UTC (rev 3472)
+++ trunk/rkward/rkward/windows/rkworkplace.cpp 2011-03-12 11:09:51 UTC (rev 3473)
@@ -311,7 +311,7 @@
if (object->isDataFrame ()) {
return true;
- } else if (object->isVariable () && object->getContainer ()->isDataFrame ()) {
+ } else if (object->isVariable () && object->parentObject ()->isDataFrame ()) {
return true;
}
return false;
@@ -336,8 +336,8 @@
RKEditor *existing_editor = object->editor ();
if (!existing_editor) {
if (!iobj->isDataFrame ()) {
- if (iobj->isVariable () && iobj->getContainer ()->isDataFrame ()) {
- iobj = iobj->getContainer ();
+ if (iobj->isVariable () && iobj->parentObject ()->isDataFrame ()) {
+ iobj = iobj->parentObject ();
} else {
return 0;
}
Modified: trunk/rkward/rkward/windows/robjectbrowser.cpp
===================================================================
--- trunk/rkward/rkward/windows/robjectbrowser.cpp 2011-03-11 10:25:52 UTC (rev 3472)
+++ trunk/rkward/rkward/windows/robjectbrowser.cpp 2011-03-12 11:09:51 UTC (rev 3473)
@@ -233,7 +233,7 @@
QString name = KInputDialog::getText (i18n ("Rename object"), i18n ("Enter the new name"), list_view->menuObject ()->getShortName (), &ok, this);
if (ok) {
- QString valid = list_view->menuObject ()->getContainer ()->validizeName (name);
+ QString valid = static_cast<RContainerObject*> (list_view->menuObject ()->parentObject ())->validizeName (name);
if (valid != name) KMessageBox::sorry (this, i18n ("The name you specified was already in use or not valid. Renamed to %1", valid), i18n ("Invalid Name"));
RKGlobals::tracker ()->renameObject (list_view->menuObject (), valid);
}
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