knowtreemodel.cpp

Go to the documentation of this file.
00001 
00002 #include <QtCore/qabstractitemmodel.h>
00003 
00004 #include <QtCore/qabstractitemmodel.h>
00005 
00006 #include "knowtreemodel.h"
00007 #include "main.h"
00008 #include "treeitem.h"
00009 #include "treemodel.h"
00010 
00011 // Конструктор модели дерева, состоящего из Item элементов
00012 // Принимает заголовки колонок и DOM модель древовидных данных
00013 knowtreemodel::knowtreemodel(const QStringList &headers, QDomDocument dommodel, QObject *parent)
00014 {
00015     QMap<QString, QString> rootData;
00016 
00017     // Определяется одно поле в корневом объекте
00018     // то есть на экране будет один столбец
00019     rootData["id"]="0";
00020     rootData["name"]="";
00021 
00022     // Создание корневого Item объекта
00023     rootItem = new TreeItem(rootData);
00024 
00025     // Динамическое создание дерева из Item ообъектов на основе DOM модели
00026     setupModelData(dommodel, rootItem);
00027 }
00028 
00029 
00030 // Деструктор Item модели.
00031 // По-хорошему деструктор перед удалением корневого элемента должен пробежать по
00032 // дереву элементов и удалить их
00033 knowtreemodel::~knowtreemodel()
00034 {
00035     delete rootItem;
00036 }
00037 
00038 
00039 // Разбор DOM модели и преобразование ее в Item модель
00040 void knowtreemodel::setupModelData(QDomDocument dommodel, TreeItem *parent)
00041 {
00042   QDomElement contentrootnode=dommodel.documentElement().firstChildElement("content").firstChildElement("node");
00043 
00044   if(contentrootnode.isNull())
00045    {
00046     qDebug() << "Unable load xml tree, first content node not found.";
00047     return;
00048    }
00049 
00050   parsenodeelement(contentrootnode,parent);
00051 
00052   return;
00053 }
00054 
00055 
00056 // Рекурсивный обход DOM дерева и извлечение из него узлов
00057 void knowtreemodel::parsenodeelement(QDomElement n, TreeItem *parent)
00058 {
00059  TreeItem *prnt = parent;
00060 
00061  // У данного Dom-элемента ищется таблица конечных записей
00062  // и XML записи заполняются в Item таблицу конечных записей
00063  prnt->recordtable_init(n);
00064 
00065  // Пробегаются все DOM элементы текущего уровня
00066  // и рекурсивно вызывается обработка подуровней
00067  while(!n.isNull())
00068  {
00069   if(n.tagName()=="node")
00070    {
00071     QString line1,line_name,line_id;
00072     line1=n.tagName();
00073     line_name=n.attribute("name");
00074     line_id=n.attribute("id");
00075     
00076     // qDebug() << "Read node " << line1 << " " << line_id<< " " << line_name;
00077 
00078     // Обнаруженый подузел прикрепляется к текущему элементу
00079     prnt->insertChildren(prnt->childCount(), 1, 1);
00080 
00081     // Устанавливается идентификатор узла
00082     prnt->child(prnt->childCount()-1)->setData("id",line_id);
00083 
00084     // Устанавливается навание узла
00085     prnt->child(prnt->childCount()-1)->setData("name",line_name);
00086 
00087     // Вызов перебора оставшегося DOM дерева с прикреплением обнаруженных объектов
00088     // к только что созданному элементу
00089     parsenodeelement(n.firstChildElement(), prnt->child(prnt->childCount()-1) );
00090 
00091    }
00092   n = n.nextSiblingElement();
00093  }
00094 
00095 }
00096 
00097 
00098 // Генерирование полного DOM дерева хранимых данных
00099 QDomElement knowtreemodel::export_fullmodeldata_to_dom(TreeItem *root)
00100 {
00101  QDomDocument doc;
00102  QDomElement elm=doc.createElement("content");
00103 
00104  // qDebug() << "New element for export" << xmlnode_to_string(elm);
00105 
00106  parsetreetodom(&elm,root);
00107 
00108  // qDebug() << "In export_fullmodeldata_to_dom stop element " << xmlnode_to_string(elm);
00109 
00110  return elm;
00111 }
00112 
00113 
00114 // Рекурсивное преобразование Item-элементов в Dom дерево
00115 void knowtreemodel::parsetreetodom(QDomElement *xmldata,TreeItem *curritem)
00116 {
00117 
00118  // Если в ветке присутсвует таблица конечных записей
00119  // В первую очередь добавляется она
00120  if(curritem->recordtable_getrowcount() > 0)
00121   {
00122    // Обработка таблицы конечных записей
00123 
00124    // Получение Dom дерева таблицы конечных записей
00125    QDomDocument rectab=curritem->recordtable_export_data_to_dom();
00126 
00127    // qDebug() << "In parsetreetodom() rectab " << rectab.toString();
00128 
00129    // Получаем корневой элемент документа
00130    QDomElement e = rectab.documentElement(); 
00131 
00132    // Dom дерево таблицы конечных записей добавляется
00133    // как подчиненный элемент к текущему элементу
00134    if(!e.isNull()) xmldata->appendChild(e.cloneNode());
00135    else qDebug() << "No convert QDomDocument to element for recordtable";
00136   }
00137 
00138  // Обработка каждой подчиненной ветки
00139  int i;
00140  for(i=0;i<curritem->childCount();i++)
00141   {
00142    // Получение имени перебираемой ветки
00143    QVariant vname=curritem->child(i)->data("name");
00144    QString branch_name=vname.toString();
00145 
00146    // Получение идентификатора перебираемой ветки
00147    QVariant vid=curritem->child(i)->data("id");
00148    QString branch_id=vid.toString();
00149 
00150    // qDebug() << "In parsetreetodom() found branch " << branch_name;
00151 
00152    // Временный элемент, куда будет внесена текущая перебираемая ветка
00153    QDomDocument doc;
00154    QDomElement  tempelement = doc.createElement("node");
00155 
00156    // Установка для временного элемента имени
00157    tempelement.setAttribute("name",branch_name);
00158 
00159    // Установка для временного элемента идентификатора
00160    tempelement.setAttribute("id",branch_id);
00161 
00162    // Добавление временного элемента к основному документу
00163    xmldata->appendChild(tempelement);
00164 
00165    // qDebug() << "In parsetreetodom() current construct doc " << xmlnode_to_string(*xmldata);
00166 
00167    // Рекурсивная обработка
00168    parsetreetodom(&(xmldata->lastChildElement()), curritem->child(i) );
00169   }
00170 
00171 }
00172 
00173 
00174 // Добавление новой подветки к указанной ветке
00175 void knowtreemodel::add_new_child_branch(const QModelIndex &index, QString id, QString name)
00176 {
00177  // Получение ссылки на Item элемент по QModelIndex
00178  TreeItem *parent=getItem(index);
00179 
00180  beginInsertRows(index, parent->childCount(), parent->childCount());
00181  add_new_branch(parent,id,name);
00182  endInsertRows();
00183 }
00184 
00185 
00186 // Добавление новой ветки после указанной ветки
00187 void knowtreemodel::add_new_sibling_branch(const QModelIndex &index, QString id, QString name)
00188 {
00189  // Получение ссылки на родительский Item элемент по QModelIndex
00190  TreeItem *current=getItem(index);
00191  TreeItem *parent=current->parent();
00192  
00193  beginInsertRows(index.parent(), parent->childCount(), parent->childCount());
00194  add_new_branch(parent,id,name);
00195  endInsertRows();
00196 }
00197 
00198 
00199 // Добавление новой подветки к Item элементу
00200 void knowtreemodel::add_new_branch(TreeItem *parent, QString id, QString name)
00201 {
00202  // Подузел прикрепляется к указанному элементу 
00203  // в конец списка подчиненных элементов
00204  parent->addChildren();
00205  
00206  // Устанавливается идентификатор узла
00207  parent->child(parent->childCount()-1)->setData("id",id);
00208 
00209  // Устанавливается навание узла
00210  parent->child(parent->childCount()-1)->setData("name",name);
00211 }
00212 
00213 
00214 // Перемещение ветки вверх
00215 QModelIndex knowtreemodel::move_up_branch(const QModelIndex &index)
00216 {
00217  return move_updn_branch(index,1);
00218 }
00219 
00220 
00221 // Перемещение ветки вниз
00222 QModelIndex knowtreemodel::move_dn_branch(const QModelIndex &index)
00223 {
00224  return move_updn_branch(index,-1);
00225 }
00226 
00227 
00228 // Перемещение ветки вверх или вниз
00229 QModelIndex knowtreemodel::move_updn_branch(const QModelIndex &index,int direction)
00230 {
00231  // Получение QModelIndex расположенного над или под элементом index
00232  QModelIndex swap_index=index.sibling(index.row()-direction,0);
00233 
00234  // Проверяется допустимость индекса элемента, куда будет сделано перемещение
00235  if(!swap_index.isValid())
00236   return QModelIndex(); // Возвращается пустой указатель
00237  
00238  // Запоминаются параметры для абсолютного позиционирования засветки
00239  // после перемещения ветки
00240  int         swpidx_row=swap_index.row();
00241  int         swpidx_column=swap_index.column();
00242  QModelIndex swpidx_parent=swap_index.parent();
00243 
00244  // Получение ссылки на Item элемент по QModelIndex
00245  TreeItem *current=getItem(index);
00246 
00247  // Перемещается ветка
00248  emit layoutAboutToBeChanged();
00249 
00250  bool moveok;
00251  if(direction==1) moveok=current->move_up();  // Перемещение в Item представлении
00252  else             moveok=current->move_dn(); 
00253 
00254  if(moveok)
00255   {
00256    changePersistentIndex(swap_index,index);
00257    changePersistentIndex(index,swap_index);
00258   } 
00259 
00260  emit layoutChanged();
00261 
00262  // Возвращается указатель на перемещенную ветку
00263  if(moveok) return this->index(swpidx_row, swpidx_column, swpidx_parent);
00264  else return QModelIndex(); // Возвращается пустой указатель
00265 }
00266 
00267 
00268 // Получение индекса подчиненного элемента с указанным номером
00269 // Нумерация элементов считается что идет с нуля
00270 QModelIndex knowtreemodel::indexChildren(const QModelIndex &parent, int n) const
00271 {
00272  // Проверяется, передан ли правильный QModelIndex
00273  // Если он неправильный, возвращается пустой индекс
00274  if(!parent.isValid()) 
00275   {
00276    qDebug() << "In indexChildren() unavailable model index";
00277    return QModelIndex();
00278   } 
00279  
00280  // Выясняется указатель на основной Item элемент
00281  TreeItem *item = getItem(parent);
00282  
00283  // Если у основного Item элемента запрашивается индекс 
00284  // несуществующего подэлемента, возвращается пустой индекс
00285  if( n<0 || n>(item->childCount()-1) ) 
00286   {
00287    qDebug() << "In indexChildren() unavailable children number";
00288    return QModelIndex();
00289   } 
00290   
00291  // Выясняется указатель на подчиненный Item элемент
00292  TreeItem *childitem = item->child(n);
00293     
00294  // Если указатель на подчиненный Item элемент непустой
00295  if(childitem)
00296   {
00297    // return createIndex(0, 0, childitem); // Индекс подчиненного элемента
00298    // return createIndex(n, 0, parent.internalPointer());
00299    
00300    return index(n,0,parent);
00301   }
00302  else
00303   {
00304    qDebug() << "In indexChildren() empty child element";
00305    return QModelIndex(); // Возвращается пустой индекс
00306   }
00307 }
00308 
00309 
00310 // Получение QModelIndex по известному TreeItem
00311 QModelIndex knowtreemodel::get_item_index(TreeItem *item)
00312 {
00313  int itemrow=item->childNumber();
00314  
00315  return this->createIndex(itemrow,0,item);
00316 }
00317 
00318 
00319 // Старый вариант поиска QModelIndex по известному TreeItem закомментирован,
00320 // но алгоритм может пригодиться для поиска других данных
00321 /*
00322 // Получение QModelIndex по известному TreeItem
00323 QModelIndex knowtreemodel::get_item_index(TreeItem *item)
00324 {
00325  // Выясняется начальный QModelIndex дерева
00326  QModelIndex rootindex=index( 0, 0 );
00327  
00328  // Очищается флаг поиска внутри элементов
00329  get_item_index_recurse(rootindex, item, 0);
00330  
00331  // Перебираются элементы на одном уровне вложения с начальным элементом дерева
00332  for(int i=0;rootindex.sibling(i,0).isValid();i++)
00333   {
00334    // qDebug() << "Sibling current " << (find_object<QTreeView>("knowtree")->model()->data(rootindex.sibling(i,0),Qt::EditRole)).toString();
00335 
00336    // Перебираемый элемент проверяется на соответствие с искомым TreeItem
00337    if(item==static_cast<TreeItem*>(rootindex.sibling(i,0).internalPointer()))
00338     return rootindex.sibling(i,0);
00339    else
00340     {
00341      // Производится поиск внутри элемента
00342      QModelIndex idx=get_item_index_recurse(rootindex.sibling(i,0), item, 1);
00343     
00344      // Если был найден элемент
00345      if(idx.isValid())return idx;
00346     }
00347   }
00348  
00349  // Если ничего не было найдено, возвращается пустой индекс
00350  return QModelIndex();
00351 }
00352 
00353 
00354 QModelIndex knowtreemodel::get_item_index_recurse(QModelIndex currindex, TreeItem *finditem, int mode)
00355 {
00356  static QModelIndex findindex;
00357  static int findflag=0;
00358 
00359  // Из QModelIndex можно всегда получить указатель TreeItem,
00360  // поэтому поиск можно вести по QModelIndex
00361  
00362  // Инициализация поиска
00363  if(mode==0)
00364   {
00365    findflag=0;
00366    return QModelIndex();
00367   } 
00368 
00369  // qDebug() << "Recurse current " << (find_object<QTreeView>("knowtree")->model()->data(currindex,Qt::EditRole)).toString();
00370  // qDebug() << "Current index have " << currindex.row() << "row";
00371  // qDebug() << "Find flag " << findflag;
00372  
00373  // Если был найден QModelIndex  
00374  if(findflag==1)return findindex;
00375   
00376  for(int i=0;currindex.child(i,0).isValid();i++)
00377   {
00378    // Проверяется текущий элемент, не соответствует ли 
00379    // его QModelIndex искомому TreeItem
00380    if(findflag==0 && 
00381       finditem==static_cast<TreeItem*>(currindex.child(i,0).internalPointer()))
00382     {
00383      findflag=1;
00384      findindex=currindex.child(i,0);
00385      return findindex;
00386     }
00387    
00388    // Рекурсивный вызов поиска в глубину дерева
00389    get_item_index_recurse(currindex.child(i,0), finditem, 1);
00390    
00391    // Если был найден QModelIndex  
00392    if(findflag==1)return findindex;
00393   }
00394 
00395  // Сюда код доходит если на текущем уровне поиска элемент еще не найден
00396  return QModelIndex();
00397 }
00398 */

Generated on Mon Feb 2 00:25:34 2009 for mytetra by  doxygen 1.5.1