1/*
2 * Copyright 2022, Haiku. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "ThemeWindow.h"
8
9#include <stdio.h>
10
11#include <Button.h>
12#include <Catalog.h>
13#include <Directory.h>
14#include <File.h>
15#include <FilePanel.h>
16#include <FindDirectory.h>
17#include <LayoutBuilder.h>
18#include <Locale.h>
19#include <Messenger.h>
20#include <Path.h>
21#include <SeparatorView.h>
22
23#include "PrefHandler.h"
24#include "TermConst.h"
25#include "ThemeView.h"
26
27
28#undef B_TRANSLATION_CONTEXT
29#define B_TRANSLATION_CONTEXT "Terminal ThemeWindow"
30
31// local messages
32const uint32 MSG_DEFAULTS_PRESSED = 'defl';
33const uint32 MSG_SAVEAS_PRESSED = 'canl';
34const uint32 MSG_REVERT_PRESSED = 'revt';
35
36
37ThemeWindow::ThemeWindow(const BMessenger& messenger)
38	:
39	BWindow(BRect(0, 0, 0, 0), B_TRANSLATE("Colors"), B_TITLED_WINDOW,
40		B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS),
41		fPreviousPref(new PrefHandler(PrefHandler::Default())),
42		fSavePanel(NULL),
43		fDirty(false),
44		fTerminalMessenger(messenger)
45{
46	fDefaultsButton = new BButton("defaults", B_TRANSLATE("Defaults"),
47		new BMessage(MSG_DEFAULTS_PRESSED), B_WILL_DRAW);
48
49	fRevertButton = new BButton("revert", B_TRANSLATE("Revert"),
50		new BMessage(MSG_REVERT_PRESSED), B_WILL_DRAW);
51
52	fSaveAsFileButton = new BButton("savebutton",
53		B_TRANSLATE("Save to file" B_UTF8_ELLIPSIS),
54		new BMessage(MSG_SAVEAS_PRESSED), B_WILL_DRAW);
55
56	fThemeView = new ThemeView("Theme", fTerminalMessenger);
57
58	BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
59		.SetInsets(B_USE_WINDOW_SPACING)
60		.Add(fThemeView)
61		.AddGroup(B_HORIZONTAL)
62			.Add(fDefaultsButton)
63			.Add(fRevertButton)
64			.AddGlue()
65			.Add(fSaveAsFileButton)
66			.SetInsets(0, B_USE_DEFAULT_SPACING, 0, 0);
67
68	fRevertButton->SetEnabled(fDirty);
69
70	AddShortcut('Q', B_COMMAND_KEY, new BMessage(B_QUIT_REQUESTED));
71	AddShortcut('W', B_COMMAND_KEY, new BMessage(B_QUIT_REQUESTED));
72
73	CenterOnScreen();
74	Show();
75}
76
77
78void
79ThemeWindow::Quit()
80{
81	fTerminalMessenger.SendMessage(MSG_THEME_CLOSED);
82	delete fPreviousPref;
83	delete fSavePanel;
84	BWindow::Quit();
85}
86
87
88bool
89ThemeWindow::QuitRequested()
90{
91	if (fDirty)
92		_Save();
93
94	return true;
95}
96
97
98void
99ThemeWindow::_SaveAs()
100{
101	if (!fSavePanel) {
102		BMessenger messenger(this);
103		fSavePanel = new BFilePanel(B_SAVE_PANEL, &messenger);
104	}
105
106	BPath path;
107	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
108		path.Append("Terminal/Themes");
109		create_directory(path.Path(), 0755);
110		fSavePanel->SetPanelDirectory(path.Path());
111	}
112
113	fSavePanel->Show();
114}
115
116
117void
118ThemeWindow::_SaveRequested(BMessage *msg)
119{
120	entry_ref dirref;
121	const char* filename;
122
123	msg->FindRef("directory", &dirref);
124	msg->FindString("name", &filename);
125
126	BDirectory dir(&dirref);
127	BPath path(&dir, filename);
128
129	PrefHandler *prefHandler = PrefHandler::Default();
130
131	BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
132	char buffer[512];
133
134	for (const char** table = ThemeView::kColorTable; *table != NULL; ++table) {
135		int len = snprintf(buffer, sizeof(buffer), "\"%s\" , \"%s\"\n",
136			*table, prefHandler->getString(*table));
137		file.Write(buffer, len);
138	}
139
140	// Name the theme after the filename
141	int len = snprintf(buffer, sizeof(buffer), "\"%s\" , \"%s\"\n",
142		PREF_THEME_NAME, filename);
143	file.Write(buffer, len);
144
145	fThemeView->UpdateMenu();
146}
147
148
149void
150ThemeWindow::_Save()
151{
152	delete fPreviousPref;
153	fPreviousPref = new PrefHandler(PrefHandler::Default());
154
155	PrefHandler::Default()->SaveDefaultAsText();
156	fDirty = false;
157}
158
159
160void
161ThemeWindow::_Revert()
162{
163	if (fDirty) {
164		PrefHandler::SetDefault(new PrefHandler(fPreviousPref));
165
166		fThemeView->Revert();
167
168		fDirty = false;
169		fRevertButton->SetEnabled(fDirty);
170	}
171}
172
173
174void
175ThemeWindow::MessageReceived(BMessage *message)
176{
177	switch (message->what) {
178
179		case MSG_SAVEAS_PRESSED:
180			_SaveAs();
181			break;
182
183		case MSG_REVERT_PRESSED:
184			_Revert();
185			break;
186
187		case MSG_DEFAULTS_PRESSED:
188			PrefHandler::SetDefault(new PrefHandler(false));
189			fThemeView->SetDefaults();
190			// fallthrough
191
192		case MSG_THEME_MODIFIED:
193			fDirty = true;
194			fRevertButton->SetEnabled(fDirty);
195			break;
196
197		case B_SAVE_REQUESTED:
198			_SaveRequested(message);
199			break;
200
201		default:
202			BWindow::MessageReceived(message);
203			break;
204	}
205}
206