g4dialog
Loading...
Searching...
No Matches
gcommands.cc
Go to the documentation of this file.
1// G4Dialog
2#include "gcommands.h"
3
4G4Commands::G4Commands(QWidget* parent) : QWidget(parent) {
5 // Summary: Build the overall UI layout (search, commands tree + help, history, command prompt).
6
7 // + +-------------------+ +
8 // | | > Search | |
9 // + +-------------------+ +
10 // | | | | |
11 // | | Tree | Help | |
12 // | | | | |
13 // | +-------------------+ |
14 // | +-------------------+ |
15 // | | | |
16 // | | History | |
17 // | | | |
18 // | +-------------------+ |
19 // | +-------------------+ |
20 // | | > Prompt | |
21 // | +-------------------+ |
22 // +-----------------------+
23
24 // Search entry: used to filter the tree model in real time.
25 w_search = new QLineEdit();
26 w_search->installEventFilter(this);
27 w_search->activateWindow();
28 w_search->setFocusPolicy(Qt::StrongFocus);
29 w_search->setFocus(Qt::TabFocusReason);
30
31 // Every time w_search is changed, filter the tree.
32 connect(w_search, &QLineEdit::textChanged, this, &G4Commands::filterTreeItems);
33
34 // Commands tree and help are placed side-by-side.
35 QSplitter* commands_help_splitter = new QSplitter(Qt::Horizontal);
36 QVBoxLayout* commands_help_layout = new QVBoxLayout(commands_help_splitter);
37
38 // Left: the commands tree (built from Geant4 UI command tree).
39 create_geant4_commands_widget();
40 commands_help_layout->addWidget(w_commands);
41
42 // Right: the help on individual commands or command directories.
43 w_help = new QTextEdit(commands_help_splitter);
44 w_help->setReadOnly(true);
45
46 // History area: executed commands (deduplicated).
47 w_history = new QListWidget();
48 w_history->setSelectionMode(QAbstractItemView::SingleSelection);
49 w_history->installEventFilter(this);
50 connect(w_history, &QListWidget::itemDoubleClicked, this, &G4Commands::recall_history_item_on_double_click);
51
52 // Command entry: pressing Enter triggers execution.
53 w_command = new QLineEdit();
54 w_command->installEventFilter(this);
55 w_command->activateWindow();
56 w_command->setFocusPolicy(Qt::StrongFocus);
57 w_command->setFocus(Qt::TabFocusReason);
58 connect(w_command, &QLineEdit::returnPressed, this, &G4Commands::execute_command);
59
60 // Allocate more horizontal space to the help pane by default.
61 commands_help_splitter->setSizes(QList<int>() << 300 << 800);
62
63 // Putting all together into a vertical layout.
64 QVBoxLayout* v_layout = new QVBoxLayout(this);
65 v_layout->addWidget(new QLabel("Search Commands"));
66 v_layout->addWidget(w_search);
67 v_layout->addWidget(commands_help_splitter, /* stretch factor */ 2);
68 v_layout->addWidget(new QLabel("History"));
69 v_layout->addWidget(w_history);
70 v_layout->addWidget(new QLabel("Enter Command"));
71 v_layout->addWidget(w_command);
72}
73
74void G4Commands::create_geant4_commands_widget() {
75 // Summary: Build the QTreeView model by walking the Geant4 UI command tree.
76
77 // Read current search text (used by filterTreeItems()).
78 QString search_text = w_search->text();
79 (void)search_text; // Not used immediately here; kept as a convenient debug hook.
80
81 G4UImanager* ui_manager = G4UImanager::GetUIpointer();
82 G4UIcommandTree* g4_commands_tree = ui_manager->GetTree();
83
84 // Create model for QTreeView.
85 QStandardItemModel* model = new QStandardItemModel();
86 w_commands = new QTreeView();
87 w_commands->setModel(model);
88 w_commands->setSelectionMode(QAbstractItemView::SingleSelection);
89
90 // Set header label for the QTreeView model.
91 model->setHorizontalHeaderLabels(QStringList() << "Commands");
92
93 // Add top-level command directories to the model.
94 G4int g4_commands_tree_size = g4_commands_tree->GetTreeEntry();
95 for (int a = 0; a < g4_commands_tree_size; a++) {
96 // Each top-level entry is a command directory node; children are populated recursively.
97 QStandardItem* newItem = new QStandardItem(
98 QString((char*)g4_commands_tree->GetTree(a + 1)->GetPathName().data()).trimmed());
99 model->appendRow(newItem);
100
101 // Add child directories and commands.
102 create_child_help_tree(newItem, g4_commands_tree->GetTree(a + 1));
103 }
104
105 // Read-only: prevent accidental edits to the command path strings.
106 w_commands->setEditTriggers(QAbstractItemView::NoEditTriggers);
107
108 // Selection drives help display; double-click pastes selection into the command prompt.
109 connect(w_commands->selectionModel(), &QItemSelectionModel::selectionChanged, this,
110 &G4Commands::display_help_from_selection);
111 connect(w_commands, &QTreeView::doubleClicked, this, &G4Commands::paste_help_selection_item);
112}
113
114void G4Commands::filterTreeItems() {
115 // Summary: Hide/show top-level rows depending on whether they (or their descendants) match the search string.
116
117 QString search_text = w_search->text().trimmed();
118 QStandardItemModel* model = qobject_cast<QStandardItemModel*>(w_commands->model());
119 if (!model) return;
120
121 for (int i = 0; i < model->rowCount(); ++i) {
122 QStandardItem* item = model->item(i);
123 bool showItem = filterItem(item, search_text);
124
125 // For top-level nodes we also explicitly hide the row at the root.
126 w_commands->setRowHidden(i, QModelIndex(), !showItem);
127 }
128}
129
130bool G4Commands::filterItem(QStandardItem* item, const QString& search_text) {
131 // Summary: Recursively evaluate whether this item should be visible.
132
133 // Direct match on this node.
134 bool matches = item->text().contains(search_text, Qt::CaseInsensitive);
135 bool childMatches = false;
136
137 // Check child items recursively (depth-first).
138 for (int i = 0; i < item->rowCount(); ++i) {
139 QStandardItem* childItem = item->child(i);
140 if (filterItem(childItem, search_text)) { childMatches = true; }
141 }
142
143 // Show this item if it matches or has a matching child.
144 bool showItem = matches || childMatches;
145
146 // Apply visibility at this node's location in the tree.
147 w_commands->setRowHidden(item->row(), item->index().parent(), !showItem);
148
149 return showItem;
150}
151
152void G4Commands::create_child_help_tree(QStandardItem* parent, G4UIcommandTree* aCommandTree) {
153 // Summary: Populate children for a given Geant4 tree node (sub-directories first, then leaf commands).
154
155 if (parent == nullptr || aCommandTree == nullptr) return;
156
157 // Add child directories (sub-trees).
158 for (int a = 0; a < aCommandTree->GetTreeEntry(); a++) {
159 QStandardItem* newItem = new QStandardItem(
160 QString((char*)(aCommandTree->GetTree(a + 1)->GetPathName()).data()).trimmed());
161 parent->appendRow(newItem);
162 create_child_help_tree(newItem, aCommandTree->GetTree(a + 1));
163 }
164
165 // Add commands at this node (leaf entries).
166 for (int a = 0; a < aCommandTree->GetCommandEntry(); a++) {
167 QStandardItem* newItem = new QStandardItem(
168 QString((char*)(aCommandTree->GetCommand(a + 1)->GetCommandPath()).data()).trimmed());
169 parent->appendRow(newItem);
170 }
171}
172
173void G4Commands::execute_command() {
174 // Summary: Execute the typed command through Geant4 UI manager and update history.
175
176 if (!w_command) return;
177
178 QString command = w_command->text().trimmed();
179 if (command.isEmpty()) return;
180
181 G4UImanager* ui_manager = G4UImanager::GetUIpointer();
182 ui_manager->ApplyCommand(command.toStdString().c_str());
183
184 // Avoid duplicate history entries (simple linear scan, small list expected).
185 bool exists = false;
186 for (int i = 0; i < w_history->count(); ++i) {
187 if (w_history->item(i)->text() == command) {
188 exists = true;
189 break;
190 }
191 }
192
193 if (!exists) { w_history->addItem(command); }
194
195 // Clear command field after execution to signal completion.
196 w_command->clear();
197}
198
199void G4Commands::recall_history_item_on_double_click(QListWidgetItem* item) {
200 // Summary: Load the selected history command into the input field.
201
202 if (!item) return;
203
204 // Set the command line input to the selected history item.
205 w_command->setText(item->text());
206}
207
208// paste history item onto command line
209void G4Commands::display_help_from_selection() {
210 // Summary: Determine whether selection is a command or a directory and show help/title accordingly.
211
212 if (!w_commands || !w_help) return;
213
214 QModelIndexList selectedIndexes = w_commands->selectionModel()->selectedIndexes();
215 if (selectedIndexes.isEmpty()) return;
216
217 QModelIndex index = selectedIndexes.first();
218 QStandardItemModel* model = qobject_cast<QStandardItemModel*>(w_commands->model());
219 if (!model) return;
220
221 QStandardItem* item = model->itemFromIndex(index);
222 if (!item) return;
223
224 std::string itemText = item->text().toStdString();
225 G4UIcommandTree* treeTop = G4UImanager::GetUIpointer()->GetTree();
226 G4UIcommand* command = treeTop->FindPath(itemText.c_str());
227
228 if (command) {
229 // Leaf command: show detailed guidance and parameter info.
230 w_help->setText(get_command_g4help(command));
231 }
232 else {
233 // Directory node: show the title (if found).
234 G4UIcommandTree* path = treeTop->FindCommandTree(itemText.c_str());
235 if (path) { w_help->setText(QString::fromStdString(path->GetTitle())); }
236 }
237}
238
239// display help on selected item
240void G4Commands::paste_help_selection_item() {
241 // Summary: Refresh help and paste the selected command/directory text into the prompt.
242
243 // Display help from the selection.
244 display_help_from_selection();
245
246 if (!w_commands || !w_help) { return; }
247
248 // Get the selected items from the selection model of QTreeView.
249 QModelIndexList selectedIndexes = w_commands->selectionModel()->selectedIndexes();
250 if (selectedIndexes.isEmpty()) { return; }
251
252 // Assuming the first selected item is the one to retrieve.
253 QModelIndex index = selectedIndexes.first();
254 QStandardItemModel* model = qobject_cast<QStandardItemModel*>(w_commands->model());
255 if (!model) { return; }
256
257 // Retrieve the item at the given index.
258 QStandardItem* item = model->itemFromIndex(index);
259 if (!item) { return; }
260
261 // Clear the command input field and set the selected item's text.
262 w_command->clear();
263 w_command->setText(item->text());
264}
265
266QString G4Commands::get_command_g4help(const G4UIcommand* aCommand) {
267 // Summary: Format Geant4 UI command help into a human-readable text block.
268
269 QString txt = "";
270 if (aCommand == nullptr)
271 return txt;
272
273 G4String commandPath = aCommand->GetCommandPath();
274 G4String rangeString = aCommand->GetRange();
275 G4int n_guidanceEntry = aCommand->GetGuidanceEntries();
276 G4int n_parameterEntry = aCommand->GetParameterEntries();
277
278 // If there is no meaningful content, return an empty string (keeps UI tidy).
279 if ((commandPath == "") && (rangeString == "") && (n_guidanceEntry == 0) && (n_parameterEntry == 0)) { return txt; }
280
281 // CommandPath ending with '/' denotes a directory in Geant4 UI; otherwise it's a concrete command.
282 if ((commandPath.length() - 1) != '/') { txt += "Command " + QString((char*)(commandPath).data()) + "\n"; }
283 txt += "Guidance :\n";
284
285 for (G4int i_thGuidance = 0; i_thGuidance < n_guidanceEntry; i_thGuidance++) {
286 txt += QString((char*)(aCommand->GetGuidanceLine(i_thGuidance)).data()) + "\n";
287 }
288
289 if (rangeString != "") { txt += " Range of parameters : " + QString((char*)(rangeString).data()) + "\n"; }
290
291 if (n_parameterEntry > 0) {
292 G4UIparameter* param;
293
294 // Re-implementation from G4UIparameter.cc (mirrors Geant4 formatting for consistency).
295 for (G4int i_thParameter = 0; i_thParameter < n_parameterEntry; i_thParameter++) {
296 param = aCommand->GetParameter(i_thParameter);
297 txt += "\nParameter : " + QString((char*)(param->GetParameterName()).data()) + "\n";
298 if (param->GetParameterGuidance() != "") {
299 txt += QString((char*)(param->GetParameterGuidance()).data()) + "\n";
300 }
301 txt += " Parameter type : " + QString(QChar(param->GetParameterType())) + "\n";
302
303 if (param->IsOmittable()) { txt += " Omittable : True\n"; }
304 else { txt += " Omittable : False\n"; }
305
306 if (param->GetCurrentAsDefault()) { txt += " Default value : taken from the current value\n"; }
307 else if (param->GetDefaultValue() != "") {
308 txt += " Default value : " + QString((char*)(param->GetDefaultValue()).data()) + "\n";
309 }
310
311 if (param->GetParameterRange() != "") {
312 txt += " Parameter range : " + QString((char*)(param->GetParameterRange()).data()) + "\n";
313 }
314
315 if (param->GetParameterCandidates() != "") {
316 txt += " Candidates : " + QString((char*)(param->GetParameterCandidates()).data()) + "\n";
317 }
318 }
319 }
320 return txt;
321}
G4Commands(QWidget *parent=nullptr)
Construct the commands widget.
Definition gcommands.cc:4