~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to kcontrol/hardware/joystick/joywidget.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *   Copyright (C) 2003 by Martin Koller                                   *
 
3
 *   m.koller@surfeu.at                                                    *
 
4
 *   This file is part of the KDE Control Center Module for Joysticks      *
 
5
 *                                                                         *
 
6
 *   This program is free software; you can redistribute it and/or modify  *
 
7
 *   it under the terms of the GNU General Public License as published by  *
 
8
 *   the Free Software Foundation; either version 2 of the License, or     *
 
9
 *   (at your option) any later version.                                   *
 
10
 *                                                                         *
 
11
 *   This program is distributed in the hope that it will be useful,       *
 
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 
14
 *   GNU General Public License for more details.                          *
 
15
 *                                                                         *
 
16
 *   You should have received a copy of the GNU General Public License     *
 
17
 *   along with this program; if not, write to the                         *
 
18
 *   Free Software Foundation, Inc.,                                       *
 
19
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
 
20
 ***************************************************************************/
 
21
#include "joywidget.h"
 
22
#include "joydevice.h"
 
23
#include "poswidget.h"
 
24
#include "caldialog.h"
 
25
 
 
26
#include <QtGui/QTableWidget>
 
27
#include <QLabel>
 
28
#include <QCheckBox>
 
29
#include <QTimer>
 
30
#include <QFontMetrics>
 
31
#include <QPushButton>
 
32
#include <QHBoxLayout>
 
33
#include <QVBoxLayout>
 
34
#include <QHeaderView>
 
35
 
 
36
#include <klocale.h>
 
37
#include <kdialog.h>
 
38
#include <kmessagebox.h>
 
39
#include <kiconloader.h>
 
40
#include <kcombobox.h>
 
41
#include <kurlcompletion.h>
 
42
 
 
43
#include <stdio.h>
 
44
#include <kvbox.h>
 
45
#include <kdebug.h>
 
46
//--------------------------------------------------------------
 
47
static QString PRESSED = I18N_NOOP("PRESSED");
 
48
//--------------------------------------------------------------
 
49
 
 
50
class TableWidget : public QTableWidget
 
51
{
 
52
  public:
 
53
    TableWidget(int row, int col) : QTableWidget(row, col) {}
 
54
 
 
55
    virtual QSize sizeHint() const
 
56
    {
 
57
      return QSize(150, 100);  // return a smaller size than the Qt default(256, 192)
 
58
    }
 
59
};
 
60
 
 
61
//--------------------------------------------------------------
 
62
 
 
63
JoyWidget::JoyWidget(QWidget *parent)
 
64
 : QWidget(parent), idle(0), joydev(0)
 
