OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4ConsoleQtDefinitionListViewer.cpp
Go to the documentation of this file.
1 /*
2 * OpenClonk, http://www.openclonk.org
3 *
4 * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5 * Copyright (c) 2013, The OpenClonk Team and contributors
6 *
7 * Distributed under the terms of the ISC license; see accompanying file
8 * "COPYING" for details.
9 *
10 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11 * See accompanying file "TRADEMARK" for details.
12 *
13 * To redistribute this file separately, substitute the full license texts
14 * for the above references.
15 */
16 
17 /* Proplist table view */
18 
19 #include "C4Include.h"
20 #include "script/C4Value.h"
21 #include "object/C4Def.h"
22 #include "object/C4DefList.h"
24 #include "editor/C4Console.h"
25 #include "editor/C4EditCursor.h"
26 
27 
28 /* Defintion tree */
29 
30 void C4ConsoleQtDefinitionListModel::DefListNode::SortByName()
31 {
32  // sort self
33  std::sort(items.begin(), items.end(),
34  [](const std::unique_ptr<DefListNode> & a, const std::unique_ptr<DefListNode> & b) -> bool
35  { return a->name.Compare(b->name) < 0; });
36  // sort children recursively
37  int32_t idx = 0;
38  for (auto & child : items)
39  {
40  child->SortByName();
41  child->idx = idx++; // re-assign indices to reflect new sorting
42  }
43 }
44 
45 /* Defintion view model */
46 
47 C4ConsoleQtDefinitionListModel::C4ConsoleQtDefinitionListModel()
48  : last_row_count(0)
49 {
50  // initial model data
51  ReInit();
52 }
53 
54 C4ConsoleQtDefinitionListModel::~C4ConsoleQtDefinitionListModel()
55 {
56 }
57 
58 void C4ConsoleQtDefinitionListModel::EnsureInit()
59 {
60  // Init if not already done
61  if (!root.get() || root->items.empty())
62  if (::Definitions.GetDefCount())
63  ReInit();
64 }
65 
66 void C4ConsoleQtDefinitionListModel::ReInit()
67 {
68  // Re-fill definition model with all loaded definitions matching condition
69  // (TODO: Add conditional lists)
70  root.reset(new DefListNode());
71  int32_t index = 0; C4Def *def;
72  while (def = ::Definitions.GetDef(index++))
73  {
74  // Ignore hidden defs
75  if (def->HideInCreator) continue;
76  // Build path leading to this definition
77  DefListNode *node_parent = root.get();
78  StdCopyStrBuf fn(def->Filename), fn2;
80  for (;;)
81  {
82  bool is_parent_folder = fn.SplitAtChar(DirectorySeparator, &fn2);
83  if (!is_parent_folder || WildcardMatch(C4CFN_DefFiles, fn.getData())) // ignore non-.ocd-folders (except for final definition)
84  {
85  // Find if path is already there
86  RemoveExtension(&fn);
87  DefListNode *node_child = nullptr;
88  for (auto &test_node_child : node_parent->items)
89  if (test_node_child->filename == fn)
90  {
91  node_child = &*test_node_child;
92  break;
93  }
94  // If not, create it
95  if (!node_child)
96  {
97  node_parent->items.emplace_back((node_child = new DefListNode()));
98  node_child->idx = node_parent->items.size() - 1;
99  node_child->parent = node_parent;
100  node_child->name.Copy(fn);
101  node_child->filename.Copy(fn);
102  }
103  // And fill in node if this is not a parent folder
104  if (!is_parent_folder)
105  {
106  node_child->def = def;
107  const char *def_name = def->GetName();
108  if (def_name && *def_name) node_child->name.Copy(def_name);
109  break;
110  }
111  else
112  {
113  // Parent folder: Next path segment
114  node_parent = node_child;
115  }
116  }
117  fn = fn2;
118  }
119  }
120  // Descend into singleton root classes. I.e. if all elements are children of Objects/Items, move the root in there.
121  DefListNode *new_root = root.get();
122  while (new_root->items.size() == 1 && !new_root->items[0]->def)
123  {
124  std::unique_ptr<DefListNode> tmp(new_root->items[0].release());
125  root.reset(tmp.release());
126  new_root = root.get();
127  }
128  root->parent = nullptr;
129  // Copy group path names into definitions for later lookup by script
130  QStringList group_names;
131  DefListNode *node = root.get();
132  while (node)
133  {
134  if (node->def)
135  {
136  node->def->ConsoleGroupPath.Copy(group_names.join('/').toUtf8());
137  }
138  // Walk over tree. Remember groups in group_names string list.
139  if (!node->items.empty())
140  {
141  if (node != root.get()) group_names.append(node->name.getData());
142  node = node->items[0].get();
143  }
144  else
145  {
146  int32_t idx = node->idx + 1;
147  while ((node = node->parent))
148  {
149  if (node->items.size() > idx)
150  {
151  node = node->items[idx].get();
152  break;
153  }
154  if (group_names.size()) group_names.pop_back();
155  idx = node->idx + 1;
156  }
157  }
158  }
159  // Sort everything by display name (recursively)
160  root->SortByName();
161  // Model reset to invalidate all indexes
162  beginResetModel();
163  endResetModel();
164 }
165 
166 void C4ConsoleQtDefinitionListModel::OnItemRemoved(C4Def *p)
167 {
168  for (auto idx : this->persistentIndexList())
169  if (idx.internalPointer() == p)
170  this->changePersistentIndex(idx, QModelIndex());
171  ReInit();
172 }
173 
174 class C4Def *C4ConsoleQtDefinitionListModel::GetDefByModelIndex(const QModelIndex &idx)
175 {
176  DefListNode *node = static_cast<DefListNode *>(idx.internalPointer());
177  if (node) return node->def; else return nullptr;
178 }
179 
180 const char *C4ConsoleQtDefinitionListModel::GetNameByModelIndex(const QModelIndex &idx)
181 {
182  DefListNode *node = static_cast<DefListNode *>(idx.internalPointer());
183  if (node) return node->name.getData(); else return nullptr;
184 }
185 
186 int C4ConsoleQtDefinitionListModel::rowCount(const QModelIndex & parent) const
187 {
188  int result = 0;
189  DefListNode *parent_node = parent.isValid() ? static_cast<DefListNode *>(parent.internalPointer()) : nullptr;
190  if (!parent_node) parent_node = root.get();
191  if (parent_node) result = parent_node->items.size();
192  return result;
193 }
194 
195 int C4ConsoleQtDefinitionListModel::columnCount(const QModelIndex & parent) const
196 {
197  return 1; // Name only
198 }
199 
200 QVariant C4ConsoleQtDefinitionListModel::data(const QModelIndex & index, int role) const
201 {
202  // Object list lookup is done in index(). Here we just use the pointer.
203  DefListNode *node = static_cast<DefListNode *>(index.internalPointer());
204  if (!node) return QVariant();
205  if (role == Qt::DisplayRole)
206  {
207  return QString(node->name.getData());
208  }
209  // Nothing to show
210  return QVariant();
211 }
212 
213 QModelIndex C4ConsoleQtDefinitionListModel::index(int row, int column, const QModelIndex &parent) const
214 {
215  // Current index out of range?
216  if (row < 0 || column != 0) return QModelIndex();
217  DefListNode *parent_node = parent.isValid() ? static_cast<DefListNode *>(parent.internalPointer()) : nullptr;
218  if (!parent_node) parent_node = root.get();
219  if (parent_node->items.size() <= row) return QModelIndex();
220  // Index into tree
221  DefListNode *node = parent_node->items[row].get();
222  return createIndex(row, column, node);
223 }
224 
225 QModelIndex C4ConsoleQtDefinitionListModel::parent(const QModelIndex &index) const
226 {
227  // Find parent through tree
228  DefListNode *node = static_cast<DefListNode *>(index.internalPointer());
229  if (!node) return QModelIndex();
230  DefListNode *parent_node = node->parent;
231  if (!parent_node || parent_node == root.get()) return QModelIndex();
232  return createIndex(parent_node->idx, index.column(), parent_node);
233 }
234 
235 QModelIndex C4ConsoleQtDefinitionListModel::GetModelIndexByItem(C4Def *def) const
236 {
237  // Just search tree
238  DefListNode *node = root.get();
239  while (node)
240  {
241  if (node->def == def) break;
242  if (!node->items.empty())
243  node = node->items[0].get();
244  else
245  {
246  int32_t idx = node->idx + 1;
247  while ((node = node->parent))
248  {
249  if (node->items.size() > idx)
250  {
251  node = node->items[idx].get();
252  break;
253  }
254  idx = node->idx + 1;
255  }
256  }
257  }
258  // Def found in tree?
259  if (node)
260  {
261  return createIndex(node->idx, 0, node);
262  }
263  else
264  {
265  return QModelIndex();
266  }
267 }
virtual const char * GetName() const
Definition: C4PropList.cpp:267
C4Def * GetDef(int32_t Index)
#define b
int32_t GetDefCount()
#define a
#define AltDirectorySeparator
bool HideInCreator
Definition: C4Def.h:151
Definition: C4Def.h:100
void RemoveExtension(char *szFilename)
Definition: StdFile.cpp:316
int ReplaceChar(char cOld, char cNew)
Definition: StdBuf.cpp:343
bool WildcardMatch(const char *szWildcard, const char *szString)
Definition: StdFile.cpp:384
char Filename[_MAX_FNAME+1]
Definition: C4Def.h:179
#define C4CFN_DefFiles
Definition: C4Components.h:166
C4DefList Definitions
Definition: C4Globals.cpp:49
#define DirectorySeparator
void Copy()
Definition: StdBuf.h:475