Bugfix
[ussd-widget] / ussd4all / src / qussd.cpp
1 #include <QtGui>
2 #include <QSignalMapper>
3 #include <iostream>
4 #include <string.h>
5 #include <libintl.h>
6
7 #define PROCESSING "Processing..."
8
9 class QUssd : public QMainWindow {
10         Q_OBJECT
11
12         public:
13                 QUssd(QString message, bool lock = false) {
14                         initOrientation();
15
16                         replyLabel = new QTextEdit(message);
17                         replyLabel->setMinimumWidth(400);
18                         replyLabel->setMinimumHeight(200);
19                         replyLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
20                         replyLabel->setFrameStyle(QFrame::NoFrame);
21                         QPalette pal = palette();
22                         pal.setColor(QPalette::Base, Qt::transparent);
23                         pal.setColor(QPalette::Text, pal.color(QPalette::ButtonText));
24                         replyLabel->setPalette(pal);
25                         replyLabel->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
26                         
27                         numberLabel = new QLabel();
28                         numberLabel->setMinimumWidth(400);
29                         numberLabel->setMaximumHeight(100);
30                         numberLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
31
32                         indicationLayout = new QVBoxLayout;
33                         indicationLayout->addWidget(numberLabel);
34
35                         indicationLayout->addWidget(replyLabel);
36
37                         padDel = new QPushButton("C");
38                         connect(padDel, SIGNAL(clicked()), this, SLOT(del()));
39                         padDel->setMaximumWidth(150);
40                         padDel->setMaximumHeight(72);
41                         padDel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
42                         padSend = new QPushButton("SEND");
43                         connect(padSend, SIGNAL(clicked()), this, SLOT(send()));
44                         padSend->setMaximumWidth(300);
45                         padSend->setMaximumHeight(72);
46                         padSend->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
47
48                         btnLayout = new QHBoxLayout;
49                         btnLayout->addWidget(padSend);
50                         btnLayout->addWidget(padDel);
51
52                         numberPad = new QGridLayout();
53                         numberPad->setSpacing(2);
54
55                         QSignalMapper *signalMapper = new QSignalMapper(this);
56
57                         numberPad->addWidget(createButton("1", signalMapper), 0, 0);
58                         numberPad->addWidget(createButton("2", signalMapper), 0, 1);
59                         numberPad->addWidget(createButton("3", signalMapper), 0, 2);
60                         numberPad->addWidget(createButton("4", signalMapper), 1, 0);
61                         numberPad->addWidget(createButton("5", signalMapper), 1, 1);
62                         numberPad->addWidget(createButton("6", signalMapper), 1, 2);
63                         numberPad->addWidget(createButton("7", signalMapper), 2, 0);
64                         numberPad->addWidget(createButton("8", signalMapper), 2, 1);
65                         numberPad->addWidget(createButton("9", signalMapper), 2, 2);
66                         numberPad->addWidget(createButton("0", signalMapper), 3, 1);
67                         numberPad->addWidget(createButton("#", signalMapper), 3, 2);
68
69                         connect(signalMapper, SIGNAL(mapped(QString)), this, SLOT(appendToNumber(QString)));
70                                                                         
71                         padBtnStar = new QPushButton("*+");
72                         connect(padBtnStar, SIGNAL(clicked()), this, SLOT(addStar()));
73                         padBtnStar->setMaximumWidth(150);
74                         padBtnStar->setMaximumHeight(72);
75                         padBtnStar->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
76                         numberPad->addWidget(padBtnStar, 3, 0);
77
78                         centralWidget = new QWidget;
79                         setCentralWidget(centralWidget);
80                         mainLayout = new QGridLayout(centralWidget);
81
82                         connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(orientationChanged()));
83                         setOrientation();
84                         orientationChanged();
85
86                         startUSSD (lock);
87                 }
88
89                 ~QUssd () {
90                         USSDquery->write("exit\n");
91                         USSDquery->closeWriteChannel();
92                         USSDquery->waitForFinished();
93
94                         delete USSDquery;
95                 }
96
97         private slots:
98                 QPushButton* createButton(QString caption, QSignalMapper *signalMapper) {
99                         QPushButton *button = new QPushButton(caption);
100                         signalMapper->setMapping(button, caption);
101                         connect(button, SIGNAL(clicked()), signalMapper, SLOT (map()));
102                         button->setMaximumWidth(150);
103                         button->setMaximumHeight(72);
104                         button->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
105                         return button;
106                 }
107
108                 void initOrientation() {
109                         QActionGroup *filterGroup = new QActionGroup(this);
110                         filterGroup->setExclusive(true);
111
112                         actPortrait = new QAction(tr("Portrait"), filterGroup);
113                         actPortrait->setCheckable(true);
114
115                         actLandscape = new QAction(tr("Landscape"), filterGroup);
116                         actLandscape->setCheckable(true);
117
118                         actAuto = new QAction(tr("Auto"), filterGroup);
119                         actAuto->setCheckable(true);
120                         actAuto->setChecked(true);
121                 
122                         menuBar()->addActions(filterGroup->actions());
123
124                         connect(actPortrait, SIGNAL(changed()), this, SLOT(setOrientation()));
125                         connect(actLandscape, SIGNAL(changed()), this, SLOT(setOrientation()));
126                         connect(actAuto, SIGNAL(changed()), this, SLOT(setOrientation()));
127                 }
128
129                 void restartUSSD( int, QProcess::ExitStatus) {
130                         replyLabel->setText(QString("Error: ")+QString::fromUtf8(reply));
131                         reply = "";
132                         number = "";
133                         setNumber();
134
135                         delete USSDquery;
136                         startUSSD ();
137                 }
138
139
140                 void send() {   
141                         USSDquery->write(number.toUtf8().data());
142                         USSDquery->write("\n");
143                         number = tr(PROCESSING);
144                         setNumber();
145                 }
146
147                 void readData() {
148                         QByteArray line;
149                         for (line = USSDquery->readLine(); !line.isEmpty(); line = USSDquery->readLine()) {
150                                 reply += line;
151                                 if (reply.endsWith("\n==MESSAGE END ==\n")) {
152                                         reply.chop(strlen("\n==MESSAGE END ==\n"));
153                                         if (!reply.isEmpty())
154                                                 replyLabel->setText(QString::fromUtf8(reply));
155                                         reply = "";
156                                         number = "";
157                                         setNumber();
158                                         break;
159                                 }
160                         }
161                 }
162
163                 void setOrientation() {
164                         if (actLandscape->isChecked())
165                                 setAttribute(Qt::WA_Maemo5LandscapeOrientation, true);
166                         else if (actPortrait->isChecked())
167                                 setAttribute(Qt::WA_Maemo5PortraitOrientation, true);
168                         else
169                                 setAttribute(Qt::WA_Maemo5AutoOrientation, true);
170                 }
171
172                 void orientationChanged() {
173                         QRect screenGeometry = QApplication::desktop()->screenGeometry();
174                         mainLayout->removeItem(indicationLayout);
175                         mainLayout->removeItem(numberPad);
176                         mainLayout->removeItem(btnLayout);
177                         
178                         if (screenGeometry.width() > screenGeometry.height()) {
179                                 mainLayout->addLayout(indicationLayout, 0, 0);
180                                 mainLayout->addLayout(btnLayout, 1, 0);
181                                 mainLayout->addLayout(numberPad, 0, 1, -1, 1);
182                         } else {
183                                 mainLayout->addLayout(indicationLayout, 0, 0);
184                                 mainLayout->addLayout(numberPad, 1, 0);
185                                 mainLayout->addLayout(btnLayout, 2, 0);
186                         }
187                 }
188         
189                 void appendToNumber (QString str) {
190                         if (number != tr(PROCESSING)) {
191                                 number += str;
192                                 setNumber();
193                         }
194                 }
195
196                 void addStar () {
197                         if (number != tr(PROCESSING)) {
198                                 // Do not change star if it was created more than 3 seconds before.
199                                 if (number[number.length()-1] == '*' && lastStar.elapsed() < 3*1000) {
200                                         number[number.length()-1] = '+';
201                                 } else {
202                                         number += "*";
203                                         lastStar = QTime();
204                                         lastStar.start();
205                                 }
206                                 setNumber();
207                         }
208                 }
209
210                 void del () {
211                         if (number != tr(PROCESSING)) {
212                                 number.chop(1);
213                                 setNumber();
214                         }
215                 }
216
217         private:
218                 void startUSSD (bool lock = false) {
219                         QString program = "ussdquery.py";
220                         QStringList arguments;
221                         arguments << "interactive" << "-d" << "\n==MESSAGE END ==\n";
222                         if (lock)
223                                 arguments << "-m";
224
225                         USSDquery = new QProcess();
226                         USSDquery->setProcessChannelMode(QProcess::MergedChannels);
227                         connect(USSDquery, SIGNAL(readyReadStandardOutput()), this, SLOT(readData()));
228                         connect(USSDquery, SIGNAL(readyReadStandardError()), this, SLOT(readData()));
229                         connect(USSDquery, SIGNAL(finished( int, QProcess::ExitStatus )), this, SLOT(restartUSSD( int, QProcess::ExitStatus )));
230
231                         USSDquery->start(program, arguments);
232                 }
233
234                 void setNumber () {
235                         numberLabel->setText(QString("<p style=\"font-size: 30pt;\" align=\"center\">")+number+"</p>");
236                 }
237
238                 QAction *actPortrait;
239                 QAction *actLandscape;
240                 QAction *actAuto;
241
242                 QTextEdit *replyLabel;
243                 QLabel *numberLabel;
244
245                 QVBoxLayout *indicationLayout;
246                 QHBoxLayout *btnLayout;
247                 QGridLayout *numberPad;
248                 QGridLayout *mainLayout;
249                 QWidget* centralWidget;
250
251                 QPushButton *padBtnStar;
252
253                 QPushButton *padDel;
254                 QPushButton *padSend;
255
256                 QProcess *USSDquery;
257
258                 QString number;
259                 QByteArray reply;
260
261                 QTime lastStar;
262 };
263
264 int main(int argc, char *argv[]) {
265         QApplication app(argc, argv);
266
267         bool lock = false;
268         QString message;
269         if (argc >= 2)
270                 message = message.fromUtf8(argv[1]);
271         if (argc >=3 && !strcmp(argv[2], "lock"))
272                 lock = true;
273
274         // If no reply is expected just show notification box
275         if (!lock && !message.isEmpty()) {
276                 QMessageBox box(QMessageBox::NoIcon, QString::fromUtf8(dgettext("rtcom-call-ui", "call_ti_message")), message, QMessageBox::Ok);
277                 box.button(QMessageBox::Ok)->setText(QString::fromUtf8(dgettext("hildon-libs", "wdgt_bd_done")));
278                 return box.exec();
279         } else {
280                 QUssd w(message, lock);
281                 w.show();
282         
283                 return app.exec();
284         }
285 }
286
287 #include "qussd.moc"