65
{
 
66
  QVBoxLayout *mainVbox = new QVBoxLayout(this);
 
67
  mainVbox->setSpacing(KDialog::spacingHint());
 
68
  mainVbox->setMargin(0);
 
69
 
 
70
  // create area to show an icon + message if no joystick was detected
 
71
  {
 
72
    messageBox = new QFrame(this);
 
73
    messageBox->setFrameStyle(QFrame::StyledPanel);
 
74
    QHBoxLayout *box = new QHBoxLayout(messageBox);
 
75
    box->setSpacing(KDialog::spacingHint());
 
76
 
 
77
    QLabel *icon = new QLabel(messageBox);
 
78
    icon->setPixmap(KIconLoader::global()->loadIcon("dialog-warning", KIconLoader::NoGroup,
 
79
                                                    KIconLoader::SizeMedium, KIconLoader::DefaultState, QStringList(), 0, true));
 
80
    icon->setFixedSize(icon->sizeHint());
 
81
    message = new QLabel(messageBox);
 
82
 
 
83
    box->addWidget(icon);
 
84
    box->addWidget(message);
 
85
 
 
86
    messageBox->hide();
 
87
 
 
88
    mainVbox->addWidget(messageBox);
 
89
  }
 
90
 
 
91
  QHBoxLayout *devHbox = new QHBoxLayout;
 
92
  devHbox->setSpacing(KDialog::spacingHint());
 
93
  devHbox->addWidget(new QLabel(i18n("Device:")));
 
94
  devHbox->addWidget(device = new KComboBox(true));
 
95
 
 
96
  device->setInsertPolicy(QComboBox::NoInsert);
 
97
  KUrlCompletion *kc = new KUrlCompletion(KUrlCompletion::FileCompletion);
 
98
  device->setCompletionObject(kc);
 
99
  device->setAutoDeleteCompletionObject(true);
 
100
  connect(device, SIGNAL(activated(const QString &)), this, SLOT(deviceChanged(const QString &)));
 
101
  connect(device, SIGNAL(returnPressed(const QString &)), this, SLOT(deviceChanged(const QString &)));
 
102
  devHbox->setStretchFactor(device, 3);
 
103
 
 
104
  QHBoxLayout *hbox = new QHBoxLayout;
 
105
  hbox->setSpacing(KDialog::spacingHint());
 
106
 
 
107
  mainVbox->addLayout(devHbox);
 
108
  mainVbox->addLayout(hbox);
 
109
 
 
110
  QVBoxLayout *vboxLeft = new QVBoxLayout;
 
111
  vboxLeft->setSpacing(KDialog::spacingHint());
 
112
  vboxLeft->addWidget(new QLabel(i18nc("Cue for deflection of the stick", "Position:")));
 
113
  vboxLeft->addWidget(xyPos = new PosWidget);
 
114
 
 
115
  vboxLeft->addWidget(trace = new QCheckBox(i18n("Show trace")));
 
116
  connect(trace, SIGNAL(toggled(bool)), this, SLOT(traceChanged(bool)));
 
117
 
 
118
  QVBoxLayout *vboxMid = new QVBoxLayout;
 
119
  vboxMid->setSpacing(KDialog::spacingHint());
 
120
 
 
121
  QVBoxLayout *vboxRight = new QVBoxLayout;
 
122
  vboxRight->setSpacing(KDialog::spacingHint());
 
123
 
 
124
  // calculate the column width we need
 
125
  QFontMetrics fm(font());
 
126
  int colWidth = qMax(fm.width(PRESSED), fm.width("-32767")) + 10;  // -32767 largest string
 
127
 
 
128
  vboxMid->addWidget(new QLabel(i18n("Buttons:")));
 
129
  buttonTbl = new TableWidget(0, 1);
 
130
  buttonTbl->setSelectionMode(QAbstractItemView::NoSelection);
 
131
  buttonTbl->setEditTriggers(QAbstractItemView::NoEditTriggers);
 
132
  buttonTbl->setHorizontalHeaderLabels(QStringList(i18n("State")));
 
133
  buttonTbl->setSortingEnabled(false);
 
134
  buttonTbl->horizontalHeader()->setClickable(false);
 
135
  buttonTbl->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
 
136
  buttonTbl->horizontalHeader()->resizeSection(0, colWidth);
 
137
  buttonTbl->verticalHeader()->setClickable(false);
 
138
  vboxMid->addWidget(buttonTbl);
 
139
 
 
140
  vboxRight->addWidget(new QLabel(i18n("Axes:")));
 
141
  axesTbl = new TableWidget(0, 1);
 
142
  axesTbl->setSelectionMode(QAbstractItemView::NoSelection);
 
143
  axesTbl->setEditTriggers(QAbstractItemView::NoEditTriggers);
 
144
  axesTbl->setHorizontalHeaderLabels(QStringList(i18n("Value")));
 
145
  axesTbl->setSortingEnabled(false);
 
146
  axesTbl->horizontalHeader()->setClickable(false);
 
147
  axesTbl->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
 
148
  axesTbl->horizontalHeader()->resizeSection(0, colWidth);
 
149
  axesTbl->verticalHeader()->setClickable(false);
 
150
  vboxRight->addWidget(axesTbl);
 
151
 
 
152
  hbox->addLayout(vboxLeft);
 
153
  hbox->addLayout(vboxMid);
 
154
  hbox->addLayout(vboxRight);
 
155
 
 
156
  // calibrate button
 
157
  calibrate = new QPushButton(i18n("Calibrate"));
 
158
  connect(calibrate, SIGNAL(clicked()), this, SLOT(calibrateDevice()));
 
159
  calibrate->setEnabled(false);
 
160
 
 
161
  vboxLeft->addStretch();
 
162
  vboxLeft->addWidget(calibrate);
 
163
 
 
164
  // set up a timer for idle processing of joystick events
 
165
  idle = new QTimer(this);
 
166
  connect(idle, SIGNAL(timeout()), this, SLOT(checkDevice()));
 
167
 
 
168
  // check which devicefiles we have
 
169
  init();
 
170
}
 
171
 
 
172
//--------------------------------------------------------------
 
173
 
 
174
JoyWidget::~JoyWidget()
 
175
{
 
176
  delete joydev;
 
177
}
 
178
 
 
179
//--------------------------------------------------------------
 
180
 
 
181
void JoyWidget::init()
 
