1 /*
2 * Copyright (c) 208 Dimitris Tassopoulos <dimtass@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 *
18 * For more information on the GPL, please go to:
19 * http://www.gnu.org/copyleft/gpl.html
20 */
21
22 #include "macrosettings.h"
23 #include <QDebug>
24 #include <QMessageBox>
25
26 #define TRACE \
27 if (!debug) { \
28 } else \
29 qDebug()
30
31 static bool debug = false;
32
33 #define MACRO_ITEM(CMD, NAME, TMR_INTERVAL, BUTTON, TMR_ACTIVE, TMR) \
34 new macro_item(CMD, NAME, TMR_INTERVAL, BUTTON, TMR_ACTIVE, TMR)
35
MacroSettings(QPushButton ** mainButtons,QWidget * parent)36 MacroSettings::MacroSettings(QPushButton **mainButtons, QWidget *parent)
37 : QDialog(parent)
38 , m_mainForm(parent)
39 {
40 setupUi(this);
41 this->setWindowTitle("Macro Settings");
42 /* Create an array of macro objects in order to make code simpler */
43 m_macros = new macro_item *[NUM_OF_BUTTONS] {
44 MACRO_ITEM(m_le_macro_txt_1, m_le_macro_bt_txt_1, m_sb_macro_tmr_1, m_bt_macro_1, m_cb_enable_macro_tmr_1,
45 new QTimer(this)),
46 MACRO_ITEM(m_le_macro_txt_2, m_le_macro_bt_txt_2, m_sb_macro_tmr_2, m_bt_macro_2, m_cb_enable_macro_tmr_2,
47 new QTimer(this)),
48 MACRO_ITEM(m_le_macro_txt_3, m_le_macro_bt_txt_3, m_sb_macro_tmr_3, m_bt_macro_3, m_cb_enable_macro_tmr_3,
49 new QTimer(this)),
50 MACRO_ITEM(m_le_macro_txt_4, m_le_macro_bt_txt_4, m_sb_macro_tmr_4, m_bt_macro_4, m_cb_enable_macro_tmr_4,
51 new QTimer(this)),
52 MACRO_ITEM(m_le_macro_txt_5, m_le_macro_bt_txt_5, m_sb_macro_tmr_5, m_bt_macro_5, m_cb_enable_macro_tmr_5,
53 new QTimer(this)),
54 MACRO_ITEM(m_le_macro_txt_6, m_le_macro_bt_txt_6, m_sb_macro_tmr_6, m_bt_macro_6, m_cb_enable_macro_tmr_6,
55 new QTimer(this)),
56 MACRO_ITEM(m_le_macro_txt_7, m_le_macro_bt_txt_7, m_sb_macro_tmr_7, m_bt_macro_7, m_cb_enable_macro_tmr_7,
57 new QTimer(this)),
58 MACRO_ITEM(m_le_macro_txt_8, m_le_macro_bt_txt_8, m_sb_macro_tmr_8, m_bt_macro_8, m_cb_enable_macro_tmr_8,
59 new QTimer(this)),
60 MACRO_ITEM(m_le_macro_txt_9, m_le_macro_bt_txt_9, m_sb_macro_tmr_9, m_bt_macro_9, m_cb_enable_macro_tmr_9,
61 new QTimer(this)),
62 MACRO_ITEM(m_le_macro_txt_10, m_le_macro_bt_txt_10, m_sb_macro_tmr_10, m_bt_macro_10,
63 m_cb_enable_macro_tmr_10, new QTimer(this)),
64 MACRO_ITEM(m_le_macro_txt_11, m_le_macro_bt_txt_11, m_sb_macro_tmr_11, m_bt_macro_11,
65 m_cb_enable_macro_tmr_11, new QTimer(this)),
66 MACRO_ITEM(m_le_macro_txt_12, m_le_macro_bt_txt_12, m_sb_macro_tmr_12, m_bt_macro_12,
67 m_cb_enable_macro_tmr_12, new QTimer(this)),
68 MACRO_ITEM(m_le_macro_txt_13, m_le_macro_bt_txt_13, m_sb_macro_tmr_13, m_bt_macro_13,
69 m_cb_enable_macro_tmr_13, new QTimer(this)),
70 MACRO_ITEM(m_le_macro_txt_14, m_le_macro_bt_txt_14, m_sb_macro_tmr_14, m_bt_macro_14,
71 m_cb_enable_macro_tmr_14, new QTimer(this)),
72 MACRO_ITEM(m_le_macro_txt_15, m_le_macro_bt_txt_15, m_sb_macro_tmr_15, m_bt_macro_15,
73 m_cb_enable_macro_tmr_15, new QTimer(this)),
74 MACRO_ITEM(m_le_macro_txt_16, m_le_macro_bt_txt_16, m_sb_macro_tmr_16, m_bt_macro_16,
75 m_cb_enable_macro_tmr_16, new QTimer(this)),
76 };
77
78 /* Setup signal/slots */
79 for (size_t i = 0; i < NUM_OF_BUTTONS; i++) {
80 /* Click events from the panel in the main menu */
81 connect(mainButtons[i], &QPushButton::clicked, this, &MacroSettings::macroPress);
82 /* events to change this dialog's buttons text */
83 connect(m_macros[i]->name, &QLineEdit::textChanged, this,
84 [=]() { m_macros[i]->button->setText(m_macros[i]->name->text()); });
85 /* events to change the buttons text on main menu */
86 connect(m_macros[i]->name, &QLineEdit::textChanged, this,
87 [=]() { mainButtons[i]->setText(m_macros[i]->name->text()); });
88 /* event handling for this dialog's buttons */
89 connect(m_macros[i]->button, &QPushButton::clicked, this, &MacroSettings::macroPress);
90 /* timer enable/disable events */
91 connect(m_macros[i]->tmr_active, &QCheckBox::stateChanged, [=](int state) {
92 if (state == Qt::Checked) {
93 m_macros[i]->tmr->stop();
94 m_macros[i]->tmr->setInterval(m_macros[i]->tmr_interval->text().toInt());
95 m_macros[i]->tmr->start();
96 TRACE << "Timer " << i << " started.";
97 } else {
98 m_macros[i]->tmr->stop();
99 TRACE << "Timer " << i << " stopped.";
100 }
101 });
102 /* timer events */
103 connect(m_macros[i]->tmr, &QTimer::timeout, [=]() { emit sendCmd(m_macros[i]->cmd->text().toLatin1()); });
104 }
105 connect(m_bt_load_macros, &QPushButton::clicked, this, &MacroSettings::openFile);
106 connect(m_bt_save_macros, &QPushButton::clicked, this, &MacroSettings::saveFile);
107 connect(m_bt_macro_help, &QPushButton::clicked, this, &MacroSettings::helpMsg);
108
109 m_lbl_macros_path->setText("");
110 }
111
~MacroSettings()112 MacroSettings::~MacroSettings()
113 {
114 if (m_macros)
115 delete[] m_macros;
116 }
117
118 /**
119 * @brief Extract the button index. That's a bit dirty way to get indexes
120 * from the buttons. For this to happen the buttons must always be named
121 * as 'm_bt_macro_' and then the index.
122 * @param btnName The button object name
123 * @return int The index of the button that corresponds to m_macros[]
124 */
getButtonIndex(QString btnName)125 int MacroSettings::getButtonIndex(QString btnName)
126 {
127 int idx = -1;
128
129 if (btnName.startsWith("m_bt_macro_")) {
130 idx = btnName.remove("m_bt_macro_").toInt() - 1;
131 }
132 return idx;
133 }
134
135 /**
136 * @brief Sends the cmd that corresponds to the macro button
137 */
macroPress()138 void MacroSettings::macroPress()
139 {
140 QPushButton *button = qobject_cast<QPushButton *>(sender());
141 if (button) {
142 int idx = getButtonIndex(button->objectName());
143 if (idx < 0)
144 return;
145
146 /* Send macro text */
147 emit sendCmd(m_macros[idx]->cmd->text().toLatin1());
148 TRACE << "[MacroSettings] macroPress " << m_macros[idx]->button->objectName() << " : "
149 << m_macros[idx]->cmd->text();
150 }
151 }
152
153 /**
154 * @brief Load a macro file that is compatible with Br@y's terminal
155 * @param fname The filename of the *.tmf file.
156 */
loadFile(QString fname)157 void MacroSettings::loadFile(QString fname)
158 {
159 if (fname.isEmpty())
160 return;
161
162 QFile file(fname);
163
164 if (!file.open(QFile::ReadOnly | QFile::Text)) {
165 QMessageBox::critical(this, tr("Could not open file"), file.errorString());
166 return;
167 }
168 QTextStream in(&file);
169 if (parseFile(in))
170 m_lbl_macros_path->setText(fname);
171
172 file.close();
173 if (QString::compare(m_macroFilename, fname, Qt::CaseSensitive)) {
174 m_macroFilename = fname;
175 m_lbl_macros_path->setText(m_macroFilename);
176 emit fileChanged(m_macroFilename);
177 }
178 }
179
openFile()180 void MacroSettings::openFile()
181 {
182 QString fname = QFileDialog::getOpenFileName(this, tr("Open a bray's terminal macro settings file"),
183 QDir::homePath(), "Macros (*.tmf)");
184 if (!fname.isEmpty())
185 loadFile(fname);
186 }
187
188 /**
189 * @brief Parse a macro *.tmf file and fill the dialog form
190 * @param in The file text stream
191 * @return true if all gone OK, otherwise false
192 */
parseFile(QTextStream & in)193 bool MacroSettings::parseFile(QTextStream &in)
194 {
195 /* Read the first line */
196 QString line = in.readLine();
197 if (line.startsWith("# Terminal macro file v2")) {
198 for (size_t i = 0; i < NUM_OF_BUTTONS; i++) {
199 /* Get button name */
200 line = in.readLine();
201 m_macros[i]->button->setText(line);
202 m_macros[i]->name->setText(line);
203 /* Get button cmd */
204 line = in.readLine();
205 m_macros[i]->cmd->setText(line);
206 }
207 } else {
208 QMessageBox::warning(this, tr("Error"), tr("Unsupported macro file!"));
209 return false;
210 }
211 return true;
212 }
213
saveFile()214 void MacroSettings::saveFile()
215 {
216 QDir dir(QDir::homePath());
217 QString fname = QFileDialog::getSaveFileName(this, tr("Open a bray's terminal macro settings file"),
218 dir.filePath(m_macroFilename), "Macros (*.tmf)");
219 if (fname.isEmpty())
220 return;
221
222 TRACE << "Save to: " << fname;
223 QFile file(fname);
224 if (!file.open(QFile::WriteOnly | QFile::Text)) {
225 QMessageBox::warning(this, tr("Could not open file"), file.errorString());
226 return;
227 }
228 QTextStream out(&file);
229 out << "# Terminal macro file v2" << endl;
230 for (size_t i = 0; i < NUM_OF_BUTTONS; i++) {
231 out << m_macros[i]->button->text() << endl;
232 out << m_macros[i]->cmd->text() << endl;
233 }
234 out.flush();
235 file.close();
236 if (QString::compare(m_macroFilename, fname, Qt::CaseSensitive)) {
237 m_macroFilename = fname;
238 m_lbl_macros_path->setText(m_macroFilename);
239 emit fileChanged(m_macroFilename);
240 }
241 }
242
helpMsg(void)243 void MacroSettings::helpMsg(void)
244 {
245 QString help_str = tr("In order to use macros you need to need to\n"
246 "fill the serial command you want to send in\n"
247 "the first column. Then you can name the macro\n"
248 "in the second column. This name will also be\n"
249 "applied on the button label.\n\n"
250 "To trigger the macro you can press the button\n"
251 "on this dialog or in the main interface.\n\n"
252 "If you want to auto-trigger the macro on time\n"
253 "intervals then you can set the (msec) timer\n"
254 "interval and then enable/disable the macro timer\n"
255 "using the checkbox. Note that each timer is\n"
256 "autonomous.\n\n"
257 "The macro format is compatible with the tmf\n"
258 "format of Bray's terminal.");
259
260 QMessageBox::information(this, tr("How to use"), help_str);
261 }
262