OpenClonk
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 {
49  // initial model data
50  ReInit();
51 }
52 
53 C4ConsoleQtDefinitionListModel::~C4ConsoleQtDefinitionListModel() = default;
54 
55 void C4ConsoleQtDefinitionListModel::EnsureInit()
56 {
57  // Init if not already done
58  if (!root.get() || root->items.empty())
59  if (::Definitions.GetDefCount())
60  ReInit();
61 }
62 
63 void C4ConsoleQtDefinitionListModel::ReInit()
64 {
65  // Re-fill definition model with all loaded definitions matching condition
66  // (TODO: Add conditional lists)
67  root = std::make_unique<C4ConsoleQtDefinitionListModel::DefListNode>();
68  int32_t index = 0; C4Def *def;
69  while ((def = ::Definitions.GetDef(index++)))
70  {
71  // Ignore hidden defs
72  if (def->HideInCreator) continue;
73  // Build path leading to this definition
74  DefListNode *node_parent = root.get();
75  StdCopyStrBuf fn(def->Filename), fn2;
76  StdCopyStrBuf fn_full;
78  for (;;)
79  {
80  bool is_parent_folder = fn.SplitAtChar(DirectorySeparator, &fn2);
81  if (fn_full.getLength())
82  {
84  }
85  fn_full.Append(fn);
86  if (!is_parent_folder || WildcardMatch(C4CFN_DefFiles, fn.getData())) // ignore non-.ocd-folders (except for final definition)
87  {
88  // Find if path is already there
89  RemoveExtension(&fn);
90  DefListNode *node_child = nullptr;
91  for (auto &test_node_child : node_parent->items)
92  if (test_node_child->filename == fn)
93  {
94  node_child = &*test_node_child;
95  break;
96  }
97  // If not, create it
98  if (!node_child)
99  {
100  node_parent->items.emplace_back((node_child = new DefListNode()));
101  node_child->idx = node_parent->items.size() - 1;
102  node_child->parent = node_parent;
103  const char *localized_name = ::Definitions.GetLocalizedGroupFolderName(fn_full.getData());
104  node_child->name.Copy(localized_name ? localized_name : fn.getData());
105  node_child->filename.Copy(fn);
106  }
107  // And fill in node if this is not a parent folder
108  if (!is_parent_folder)
109  {
110  node_child->def = def;
111  const char *def_name = def->GetName();
112  if (def_name && *def_name) node_child->name.Copy(def_name);
113  break;
114  }
115  else
116  {
117  // Parent folder: Next path segment
118  node_parent = node_child;
119  }
120  }
121  fn = fn2;
122  }
123  }
124  // Descend into singleton root classes. I.e. if all elements are children of Objects/Items, move the root in there.
125  DefListNode *new_root = root.get();
126  while (new_root->items.size() == 1 && !new_root->items[0]->def)
127  {
128  std::unique_ptr<DefListNode> tmp(new_root->items[0].release());
129  root.reset(tmp.release());
130  new_root = root.get();
131  }
132  root->parent = nullptr;
133  // Copy group path names into definitions for later lookup by script
134  QStringList group_names;
135  DefListNode *node = root.get();
136  while (node)
137  {
138  if (node->def)
139  {
140  node->def->ConsoleGroupPath.Copy(group_names.join('/').toUtf8());
141  }
142  // Walk over tree. Remember groups in group_names string list.
143  if (!node->items.empty())
144  {
145  if (node != root.get()) group_names.append(node->name.getData());
146  node = node->items[0].get();
147  }
148  else
149  {
150  int32_t idx = node->idx + 1;
151  while ((node = node->parent))
152  {
153  if (node->items.size() > idx)
154  {
155  node = node->items[idx].get();
156  break;
157  }
158  if (group_names.size()) group_names.pop_back();
159  idx = node->idx + 1;
160  }
161  }
162  }
163  // Sort everything by display name (recursively)
164  root->SortByName();
165  // Model reset to invalidate all indexes
166  beginResetModel();
167  endResetModel();
168 }
169 
170 void C4ConsoleQtDefinitionListModel::OnItemRemoved(C4Def *p)
171 {
172  for (auto idx : this->persistentIndexList())
173  if (idx.internalPointer() == p)
174  this->changePersistentIndex(idx, QModelIndex());
175  ReInit();
176 }
177 
178 class C4Def *C4ConsoleQtDefinitionListModel::GetDefByModelIndex(const QModelIndex &idx)
179 {
180  DefListNode *node = static_cast<DefListNode *>(idx.internalPointer());
181  if (node) return node->def; else return nullptr;
182 }
183 
184 const char *C4ConsoleQtDefinitionListModel::GetNameByModelIndex(const QModelIndex &idx)
185 {
186  DefListNode *node = static_cast<DefListNode *>(idx.internalPointer());
187  if (node) return node->name.getData(); else return nullptr;
188 }
189 
190 int C4ConsoleQtDefinitionListModel::rowCount(const QModelIndex & parent) const
191 {
192  int result = 0;
193  DefListNode *parent_node = parent.isValid() ? static_cast<DefListNode *>(parent.internalPointer()) : nullptr;
194  if (!parent_node) parent_node = root.get();
195  if (parent_node) result = parent_node->items.size();
196  return result;
197 }
198 
199 int C4ConsoleQtDefinitionListModel::columnCount(const QModelIndex & parent) const
200 {
201  return 1; // Name only
202 }
203 
204 QVariant C4ConsoleQtDefinitionListModel::data(const QModelIndex & index, int role) const
205 {
206  // Object list lookup is done in index(). Here we just use the pointer.
207  DefListNode *node = static_cast<DefListNode *>(index.internalPointer());
208  if (!node) return QVariant();
209  if (role == Qt::DisplayRole)
210  {
211  return QString(node->name.getData());
212  }
213  // Nothing to show
214  return QVariant();
215 }
216 
217 QModelIndex C4ConsoleQtDefinitionListModel::index(int row, int column, const QModelIndex &parent) const
218 {
219  // Current index out of range?
220  if (row < 0 || column != 0) return QModelIndex();
221  DefListNode *parent_node = parent.isValid() ? static_cast<DefListNode *>(parent.internalPointer()) : nullptr;
222  if (!parent_node) parent_node = root.get();
223  if (parent_node->items.size() <= row) return QModelIndex();
224  // Index into tree
225  DefListNode *node = parent_node->items[row].get();
226  return createIndex(row, column, node);
227 }
228 
229 QModelIndex C4ConsoleQtDefinitionListModel::parent(const QModelIndex &index) const
230 {
231  // Find parent through tree
232  DefListNode *node = static_cast<DefListNode *>(index.internalPointer());
233  if (!node) return QModelIndex();
234  DefListNode *parent_node = node->parent;
235  if (!parent_node || parent_node == root.get()) return QModelIndex();
236  return createIndex(parent_node->idx, index.column(), parent_node);
237 }
238 
239 QModelIndex C4ConsoleQtDefinitionListModel::GetModelIndexByItem(C4Def *def) const
240 {
241  // Just search tree
242  DefListNode *node = root.get();
243  while (node)
244  {
245  if (node->def == def) break;
246  if (!node->items.empty())
247  node = node->items[0].get();
248  else
249  {
250  int32_t idx = node->idx + 1;
251  while ((node = node->parent))
252  {
253  if (node->items.size() > idx)
254  {
255  node = node->items[idx].get();
256  break;
257  }
258  idx = node->idx + 1;
259  }
260  }
261  }
262  // Def found in tree?
263  if (node)
264  {
265  return createIndex(node->idx, 0, node);
266  }
267  else
268  {
269  return QModelIndex();
270  }
271 }
#define C4CFN_DefFiles
Definition: C4Components.h:166
C4DefList Definitions
Definition: C4Globals.cpp:49
#define a
#define b
#define DirectorySeparator
#define AltDirectorySeparator
bool WildcardMatch(const char *szWildcard, const char *szString)
Definition: StdFile.cpp:396
void RemoveExtension(char *szFilename)
Definition: StdFile.cpp:303
Definition: C4Def.h:99
char Filename[_MAX_FNAME_LEN]
Definition: C4Def.h:176
bool HideInCreator
Definition: C4Def.h:148
int32_t GetDefCount()
const char * GetLocalizedGroupFolderName(const char *folder_path) const
Definition: C4DefList.cpp:531
C4Def * GetDef(int32_t Index)
const char * GetName() const override
Definition: C4PropList.cpp:243
const char * getData() const
Definition: StdBuf.h:442
void AppendChar(char cChar)
Definition: StdBuf.h:588
void Append(const char *pnData, size_t iChars)
Definition: StdBuf.h:519
int ReplaceChar(char cOld, char cNew)
Definition: StdBuf.cpp:336
size_t getLength() const
Definition: StdBuf.h:445