182
{
 
183
  // check which devicefiles we have
 
184
  int i;
 
185
  bool first = true;
 
186
  char dev[30];
 
187
 
 
188
  device->clear();
 
189
  buttonTbl->setRowCount(0);
 
190
  axesTbl->setRowCount(0);
 
191
 
 
192
  for (i = 0; i < 5; i++)  // check the first 5 devices
 
193
  {
 
194
    sprintf(dev, "/dev/js%d", i);  // first look in /dev
 
195
    JoyDevice *joy = new JoyDevice(dev);
 
196
 
 
197
    if ( joy->open() != JoyDevice::SUCCESS )
 
198
    {
 
199
      delete joy;
 
200
      sprintf(dev, "/dev/input/js%d", i);  // then look in /dev/input
 
201
      joy = new JoyDevice(dev);
 
202
 
 
203
      if ( joy->open() != JoyDevice::SUCCESS )
 
204
      {
 
205
        delete joy;
 
206
        continue;    // try next number
 
207
      }
 
208
    }
 
209
 
 
210
    // we found one
 
211
 
 
212
    device->addItem(QString("%1 (%2)").arg(joy->text()).arg(joy->device()));
 
213
 
 
214
    // display values for first device
 
215
    if ( first )
 
216
    {
 
217
      showDeviceProps(joy);  // this sets the joy object into this->joydev
 
218
      first = false;
 
219
    }
 
220
    else
 
221
      delete joy;
 
222
  }
 
223
 
 
224
  /* KDE 4: Remove this check(and i18n) when all KCM wrappers properly test modules */
 
225
  if ( device->count() == 0 )
 
226
  {
 
227
    messageBox->show();
 
228
    message->setWordWrap(true);
 
229
    message->setText(QString("<qt><b>%1</b></qt>").arg(
 
230
      i18n("No joystick device automatically found on this computer.<br />"
 
231
           "Checks were done in /dev/js[0-4] and /dev/input/js[0-4]<br />"
 
232
           "If you know that there is one attached, please enter the correct device file.")));
 
233
  }
 
234
}
 
235
 
 
236
//--------------------------------------------------------------
 
237
 
 
238
void JoyWidget::traceChanged(bool state)
 
239
{
 
240
  xyPos->showTrace(state);
 
241
}
 
242
 
 
243
//--------------------------------------------------------------
 
244
 
 
245
void JoyWidget::restoreCurrDev()
 
246
{
 
247
  if ( !joydev )  // no device open
 
248
  {
 
249
    device->setEditText("");
 
250
    calibrate->setEnabled(false);
 
251
  }
 
252
  else
 
253
  {
 
254
    // try to find the current open device in the combobox list
 
255
    int index = device->findText(joydev->device(), Qt::MatchContains);
 
256
 
 
257
    if ( index == -1 )  // the current open device is one the user entered (not in the list)
 
258
      device->setEditText(joydev->device());
 
259
    else
 
260
      device->setEditText(device->itemText(index));
 
261
  }
 
262
}
 
263
 
 
264
//--------------------------------------------------------------
 
265
 
 
266
void JoyWidget::deviceChanged(const QString &dev)
 
267
{
 
268
  // find "/dev" in given string
 
269
  int start, stop;
 
270
  QString devName;
 
271
 
 
272
  if ( (start = dev.indexOf("/dev")) == -1 )
 
273
  {
 
274
    KMessageBox::sorry(this,
 
275
      i18n("The given device name is invalid (does not contain /dev).\n"
 
276
           "Please select a device from the list or\n"
 
277
           "enter a device file, like /dev/js0."), i18n("Unknown Device"));
 
278
 
 
279
    restoreCurrDev();
 
280
    return;
 
281
  }
 
282
 
 
283
  if ( (stop = dev.indexOf(")", start)) != -1 )  // seems to be text selected from our list
 
284
    devName = dev.mid(start, stop - start);
 
285
  else
 
286
    devName = dev.mid(start);
 
287
 
 
288
  if ( joydev && (devName == joydev->device()) ) return;  // user selected the current device; ignore it
 
289
 
 
290
  JoyDevice *joy = new JoyDevice(devName);
 
291
  JoyDevice::ErrorCode ret = joy->open();
 
292
 
 
293
  if ( ret != JoyDevice::SUCCESS )
 
294
  {
 
295
    KMessageBox::error(this, joy->errText(ret), i18n("Device Error"));
 
296
 
 
297
    delete joy;
 
298
    restoreCurrDev();
 
299
    return;
 
300
  }
 
301
 
 
302
  showDeviceProps(joy);
 
303
}
 
304
 
 
305
//--------------------------------------------------------------
 
306
 
 
307
void JoyWidget::showDeviceProps(JoyDevice *joy)
 
