Repository navigation
Expand file tree
/
Copy pathStackCodeController.java
More file actions
428 lines (365 loc) · 16.2 KB
/
Copy pathStackCodeController.java
File metadata and controls
428 lines (365 loc) · 16.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
package com.simulator;
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import javafx.util.Duration;
import javafx.animation.Timeline;
import javafx.animation.KeyFrame;
import org.kordamp.ikonli.javafx.FontIcon;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
public class StackCodeController implements Initializable {
// FXML Components
@FXML private BorderPane rootPane;
@FXML private VBox headerContainer;
@FXML private TextField searchField;
@FXML private SplitPane mainSplitPane;
@FXML private ScrollPane categoryScrollPane;
@FXML private VBox categoryContainer;
@FXML private VBox codeDisplayContainer;
@FXML private VBox codeHeaderSection;
@FXML private VBox codeAreaSection;
@FXML private VBox codeFooterSection;
@FXML private Label codeTitle;
@FXML private Label codeDescription;
@FXML private TextArea codeTextArea;
@FXML private Label codeStats;
@FXML private Label copyStatus;
@FXML private Button copyButton;
@FXML private Button wrapTextButton;
@FXML private Button expandAllBtn;
@FXML private Button collapseAllBtn;
// Data and State
private StackController parentController;
private StackCodeRepository codeRepository;
private Map<String, CategoryTile> categoryTiles = new HashMap<>();
private List<String> allExamples = new ArrayList<>();
// 🎯 CRITICAL: Scene reference for theme management
private Scene popupScene;
private boolean isSceneRegistered = false;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
System.out.println("StackCodeController initialized");
codeRepository = new StackCodeRepository();
setupSearchFunctionality();
createCategoryTiles();
setupEventHandlers();
showWelcomeMessage();
// 🎯 CRITICAL: Register with ThemeManager after scene is ready
Platform.runLater(this::registerWithThemeManager);
}
public void setParentController(StackController parentController) {
this.parentController = parentController;
}
/**
* 🎯 CRITICAL: Register popup scene with ThemeManager for live theme updates
*/
private void registerWithThemeManager() {
if (rootPane.getScene() == null) {
Platform.runLater(this::registerWithThemeManager);
return;
}
try {
popupScene = rootPane.getScene();
ThemeManager.getInstance().registerScene(popupScene);
isSceneRegistered = true;
// Apply current theme immediately
applyCurrentTheme();
System.out.println("✅ StackCodeController registered with ThemeManager");
} catch (Exception e) {
System.err.println("❌ Failed to register with ThemeManager: " + e.getMessage());
}
}
/**
* 🎯 CRITICAL: Apply current theme from ThemeManager
*/
private void applyCurrentTheme() {
if (popupScene == null) return;
try {
boolean isDarkMode = ThemeManager.getInstance().isDarkMode();
String themeClass = isDarkMode ? "dark-theme" : "light-theme";
String removeClass = isDarkMode ? "light-theme" : "dark-theme";
// Apply theme to scene root
popupScene.getRoot().getStyleClass().removeAll(removeClass);
popupScene.getRoot().getStyleClass().add(themeClass);
// Apply theme to popup root
rootPane.getStyleClass().removeAll(removeClass);
rootPane.getStyleClass().add(themeClass);
// Update category tiles
categoryTiles.values().forEach(tile -> tile.useThemeClasses(isDarkMode));
// Force CSS refresh
Platform.runLater(() -> {
popupScene.getRoot().applyCss();
rootPane.applyCss();
});
System.out.println("🎨 Theme applied to popup: " + (isDarkMode ? "Dark" : "Light"));
} catch (Exception e) {
System.err.println("❌ Error applying theme: " + e.getMessage());
}
}
/**
* Create modern category tiles using CSS variables
*/
private void createCategoryTiles() {
CategoryInfo[] categories = {
new CategoryInfo("📚 Basic Operations", "#3b82f6", new String[]{
"Create Stack", "Push Operation", "Pop Operation", "Peek Operation"
}),
new CategoryInfo("🔧 Stack Management", "#10b981", new String[]{
"Stack Overflow Check", "Stack Underflow Check", "Size Management", "Clear Stack"
}),
new CategoryInfo("🚀 Stack Applications", "#f59e0b", new String[]{
"Stack Applications", "Balanced Parentheses", "String Reversal", "Expression Evaluation"
}),
new CategoryInfo("⚡ Advanced Operations", "#8b5cf6", new String[]{
"Multi Stack", "Stack with Min", "Stack Iterator", "Stack Clone"
})
};
for (CategoryInfo categoryInfo : categories) {
CategoryTile tile = new CategoryTile(categoryInfo, this::loadCodeExample);
categoryTiles.put(categoryInfo.name, tile);
categoryContainer.getChildren().add(tile.getContainer());
// Add all examples to searchable list
for (String example : categoryInfo.examples) {
allExamples.add(example);
}
}
}
private void setupSearchFunctionality() {
searchField.textProperty().addListener((obs, oldText, newText) -> {
filterCategories(newText.toLowerCase().trim());
});
}
private void filterCategories(String searchTerm) {
if (searchTerm.isEmpty()) {
categoryTiles.values().forEach(tile -> tile.setVisible(true));
} else {
categoryTiles.values().forEach(tile -> {
boolean hasMatch = tile.containsExample(searchTerm);
tile.setVisible(hasMatch);
tile.filterExamples(searchTerm);
});
}
}
private void setupEventHandlers() {
copyStatus.textProperty().addListener((obs, oldText, newText) -> {
if (!newText.isEmpty()) {
Timeline hideStatus = new Timeline(new KeyFrame(Duration.seconds(3), e -> copyStatus.setText("")));
hideStatus.play();
}
});
codeTextArea.textProperty().addListener((obs, oldText, newText) -> {
Platform.runLater(() -> {
codeTextArea.positionCaret(0);
codeTextArea.setScrollTop(0);
});
});
}
private void loadCodeExample(String exampleName) {
StackCodeRepository.CodeExample example = codeRepository.getCodeExample(exampleName);
if (example != null) {
codeTitle.setText("📄 " + example.getTitle());
codeDescription.setText(example.getDescription());
codeTextArea.setText(example.getCode());
String[] lines = example.getCode().split("\n");
codeStats.setText(String.format("Lines: %d | Characters: %d | Complexity: %s",
lines.length, example.getCode().length(), example.getComplexity()));
copyButton.setDisable(false);
if (parentController != null) {
parentController.logOperation("STACK_CODE_VIEWED | " + example.getTitle());
}
}
}
private void showWelcomeMessage() {
codeTitle.setText("📚 Stack Code Repository");
codeDescription.setText("Welcome to the comprehensive Stack code examples collection. " +
"Browse categories below or use the search bar to find specific implementations.");
codeTextArea.setText(codeRepository.getWelcomeMessage());
codeStats.setText("Ready to explore Stack implementations");
copyButton.setDisable(true);
}
@FXML
private void copyCodeToClipboard() {
String codeText = codeTextArea.getText();
if (!codeText.isEmpty()) {
try {
Clipboard clipboard = Clipboard.getSystemClipboard();
ClipboardContent content = new ClipboardContent();
content.putString(codeText);
clipboard.setContent(content);
copyStatus.setText("✅ Code copied to clipboard!");
copyStatus.getStyleClass().removeAll("error-text");
copyStatus.getStyleClass().add("success-text");
if (parentController != null) {
parentController.logOperation("STACK_CODE_COPIED | " + codeTitle.getText());
}
} catch (Exception e) {
copyStatus.setText("❌ Failed to copy code");
copyStatus.getStyleClass().removeAll("success-text");
copyStatus.getStyleClass().add("error-text");
}
}
}
@FXML
private void toggleWordWrap() {
boolean currentWrap = codeTextArea.isWrapText();
codeTextArea.setWrapText(!currentWrap);
if (!currentWrap) {
wrapTextButton.setText("Unwrap");
wrapTextButton.setGraphic(new FontIcon("fas-align-justify"));
copyStatus.setText("📝 Word wrap enabled - lines break automatically");
} else {
wrapTextButton.setText("Wrap");
wrapTextButton.setGraphic(new FontIcon("fas-align-left"));
copyStatus.setText("📝 Word wrap disabled - scroll horizontally for long lines");
}
copyStatus.getStyleClass().removeAll("error-text", "success-text");
copyStatus.getStyleClass().add("info-text");
}
@FXML
private void expandAllCategories() {
categoryTiles.values().forEach(tile -> tile.setExpanded(true));
copyStatus.setText("🌳 All categories expanded");
copyStatus.getStyleClass().removeAll("error-text", "success-text");
copyStatus.getStyleClass().add("info-text");
}
@FXML
private void collapseAllCategories() {
categoryTiles.values().forEach(tile -> tile.setExpanded(false));
copyStatus.setText("🌲 All categories collapsed");
copyStatus.getStyleClass().removeAll("error-text", "success-text");
copyStatus.getStyleClass().add("info-text");
}
@FXML
private void closePopup() {
// 🎯 CRITICAL: Unregister from ThemeManager before closing
cleanup();
Stage stage = (Stage) rootPane.getScene().getWindow();
stage.close();
if (parentController != null) {
parentController.logOperation("STACK_CODES_POPUP_CLOSED | Stack code examples window closed");
}
}
/**
* 🎯 CRITICAL: Cleanup method to unregister from ThemeManager
*/
public void cleanup() {
try {
if (isSceneRegistered && popupScene != null) {
ThemeManager.getInstance().unregisterScene(popupScene);
isSceneRegistered = false;
System.out.println("🧹 StackCodeController unregistered from ThemeManager");
}
} catch (Exception e) {
System.err.println("❌ Error during cleanup: " + e.getMessage());
}
}
// Inner Classes
private static class CategoryInfo {
final String name;
final String color;
final String[] examples;
CategoryInfo(String name, String color, String[] examples) {
this.name = name;
this.color = color;
this.examples = examples;
}
}
/**
* Category tile using CSS variables only
*/
private static class CategoryTile {
private final VBox container;
private final HBox headerBox;
private final VBox contentBox;
private final Label titleLabel;
private final FontIcon expandIcon;
private final CategoryInfo categoryInfo;
private final List<Button> exampleButtons = new ArrayList<>();
private boolean isExpanded = true;
public CategoryTile(CategoryInfo categoryInfo, java.util.function.Consumer<String> onExampleClick) {
this.categoryInfo = categoryInfo;
// Create main container with CSS classes only
container = new VBox();
container.setSpacing(0);
container.getStyleClass().addAll("control-panel", "rounded");
// Create header
headerBox = new HBox();
headerBox.setAlignment(Pos.CENTER_LEFT);
headerBox.setSpacing(10);
headerBox.setPadding(new Insets(15, 15, 15, 15));
headerBox.getStyleClass().add("category-header");
headerBox.setStyle("-fx-cursor: hand;");
titleLabel = new Label(categoryInfo.name);
titleLabel.getStyleClass().add("category-title");
expandIcon = new FontIcon("fas-chevron-down");
expandIcon.setIconSize(12);
expandIcon.getStyleClass().add("expand-icon");
Region spacer = new Region();
HBox.setHgrow(spacer, Priority.ALWAYS);
headerBox.getChildren().addAll(titleLabel, spacer, expandIcon);
// Create content area
contentBox = new VBox();
contentBox.setSpacing(8);
contentBox.setPadding(new Insets(0, 15, 15, 15));
contentBox.getStyleClass().add("category-content");
// Add example buttons
for (String example : categoryInfo.examples) {
Button exampleBtn = new Button(example);
exampleBtn.getStyleClass().addAll("control-button", "example-button");
exampleBtn.setMaxWidth(Double.MAX_VALUE);
exampleBtn.setAlignment(Pos.CENTER_LEFT);
exampleBtn.setOnAction(e -> onExampleClick.accept(example));
exampleButtons.add(exampleBtn);
contentBox.getChildren().add(exampleBtn);
}
headerBox.setOnMouseClicked(e -> toggleExpanded());
container.getChildren().addAll(headerBox, contentBox);
}
public VBox getContainer() { return container; }
public void setExpanded(boolean expanded) {
isExpanded = expanded;
contentBox.setVisible(expanded);
contentBox.setManaged(expanded);
expandIcon.setIconLiteral(expanded ? "fas-chevron-down" : "fas-chevron-right");
}
public void toggleExpanded() { setExpanded(!isExpanded); }
public boolean containsExample(String searchTerm) {
return titleLabel.getText().toLowerCase().contains(searchTerm) ||
java.util.Arrays.stream(categoryInfo.examples)
.anyMatch(example -> example.toLowerCase().contains(searchTerm));
}
public void filterExamples(String searchTerm) {
for (int i = 0; i < exampleButtons.size(); i++) {
Button btn = exampleButtons.get(i);
boolean matches = categoryInfo.examples[i].toLowerCase().contains(searchTerm);
btn.setVisible(matches);
btn.setManaged(matches);
}
}
public void setVisible(boolean visible) {
container.setVisible(visible);
container.setManaged(visible);
}
/**
* No manual theme classes needed - CSS variables handle everything
*/
public void useThemeClasses(boolean isDarkMode) {
// CSS variables handle all the theming automatically
}
}
}