1 /*************************************************************************** 2 rkvariable - description 3 ------------------- 4 begin : Thu Aug 12 2004 5 copyright : (C) 2004, 2007, 2010, 2011, 2012 by Thomas Friedrichsmeier 6 email : thomas.friedrichsmeier@kdemail.net 7 ***************************************************************************/ 8 9 /*************************************************************************** 10 * * 11 * This program is free software; you can redistribute it and/or modify * 12 * it under the terms of the GNU General Public License as published by * 13 * the Free Software Foundation; either version 2 of the License, or * 14 * (at your option) any later version. * 15 * * 16 ***************************************************************************/ 17 #ifndef RKVARIABLE_H 18 #define RKVARIABLE_H 19 20 #include <QStringList> 21 #include <QHash> 22 23 #include "robject.h" 24 25 class RContainerObject; 26 27 /** Abstract representation of a variable. A variable in this diction is an RObject, which is a vector of data. It may internally be a factor or a vector. 28 RKVariables are so far the only type of object that is really editable (data.frames are just a bundle of RKVariables). Therefore, for most practical purposes, the RKVariable represents a column in a table. 29 30 TODO: actually, for now, the data is always given to the backend as strings. Change that! 31 TODO: there should be "chunks" of column-data. This should be done at the level of rows, i.e. across columns. After all, if a row gets added/removed in one column, all other columns of the same table will also be affected. 32 TODO: which functions should do syncing by themselves, which should not? Or should all set... ()-functions have an extra parameter for this? 33 34 @author Thomas Friedrichsmeier 35 */ 36 class RKVariable : public RObject { 37 public: 38 /** constructs a new RKVariable as a child of the given parent and with the given name. Do not call directly, but let RContainerObject / RObjectList handle creation of new variables. */ 39 RKVariable (RContainerObject *parent, const QString &name); 40 41 ~RKVariable (); 42 43 /** set the VarType. If sync, the change will be communicated to the backend immediately. See RObject::RDataType */ 44 void setVarType (RObject::RDataType, bool sync=true); 45 46 /** reimplemented from RObject to also store value labels/factor levels (and in the future probably further info) */ 47 void writeMetaData (RCommandChain *chain) override; 48 friend class RContainerObject; 49 void rCommandDone (RCommand *command) override; 50 public: 51 ////////////// BEGIN: data handling //////////////////////// 52 /** the Status enum is used for both keeping track of the entire row and individual cells. For single cells the meaning should be obvious. The entire row 53 is set to Unused, if _no_ cell in the row is used, Valid if _all_ cells in the row are valid and Invalid if _one or more_ cells in the row are invalid, Unknown if _all_ cells in the row are unknown/updating. */ 54 enum Status { ValueUnused=0, ValueValid=1, ValueInvalid=2, ValueUnknown=4 }; 55 56 /** sets whether changed data should be synced immediately or not. Set this to off for large paste operations. Remember to call setSyncing (true) and syncDataToR () after the paste is complete */ 57 void lockSyncing (bool lock); 58 /** syncs pending data changes to the backend */ 59 void syncDataToR (); 60 /** reimplemented from RObject */ 61 void updateDataFromR (RCommandChain *chain) override; 62 63 bool hasInvalidFields () const; 64 65 /** get the value at the given row in text-form - regardless of the storage mode. 66 @param pretty: get the text in pretty form, e.g. rounding numbers to a certain number of digits, replacing numeric values with value labels if available, etc. Formatting is done according to the meta-information stored in the RObject and global user preferences */ 67 QString getText (int row, bool pretty=false) const; 68 /** get the value at the given row in text-form suitable for submission to R. I.e. strings are quoted, numbers are not, empty values are returned as NA */ 69 QString getRText (int row) const; 70 /** set the value at the given row in text-form. Will try to convert the given string to the internal storage format if possible. */ 71 virtual void setText (int row, const QString &text); 72 73 /** get a copy of the text values of rows from from_index to to_index. TODO: This could be made, but currently is not, more efficient than calling getText in a loop. */ 74 QString *getCharacter (int from_row, int to_row) const; 75 76 /** returns the current status of the given cell */ 77 Status cellStatus (int row) const; 78 79 /** entirely remove the given rows (i.e. the cells). Will also take care of updating the state (are there any invalid cells left?). Does not sync with the backend for technical reasons! You have to remove the row in the backend explicitly. */ 80 virtual void removeRows (int from_row, int to_row); 81 /** inserts count rows (with empty values) just above the given index. Does not sync with the backend for technical reasons! You have to insert the row in the backend explicitly. */ 82 virtual void insertRows (int row, int count); 83 /** Tells the object it has (data) length len. Usually this will only be called directly after creating a new object */ 84 void setLength (int len); 85 86 /** returns (a copy of) the map of value labels for this variable or and empty map, if no labels/levels are assigned. */ 87 ValueLabels getValueLabels () const; 88 /** assigns a new map of labels. Also takes care of syncing with the backend. */ 89 void setValueLabels (const ValueLabels& labels); 90 /** re-check a factor variable after editing its value labels, and sync labels to R */ 91 void updateValueLabels (); 92 /** get value labels as string (for display) */ 93 QString getValueLabelString () const; 94 /** set value labels from string (for paste operations) */ 95 void setValueLabelString (const QString &string); 96 97 /** Restores the variable including data and meta-data */ 98 void restore (RCommandChain *chain=0); 99 100 /** Stores formatting options set for this variable */ 101 struct FormattingOptions { 102 enum Alignment { AlignDefault=0, AlignLeft=1, AlignRight=2 }; 103 enum Precision { PrecisionDefault=0, PrecisionRequired=1, PrecisionFixed=2 }; 104 105 Alignment alignment; 106 Precision precision_mode; 107 int precision; 108 }; 109 110 /** assigns new formatting options. Ownership of the FormattingOptions -struct is transferred to the variable. Use setFormatting (0) to remove all options */ 111 void setFormattingOptions (const FormattingOptions new_options); 112 /** get the formatting options for this variable */ 113 FormattingOptions getFormattingOptions () const; 114 /** get formatting options as a string (for display) TODO: redundant -> remove */ 115 QString getFormattingOptionsString () const; 116 /** parse formatting options from the given string TODO: redundant -> remove */ 117 void setFormattingOptionsString (const QString &string); 118 119 /** This enum describes the alignment of text inside a table cell */ 120 enum CellAlign { AlignCellLeft=0, AlignCellRight=1 }; 121 /** returns alignment to use for this variable */ 122 CellAlign getAlignment () const; 123 124 /** creates/parses formatting options from the stored meta-property string. See also: getFormattingOptions () */ 125 static FormattingOptions parseFormattingOptionsString (const QString &string); 126 /** inverse of parseFormattingOptionsString () */ 127 static QString formattingOptionsToString (const FormattingOptions& options); 128 /** changes the allocated storage to contain a least length elements. More data may be allocated than actually needed. This function only ever does upsizing. */ 129 void extendToLength (int length); 130 protected: 131 /** Discards pending unsynced changes. */ 132 void discardUnsyncedChanges (); 133 /** like setNumeric, but sets chars. If internalStorage () is numeric, attempts to convert the given strings to numbers. I.e. the function behaves essentially like setText (), but operates on a range of cells. Code may assume that all data comes directly from R, is entirely valid in R. */ 134 virtual void setCharacterFromR (int from_row, int to_row, const QStringList &data); 135 /** set numeric values in the given range. Assumes you provide enough values for the range. If internalStorage is String, all values will be converted to strings, so you should use this function only, if you know you are dealing with a numeric object. Code may assume that all data comes directly from R, is entirely valid in R. */ 136 void setNumericFromR (int from_row, int to_row, const QVector<double> &data); 137 /** reimplemented from RObject to change the internal data storage mode, if the var is being edited */ 138 bool updateType (RData *new_data) override; 139 /** Extended from RObject::EditData to actually contain data. */ 140 struct RKVarEditData { 141 QStringList cell_strings; 142 QList<double> cell_doubles; 143 enum CellState { 144 Unknown=0, 145 Invalid=1, 146 NA=2, 147 Valid=4, 148 UnsyncedInvalidState=8 149 }; 150 QList<int> cell_states; 151 152 /// see setSyncing 153 int sync_locks; 154 /// stores changes if syncing is not immediate 155 ChangeSet changes; 156 /// stores whether there were preivously invalid cells. If so, and there are no longer, now, we may change the mode in the backend. 157 bool previously_valid; 158 /** the value-labels or factor levels assigned to this variable. 0 if no values/levels given. TODO: Should this be made a regular (non-pointer) member, or is the saved mem really worth the trouble? */ 159 ValueLabels *value_labels; 160 /// the formatting options set for this var (see FormattingOptions) */ 161 FormattingOptions formatting_options; 162 /// storage for invalid fields 163 QHash<int, QString> invalid_fields; 164 /// how many models need our data? 165 int num_listeners; 166 }; 167 RKVarEditData* data; 168 169 /** reimplemented from RObject */ 170 void beginEdit () override; 171 /** reimplemented from RObject */ 172 void endEdit () override; 173 174 /** takes care of syncing the given range of cells */ 175 void cellsChanged (int from_row, int to_row); 176 /** writes the given range of cells to the backend (regardless of whether syncing should be immediate) */ 177 virtual void writeData (int from_row, int to_row, RCommandChain *chain=0); 178 void writeInvalidFields (QList<int> rows, RCommandChain *chain=0); 179 /** writes the values labels to the backend */ 180 void writeValueLabels (RCommandChain *chain) const; 181 182 /** allocate edit data (cells initialized to NAs) */ 183 void allocateEditData (); 184 /** discard edit data */ 185 void discardEditData (); 186 /////////////////// END: data-handling ////////////////////// 187 }; 188 189 #endif 190