308
{
 
309
  joydev = joy;
 
310
 
 
311
  buttonTbl->setRowCount(joydev->numButtons());
 
312
 
 
313
  axesTbl->setRowCount(joydev->numAxes());
 
314
  if ( joydev->numAxes() >= 2 )
 
315
  {
 
316
    axesTbl->setVerticalHeaderItem(0, new QTableWidgetItem(i18n("1(x)")));
 
317
    axesTbl->setVerticalHeaderItem(1, new QTableWidgetItem(i18n("2(y)")));
 
318
  }
 
319
 
 
320
  calibrate->setEnabled(true);
 
321
  idle->start(0);
 
322
 
 
323
  // make both tables use the same space for header; this looks nicer
 
324
  // TODO: Don't know how to do this in Qt4; the following does no longer work
 
325
  // Probably by setting a sizeHint for every single header item ?
 
326
  /*
 
327
  buttonTbl->verticalHeader()->setFixedWidth(qMax(buttonTbl->verticalHeader()->width(),
 
328
                                                    axesTbl->verticalHeader()->width()));
 
329
  axesTbl->verticalHeader()->setFixedWidth(buttonTbl->verticalHeader()->width());
 
330
  */
 
331
}
 
332
 
 
333
//--------------------------------------------------------------
 
334
 
 
335
void JoyWidget::checkDevice()
 
336
{
 
337
  if ( !joydev ) return;  // no open device yet
 
338
 
 
339
  JoyDevice::EventType type;
 
340
  int number, value;
 
341
 
 
342
  if ( !joydev->getEvent(type, number, value) )
 
343
    return;
 
344
 
 
345
  if ( type == JoyDevice::BUTTON )
 
346
  {
 
347
    if ( ! buttonTbl->item(number, 0) )
 
348
      buttonTbl->setItem(number, 0, new QTableWidgetItem());
 
349
 
 
350
    if ( value == 0 )  // button release
 
351
      buttonTbl->item(number, 0)->setText("-");
 
352
    else
 
353
      buttonTbl->item(number, 0)->setText(PRESSED);
 
354
  }
 
355
 
 
356
  if ( type == JoyDevice::AXIS )
 
357
  {
 
358
    if ( number == 0 ) // x-axis
 
359
      xyPos->changeX(value);
 
360
 
 
361
    if ( number == 1 ) // y-axis
 
362
      xyPos->changeY(value);
 
363
 
 
364
    if ( ! axesTbl->item(number, 0) )
 
365
      axesTbl->setItem(number, 0, new QTableWidgetItem());
 
366
 
 
367
    axesTbl->item(number, 0)->setText(QString("%1").arg(int(value)));
 
368
  }
 
369
}
 
370
 
 
371
//--------------------------------------------------------------
 
372
 
 
373
void JoyWidget::calibrateDevice()
 
374
{
 
375
  if ( !joydev ) return;  // just to be save
 
376
 
 
377
  JoyDevice::ErrorCode ret = joydev->initCalibration();
 
378
 
 
379
  if ( ret != JoyDevice::SUCCESS )
 
380
  {
 
381
    KMessageBox::error(this, joydev->errText(ret), i18n("Communication Error"));
 
382
    return;
 
383
  }
 
384
 
 
385
  if ( KMessageBox::messageBox(this, KMessageBox::Information,
 
386
        i18n("<qt>Calibration is about to check the precision.<br /><br />"
 
387
             "<b>Please move all axes to their center position and then "
 
388
             "do not touch the joystick anymore.</b><br /><br />"
 
389
             "Click OK to start the calibration.</qt>"),
 
390
        i18n("Calibration"),
 
391
        KStandardGuiItem::ok(), KStandardGuiItem::cancel()) != KMessageBox::Ok )
 
392
    return;
 
393
 
 
394
  idle->stop();  // stop the joystick event getting; this must be done inside the calibrate dialog
 
395
 
 
396
  CalDialog dlg(this, joydev);
 
397
  dlg.calibrate();
 
398
 
 
399
  // user canceled somewhere during calibration, therefore the device is in a bad state
 
400
  if ( dlg.result() == QDialog::Rejected )
 
401
    joydev->restoreCorr();
 
402
 
 
403
  idle->start(0);  // continue with event getting
 
404
}
 
405
 
 
406
//--------------------------------------------------------------
 
407
 
 
408
void JoyWidget::resetCalibration()
 
409
{
 
410
  if ( !joydev ) return;  // just to be save
 
411
 
 
412
  JoyDevice::ErrorCode ret = joydev->restoreCorr();
 
413
 
 
414
  if ( ret != JoyDevice::SUCCESS )
 
415
  {
 
416
    KMessageBox::error(this, joydev->errText(ret), i18n("Communication Error"));
 
417
  }
 
418
  else
 
419
  {
 
420
    KMessageBox::information(this,
 
421
      i18n("Restored all calibration values for joystick device %1.", joydev->device()),
 
422
      i18n("Calibration Success"));
 
423
  }
 
424
}
 
425
 
 
426
//--------------------------------------------------------------
 
427
 
 
428
#include "joywidget.moc"