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(tr("Search Commands")));
66 v_layout->addWidget(w_search);
67 v_layout->addWidget(commands_help_splitter, /* stretch factor */ 2);
68 v_layout->addWidget(new QLabel(tr("History")));
69 v_layout->addWidget(w_history);
70 v_layout->addWidget(new QLabel(tr("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() << tr("Commands"));
92 // Add top-level command directories to the model.
93 G4int g4_commands_tree_size = g4_commands_tree->GetTreeEntry();
94 for (int a = 0; a < g4_commands_tree_size; a++) {
95 // Each top-level entry is a command directory node; children are populated recursively.
96 QStandardItem* newItem = new QStandardItem(
97 QString((char*)g4_commands_tree->GetTree(a + 1)->GetPathName().data()).trimmed());
98 model->appendRow(newItem);
99
100 // Add child directories and commands.
101 create_child_help_tree(newItem, g4_commands_tree->GetTree(a + 1));
102 }
103
104 // Read-only: prevent accidental edits to the command path strings.
105 w_commands->setEditTriggers(QAbstractItemView::NoEditTriggers);
106
107 // Selection drives help display; double-click pastes selection into the command prompt.
108 connect(w_commands->selectionModel(), &QItemSelectionModel::selectionChanged, this,
109 &G4Commands::display_help_from_selection);
110 connect(w_commands, &QTreeView::doubleClicked, this, &G4Commands::paste_help_selection_item);
111}
112
113void G4Commands::filterTreeItems() {
114 // Summary: Hide/show top-level rows depending on whether they (or their descendants) match the search string.
115
116 QString search_text = w_search->text().trimmed();
117 QStandardItemModel* model = qobject_cast<QStandardItemModel*>(w_commands->model());
118 if (!model) return;
119
120 for (int i = 0; i < model->rowCount(); ++i) {
121 QStandardItem* item = model->item(i);
122 bool showItem = filterItem(item, search_text);
123
124 // For top-level nodes we also explicitly hide the row at the root.
125 w_commands->setRowHidden(i, QModelIndex(), !showItem);
126 }
127}
128
129bool G4Commands::filterItem(QStandardItem* item, const QString& search_text) {
130 // Summary: Recursively evaluate whether this item should be visible.
131
132 // Direct match on this node.
133 bool matches = item->text().contains(search_text, Qt::CaseInsensitive);
134 bool childMatches = false;
135
136 // Check child items recursively (depth-first).
137 for (int i = 0; i < item->rowCount(); ++i) {
138 QStandardItem* childItem = item->child(i);
139 if (filterItem(childItem, search_text)) { childMatches = true; }
140 }
141
142 // Show this item if it matches or has a matching child.
143 bool showItem = matches || childMatches;
144
145 // Apply visibility at this node's location in the tree.
146 w_commands->setRowHidden(item->row(), item->index().parent(), !showItem);
147
148 return showItem;
149}
150
151void G4Commands::create_child_help_tree(QStandardItem* parent, G4UIcommandTree* aCommandTree) {
152 // Summary: Populate children for a given Geant4 tree node (sub-directories first, then leaf commands).
153
154 if (parent == nullptr || aCommandTree == nullptr) return;
155
156 // Add child directories (sub-trees).
157 for (int a = 0; a < aCommandTree->GetTreeEntry(); a++) {
158 QStandardItem* newItem = new QStandardItem(
159 QString((char*)(aCommandTree->GetTree(a + 1)->GetPathName()).data()).trimmed());
160 parent->appendRow(newItem);
161 create_child_help_tree(newItem, aCommandTree->GetTree(a + 1));
162 }
163
164 // Add commands at this node (leaf entries).
165 for (int a = 0; a < aCommandTree->GetCommandEntry(); a++) {
166 QStandardItem* newItem = new QStandardItem(
167 QString((char*)(aCommandTree->GetCommand(a + 1)->GetCommandPath()).data()).trimmed());
168 parent->appendRow(newItem);
169 }
170}
171
172void G4Commands::execute_command() {
173 // Summary: Execute the typed command through Geant4 UI manager and update history.
174
175 if (!w_command) return;
176
177 QString command = w_command->text().trimmed();
178 if (command.isEmpty()) return;
179
180 G4UImanager* ui_manager = G4UImanager::GetUIpointer();
181 ui_manager->ApplyCommand(command.toStdString().c_str());
182
183 // Avoid duplicate history entries (simple linear scan, small list expected).
184 bool exists = false;
185 for (int i = 0; i < w_history->count(); ++i) {
186 if (w_history->item(i)->text() == command) {
187 exists = true;
188 break;
189 }
190 }
191
192 if (!exists) { w_history->addItem(command); }
193
194 // Clear command field after execution to signal completion.
195 w_command->clear();
196}
197
198void G4Commands::recall_history_item_on_double_click(QListWidgetItem* item) {
199 // Summary: Load the selected history command into the input field.
200
201 if (!item) return;
202
203 // Set the command line input to the selected history item.
204 w_command->setText(item->text());
205}
206
207// paste history item onto command line
208void G4Commands::display_help_from_selection() {
209 // Summary: Determine whether selection is a command or a directory and show help/title accordingly.
210
211 if (!w_commands || !w_help) return;
212
213 QModelIndexList selectedIndexes = w_commands->selectionModel()->selectedIndexes();
214 if (selectedIndexes.isEmpty()) return;
215
216 QModelIndex index = selectedIndexes.first();
217 QStandardItemModel* model = qobject_cast<QStandardItemModel*>(w_commands->model());
218 if (!model) return;
219
220 QStandardItem* item = model->itemFromIndex(index);
221 if (!item) return;
222
223 std::string itemText = item->text().toStdString();
224 G4UIcommandTree* treeTop = G4UImanager::GetUIpointer()->GetTree();
225 G4UIcommand* command = treeTop->FindPath(itemText.c_str());
226
227 if (command) {
228 // Leaf command: show detailed guidance and parameter info.
229 w_help->setText(get_command_g4help(command));
230 }
231 else {
232 // Directory node: show the title (if found).
233 G4UIcommandTree* path = treeTop->FindCommandTree(itemText.c_str());
234 if (path) { w_help->setText(QString::fromStdString(path->GetTitle())); }
235 }
236}
237
238// display help on selected item
239void G4Commands::paste_help_selection_item() {
240 // Summary: Refresh help and paste the selected command/directory text into the prompt.
241
242 // Display help from the selection.
243 display_help_from_selection();
244
245 if (!w_commands || !w_help) { return; }
246
247 // Get the selected items from the selection model of QTreeView.
248 QModelIndexList selectedIndexes = w_commands->selectionModel()->selectedIndexes();
249 if (selectedIndexes.isEmpty()) { return; }
250
251 // Assuming the first selected item is the one to retrieve.
252 QModelIndex index = selectedIndexes.first();
253 QStandardItemModel* model = qobject_cast<QStandardItemModel*>(w_commands->model());
254 if (!model) { return; }
255
256 // Retrieve the item at the given index.
257 QStandardItem* item = model->itemFromIndex(index);
258 if (!item) { return; }
259
260 // Clear the command input field and set the selected item's text.
261 w_command->clear();
262 w_command->setText(item->text());
263}
264
265QString G4Commands::get_command_g4help(const G4UIcommand* aCommand) {
266 // Summary: Format Geant4 UI command help into a human-readable text block.
267
268 QString txt = "";
269 if (aCommand == nullptr)
270 return txt;
271
272 G4String commandPath = aCommand->GetCommandPath();
273 G4String rangeString = aCommand->GetRange();
274 G4int n_guidanceEntry = aCommand->GetGuidanceEntries();
275 G4int n_parameterEntry = aCommand->GetParameterEntries();
276
277 // If there is no meaningful content, return an empty string (keeps UI tidy).
278 if ((commandPath == "") && (rangeString == "") && (n_guidanceEntry == 0) && (n_parameterEntry == 0)) { return txt; }
279
280 // CommandPath ending with '/' denotes a directory in Geant4 UI; otherwise it's a concrete command.
281 if ((commandPath.length() - 1) != '/') { txt += tr("Command %1\n").arg(QString::fromStdString(commandPath)); }
282 txt += tr("Guidance :\n");
283 for (G4int i_thGuidance = 0; i_thGuidance < n_guidanceEntry; i_thGuidance++) {
284 txt += QString((char*)(aCommand->GetGuidanceLine(i_thGuidance)).data()) + "\n";
285 }
286 if (rangeString != "") { txt += tr(" Range of parameters : %1\n").arg(QString::fromStdString(rangeString)); }
287 if (n_parameterEntry > 0) {
288 G4UIparameter* param;
289
290 // Re-implementation from G4UIparameter.cc (mirrors Geant4 formatting for consistency).
291 for (G4int i_thParameter = 0; i_thParameter < n_parameterEntry; i_thParameter++) {
292 param = aCommand->GetParameter(i_thParameter);
293 txt += tr("\nParameter : %1\n").arg(QString::fromStdString(param->GetParameterName()));
294 if (param->GetParameterGuidance() != "") {
295 txt += QString((char*)(param->GetParameterGuidance()).data()) + "\n";
296 }
297 txt += tr(" Parameter type : %1\n").arg(QChar(param->GetParameterType()));
298 if (param->IsOmittable()) { txt += tr(" Omittable : True\n"); }
299 else { txt += tr(" Omittable : False\n"); }
300 if (param->GetCurrentAsDefault()) { txt += tr(" Default value : taken from the current value\n"); }
301 else if (param->GetDefaultValue() != "") {
302 txt += tr(" Default value : %1\n").arg(QString::fromStdString(param->GetDefaultValue()));
303 }
304
305 if (param->GetParameterRange() != "") {
306 txt += tr(" Parameter range : %1\n").arg(QString::fromStdString(param->GetParameterRange()));
307 }
308
309 if (param->GetParameterCandidates() != "") {
310 txt += tr(" Candidates : %1\n").arg(QString::fromStdString(param->GetParameterCandidates()));
311 }
312 }
313 }
314 return txt;
315}
G4Commands(QWidget *parent=nullptr)
Construct the commands widget.
Definition gcommands.cc:4