summaryrefslogtreecommitdiff
authorpaule <paule>2007-02-07 10:25:00 (UTC)
committer paule <paule>2007-02-07 10:25:00 (UTC)
commit6629be2c0147283023abcf021227bf74ca18849f (patch) (unidiff)
treeed90c015aa96f199ec92fd930c0208e69098b941
parentd7a838e0f4352522fb2c12feea58129b16e76b89 (diff)
downloadopie-6629be2c0147283023abcf021227bf74ca18849f.zip
opie-6629be2c0147283023abcf021227bf74ca18849f.tar.gz
opie-6629be2c0147283023abcf021227bf74ca18849f.tar.bz2
Implement learning process (requires patched irrecord with stdout buffering disabled)
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/tools/remote/recorddialog.cpp234
-rw-r--r--noncore/tools/remote/recorddialog.h29
2 files changed, 231 insertions, 32 deletions
diff --git a/noncore/tools/remote/recorddialog.cpp b/noncore/tools/remote/recorddialog.cpp
index a9c4c61..3d21fad 100644
--- a/noncore/tools/remote/recorddialog.cpp
+++ b/noncore/tools/remote/recorddialog.cpp
@@ -1,6 +1,6 @@
1/* 1/*
2Opie-Remote. emulates remote controlls on an iPaq (and maybe a Zaurus) in Opie. 2Opie-Remote. emulates remote controlls on an iPaq (and maybe a Zaurus) in Opie.
3Copyright (C) 2002 Thomas Stephens 3Copyright (C) 2007 Paul Eggleton & Thomas Stephens
4 4
5This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public 5This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public
6License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later 6License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later
@@ -14,18 +14,30 @@ You should have received a copy of the GNU General Public License along with thi
14Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 14Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15*/ 15*/
16 16
17#include <stdlib.h>
18#include <sys/stat.h>
19
20#include <qfile.h>
21
17#include "recorddialog.h" 22#include "recorddialog.h"
18 23
24#define RECORD_TMPDIR "/tmp/opie-remote"
25
19using namespace Opie::Core; 26using namespace Opie::Core;
20using namespace Opie::Core; 27using namespace Opie::Core;
21RecordDialog::RecordDialog(QWidget *parent, const char *name) 28RecordDialog::RecordDialog(QWidget *parent, const char *name)
22 :QDialog(parent, name) 29 :QDialog(parent, name, TRUE)
23{ 30{
24 QVBoxLayout *layout = new QVBoxLayout(this); 31 QVBoxLayout *layout = new QVBoxLayout(this);
25 QHBoxLayout *hlayout = new QHBoxLayout(this); 32 QHBoxLayout *hlayout = new QHBoxLayout(this);
26 33
27 layout->insertSpacing(0,5); 34 layout->insertSpacing(0,5);
28 output = new QTextView("Please enter the name of the new remote, and press Return\n", 0, this, "output"); 35
36 output = new QMultiLineEdit(this, "output");
37 output->setReadOnly(true);
38 output->setWordWrap(QMultiLineEdit::WidgetWidth);
39 output->setText(tr("Please enter the name of the new remote, and press Next\n"));
40
29 layout->insertWidget(-1, output); 41 layout->insertWidget(-1, output);
30 layout->insertSpacing(-1, 5); 42 layout->insertSpacing(-1, 5);
31 layout->insertLayout(-1, hlayout); 43 layout->insertLayout(-1, hlayout);
@@ -36,49 +48,215 @@ RecordDialog::RecordDialog(QWidget *parent, const char *name)
36 hlayout->insertWidget(-1, input, 1); 48 hlayout->insertWidget(-1, input, 1);
37 hlayout->insertSpacing(-1, 5); 49 hlayout->insertSpacing(-1, 5);
38 50
39 QPushButton *ret = new QPushButton("Return", this, "return"); 51 nextbtn = new QPushButton(tr("Next"), this, "next");
40 hlayout->insertWidget(-1, ret); 52 nextbtn->setDefault(true);
53 hlayout->insertWidget(-1, nextbtn);
41 hlayout->insertSpacing(-1, 5); 54 hlayout->insertSpacing(-1, 5);
42 connect(ret, SIGNAL(clicked()), this, SLOT(retPressed()) ); 55 connect(nextbtn, SIGNAL(clicked()), this, SLOT(nextPressed()) );
43 where = 0; 56
44 57 setCaption(tr("Learn Remote"));
58 input->setFocus();
59
60 stepnum = 0;
61 outputenabled = false;
62 writeok = true;
63 ignorekill = false;
64
45 record = new OProcess; 65 record = new OProcess;
66
67 // We need to stop lircd because irrecord accesses the IR device directly
68 lh = new LircHandler();
69 lh->stopLircd();
46} 70}
47 71
48void RecordDialog::retPressed() 72RecordDialog::~RecordDialog(void)
49{ 73{
50 printf("RecordDialog::retPressed: ret pressed\n"); 74 delete lh;
75 delete record;
76}
51 77
52 if(where == 0) 78void RecordDialog::nextPressed()
53 { 79{
80 if(stepnum == 0) {
81 QString remotename = input->text().stripWhiteSpace();
82
83 if(remotename == "") {
84 QMessageBox::warning(this, tr("Error"),
85 tr("Please enter a name"),
86 QMessageBox::Ok, QMessageBox::NoButton);
87 return;
88 }
89
90 if(remotename.left(1) == ".") {
91 QMessageBox::warning(this, tr("Error"),
92 tr("Name cannot start with a dot"),
93 QMessageBox::Ok, QMessageBox::NoButton);
94 return;
95 }
96
97 // Check for invalid chars
98 QRegExp invalidchars = QRegExp("[~\\[\\]/'\"|\\\\]", TRUE, FALSE);
99 if(remotename.find(invalidchars) > -1) {
100 QMessageBox::warning(this, tr("Error"),
101 tr("The name %1 contains\ninvalid characters").arg(remotename),
102 QMessageBox::Ok, QMessageBox::NoButton);
103 return;
104 }
105
106 // Check if name already exists in config
107 if(lh->checkRemoteExists(remotename)) {
108 QMessageBox::warning(this, tr("Error"),
109 tr("A remote named %1\nalready exists.").arg(remotename),
110 QMessageBox::Ok, QMessageBox::NoButton);
111 return;
112 }
113
114 printf("RecordDialog::nextPressed: starting irrecord\n");
115 input->setEnabled(false);
116
54 connect(record, SIGNAL(receivedStdout(Opie::Core::OProcess*,char*,int)), this, SLOT(incoming(Opie::Core::OProcess*,char*,int)) ); 117 connect(record, SIGNAL(receivedStdout(Opie::Core::OProcess*,char*,int)), this, SLOT(incoming(Opie::Core::OProcess*,char*,int)) );
55 connect(record, SIGNAL(receivedStderr(Opie::Core::OProcess*,char*,int)), this, SLOT(incoming(Opie::Core::OProcess*,char*,int)) ); 118 connect(record, SIGNAL(receivedStderr(Opie::Core::OProcess*,char*,int)), this, SLOT(incomingErr(Opie::Core::OProcess*,char*,int)) );
56 connect(record, SIGNAL(processExited(Opie::Core::OProcess*)), this, SLOT(done(Opie::Core::OProcess*)) ); 119 connect(record, SIGNAL(processExited(Opie::Core::OProcess*)), this, SLOT(done(Opie::Core::OProcess*)) );
57 printf("RecordDialog::retPressed: starting irrecord\n"); 120 connect(record, SIGNAL(wroteStdin(Opie::Core::OProcess*)), this, SLOT(writeFinished(Opie::Core::OProcess*)) );
58 QString file = "/tmp/" + input->text(); 121
59 *record<<"irrecord"<<file.latin1(); 122 // Prepare temp path
60 if(!record->start(OProcess::NotifyOnExit, OProcess::AllOutput)) 123 QString tmpdir = RECORD_TMPDIR;
124 mkdir(tmpdir, 0700);
125 remotefile = tmpdir + "/" + remotename;
126 if(QFile::exists(remotefile))
127 QFile::remove(remotefile);
128
129 // Set up and start irrecord
130 *record<<"irrecord"<<remotename.latin1();
131 record->setWorkingDirectory(tmpdir);
132 if(!record->start(OProcess::NotifyOnExit, OProcess::All))
61 { 133 {
62 QMessageBox *mb = new QMessageBox("Error!", 134 QMessageBox::critical(this, tr("Error"),
63 "Could not start irrecord. You must<br>use an lirc ipkg that includes<br>irrecord", 135 tr("Failed to start irrecord."),
64 QMessageBox::NoIcon, 136 QMessageBox::Ok, QMessageBox::NoButton);
65 QMessageBox::Ok,
66 QMessageBox::NoButton,
67 QMessageBox::NoButton);
68 mb->exec();
69 return; 137 return;
70 } 138 }
71 // record->resume(); 139 stepnum = 1;
72 where = 1; 140 writeToProcess("\n", 1);
141 output->setText("Please get ready to press buttons on your remote.\n\nPress many different buttons, one at a time, holding each one down for approximately one second. Each button should generate at least one dot but in no case more than ten dots of output. Don't stop pressing buttons until at least two lines of dots appear.\n\nClick Next when you are ready to begin.");
142 }
143 else if(stepnum == 1) {
144 output->setText("Press buttons now:\n");
145 output->setCursorPosition(output->numLines(), 32767);
146 outputenabled = true;
147 decoding = true;
148 writeToProcess("\n", 1);
149 nextbtn->setEnabled(false);
150 stepnum = 2;
151 }
152 else if(stepnum == 2) {
153 QString inp = input->text() + "\n";
154 writeToProcess(inp, inp.length());
155 input->clear();
73 } 156 }
74} 157}
75 158
76void RecordDialog::incoming(OProcess *proc, char *buffer, int len) 159void RecordDialog::incoming(OProcess *proc, char *buffer, int len)
77{ 160{
78 //output->setText(output->text() + QString(buffer).truncate(len-1)); 161 int line, col;
79 printf("RecordDialog::incoming: got text from irrecord\n"); 162
163 if(outputenabled) {
164 char *bufstr = strndup(buffer, len);
165 output->getCursorPosition( &line, &col );
166 output->insertAt( bufstr, line, col );
167
168 if(decoding) {
169 int pos = output->text().find("Now enter the names for the buttons");
170 if(pos > -1) {
171 output->setText(output->text().mid(pos));
172 output->setCursorPosition(output->numLines(), 32767);
173 decoding = false;
174 input->clear();
175 input->setEnabled(true);
176 nextbtn->setEnabled(true);
177 input->setFocus();
178 }
179 }
180
181 free(bufstr);
182 }
183}
184
185void RecordDialog::incomingErr(OProcess *proc, char *buffer, int len)
186{
187 char *bufstr = strndup(buffer, len);
188 errors += bufstr;
189 free(bufstr);
190}
191
192void RecordDialog::writeToProcess(const char *buffer, int len)
193{
194 while(!writeok) { }
195 // FIXME leakage
196 record->writeStdin(strndup(buffer, len), len);
197}
198
199void RecordDialog::writeFinished(Opie::Core::OProcess *proc)
200{
201 writeok = true;
80} 202}
81 203
82void RecordDialog::done(OProcess *proc) 204void RecordDialog::done(OProcess *proc)
83{ 205{
206 if(proc->normalExit() && proc->exitStatus() == 0) {
207 // Success
208
209 // Merge in new remote to lircd.conf
210 lh->mergeRemoteConfig(remotefile);
211
212 nextbtn->hide();
213 input->hide();
214 output->setText("Learning completed successfully. Click OK to close.");
215 stepnum = 4;
216 }
217 else if(!ignorekill) {
218 QMessageBox::critical(this, tr("Error"), tr("Learning failed.\n") + errors, QMessageBox::Ok, QMessageBox::NoButton);
219 }
220}
221
222void RecordDialog::accept()
223{
224 if(stepnum < 4)
225 QMessageBox::warning(this, tr("Error"), tr("Please complete the learning\n process or tap X to cancel."), QMessageBox::Ok, QMessageBox::NoButton);
226 else {
227 if(checkClose())
228 QDialog::accept();
229 }
230}
231
232void RecordDialog::reject()
233{
234 if(checkClose())
235 QDialog::reject();
236}
237
238bool RecordDialog::checkClose()
239{
240 if(!record->isRunning() || confirmClose()) {
241 if(record->isRunning()) {
242 ignorekill = true;
243 record->kill();
244 }
245 // Restart lircd
246 lh->startLircd();
247 // Delete temp file if it exists
248 if(QFile::exists(remotefile))
249 unlink(remotefile);
250 rmdir(RECORD_TMPDIR);
251
252 return true;
253 }
254 return false;
255}
256
257bool RecordDialog::confirmClose()
258{
259 return (QMessageBox::warning(this, tr("Cancel"),
260 tr("Learning is not complete.\nAre you sure you want to close?"),
261 QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes);
84} 262}
diff --git a/noncore/tools/remote/recorddialog.h b/noncore/tools/remote/recorddialog.h
index 46a82ce..e569fb6 100644
--- a/noncore/tools/remote/recorddialog.h
+++ b/noncore/tools/remote/recorddialog.h
@@ -18,31 +18,52 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18#define RecordDialog_H 18#define RecordDialog_H
19 19
20#include <qdialog.h> 20#include <qdialog.h>
21#include <qtextview.h> 21#include <qmultilineedit.h>
22#include <qlineedit.h> 22#include <qlineedit.h>
23#include <qpushbutton.h> 23#include <qpushbutton.h>
24#include <qwidget.h> 24#include <qwidget.h>
25#include <qlayout.h> 25#include <qlayout.h>
26#include <qlabel.h>
26#include <qmessagebox.h> 27#include <qmessagebox.h>
27 28
28#include <stdio.h> 29#include <stdio.h>
29 30
30#include <opie2/oprocess.h> 31#include <opie2/oprocess.h>
31 32
33#include "lirchandler.h"
34
32class RecordDialog : public QDialog 35class RecordDialog : public QDialog
33{ 36{
34 Q_OBJECT 37 Q_OBJECT
35public: 38public:
36 RecordDialog(QWidget *parent=0, const char *name=0); 39 RecordDialog(QWidget *parent=0, const char *name=0);
40 ~RecordDialog(void);
37public slots: 41public slots:
38 void retPressed(); 42 void nextPressed();
39 void incoming(Opie::Core::OProcess *proc, char *buffer, int len); 43 void incoming(Opie::Core::OProcess *proc, char *buffer, int len);
44 void incomingErr(Opie::Core::OProcess *proc, char *buffer, int len);
45 void writeFinished(Opie::Core::OProcess *proc);
40 void done(Opie::Core::OProcess *proc); 46 void done(Opie::Core::OProcess *proc);
47 void accept();
48 void reject();
49protected:
50 bool confirmClose();
51 bool checkClose();
41private: 52private:
42 QTextView *output; 53 QMultiLineEdit *output;
43 QLineEdit *input; 54 QLineEdit *input;
55 QPushButton *nextbtn;
44 Opie::Core::OProcess *record; 56 Opie::Core::OProcess *record;
45 int where; 57 int stepnum;
58 bool outputenabled;
59 bool decoding;
60 bool writeok;
61 bool ignorekill;
62 QString errors;
63 QString remotefile;
64 LircHandler *lh;
65
66 void writeToProcess(const char *buffer, int len);
46}; 67};
47 68
48#endif 69#endif