3 Copyright 2008 - 2009 by jlh (jlh at gmx dot ch)
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2 of the License, version 3 of
8 the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 The GNU General Public License version 2 is included with the source of
20 this program under the file name COPYING. You can also get a copy on
24 #include <QVBoxLayout>
25 #include <QHBoxLayout>
27 #include <QRadioButton>
29 #include <QPushButton>
34 #include <QTextStream>
35 #include <QtAlgorithms>
39 #include <QFileIconProvider>
40 #include <QFileDialog>
44 #include "preferences.h"
45 #include "smartwidgets.h"
49 Preferences preferences
;
51 QString
getOutputPath() {
52 QString path
= preferences
.get(Pref::OutputPath
).toString();
53 if (path
.startsWith("~/") || path
== "~")
54 path
.replace(0, 1, QDir::homePath());
55 else if (!path
.startsWith('/'))
56 path
.prepend(QDir::currentPath() + '/');
61 QString
escape(const QString
&s
) {
63 out
.replace('%', "%%");
64 out
.replace('/', '_');
69 QString
getFileName(const QString
&skypeName
, const QString
&displayName
,
70 const QString
&mySkypeName
, const QString
&myDisplayName
, const QDateTime
×tamp
, const QString
&pat
)
72 QString pattern
= pat
.isEmpty() ? preferences
.get(Pref::OutputPattern
).toString() : pat
;
75 for (int i
= 0; i
< pattern
.size(); i
++) {
76 if (pattern
.at(i
) == QChar('&') && i
+ 1 < pattern
.size()) {
78 if (pattern
.at(i
) == QChar('s'))
79 fileName
+= escape(skypeName
);
80 else if (pattern
.at(i
) == QChar('d'))
81 fileName
+= escape(displayName
);
82 else if (pattern
.at(i
) == QChar('t'))
83 fileName
+= escape(mySkypeName
);
84 else if (pattern
.at(i
) == QChar('e'))
85 fileName
+= escape(myDisplayName
);
86 else if (pattern
.at(i
) == QChar('&'))
87 fileName
+= QChar('&');
89 fileName
+= QChar('&');
90 fileName
+= pattern
.at(i
);
93 fileName
+= pattern
.at(i
);
97 // TODO: uhm, does QT provide any time formatting the strftime() way?
98 char *buf
= new char[fileName
.size() + 1024];
99 time_t t
= timestamp
.toTime_t();
100 struct tm
*tm
= std::localtime(&t
);
101 std::strftime(buf
, fileName
.size() + 1024, fileName
.toUtf8().constData(), tm
);
102 fileName
= QString::fromLocal8Bit(buf
);
105 return getOutputPath() + '/' + fileName
;
108 // preferences dialog
110 static QVBoxLayout
*makeVFrame(QVBoxLayout
*parentLayout
, const char *title
) {
111 QGroupBox
*box
= new QGroupBox(title
);
112 QVBoxLayout
*vbox
= new QVBoxLayout(box
);
113 parentLayout
->addWidget(box
);
117 QWidget
*PreferencesDialog::createRecordingTab() {
118 QWidget
*widget
= new QWidget
;
119 QVBoxLayout
*vbox
= new QVBoxLayout(widget
);
121 Preference
&preference
= preferences
.get(Pref::AutoRecordDefault
);
122 SmartRadioButton
*radio
= new SmartRadioButton("Automatically &record all calls", preference
, "yes");
123 vbox
->addWidget(radio
);
124 radio
= new SmartRadioButton("&Ask for every call", preference
, "ask");
125 vbox
->addWidget(radio
);
126 radio
= new SmartRadioButton("Do ¬ automatically record calls", preference
, "no");
127 vbox
->addWidget(radio
);
129 QPushButton
*button
= new QPushButton("Edit &per caller preferences");
130 connect(button
, SIGNAL(clicked(bool)), this, SLOT(editPerCallerPreferences()));
131 vbox
->addWidget(button
);
133 SmartCheckBox
*check
= new SmartCheckBox("Show &balloon notification when recording starts", preferences
.get(Pref::NotifyRecordingStart
));
134 vbox
->addWidget(check
);
140 QWidget
*PreferencesDialog::createPathTab() {
141 QWidget
*widget
= new QWidget
;
142 QVBoxLayout
*vbox
= new QVBoxLayout(widget
);
144 QLabel
*label
= new QLabel("&Save recorded calls here:");
145 outputPathEdit
= new SmartLineEdit(preferences
.get(Pref::OutputPath
));
146 label
->setBuddy(outputPathEdit
);
147 connect(outputPathEdit
, SIGNAL(textChanged(const QString
&)), this, SLOT(updateAbsolutePathWarning(const QString
&)));
148 QPushButton
*button
= new QPushButton(QFileIconProvider().icon(QFileIconProvider::Folder
), "Browse");
149 connect(button
, SIGNAL(clicked(bool)), this, SLOT(browseOutputPath()));
150 QHBoxLayout
*hbox
= new QHBoxLayout
;
151 hbox
->addWidget(outputPathEdit
);
152 hbox
->addWidget(button
);
153 vbox
->addWidget(label
);
154 vbox
->addLayout(hbox
);
156 label
= new QLabel("File &name:");
157 patternWidget
= new SmartEditableComboBox(preferences
.get(Pref::OutputPattern
));
158 label
->setBuddy(patternWidget
);
159 patternWidget
->addItem("%Y-%m-%d %H:%M:%S Call with &s");
160 patternWidget
->addItem("Call with &s, %a %b %d %Y, %H:%M:%S");
161 patternWidget
->addItem("%Y, %B/Call with &s, %a %b %d %Y, %H:%M:%S");
162 patternWidget
->addItem("Calls with &s/Call with &s, %a %b %d %Y, %H:%M:%S");
163 patternWidget
->setupDone();
164 connect(patternWidget
, SIGNAL(editTextChanged(const QString
&)), this, SLOT(updatePatternToolTip(const QString
&)));
165 vbox
->addWidget(label
);
166 vbox
->addWidget(patternWidget
);
170 absolutePathWarningLabel
= new QLabel("<b>Warning:</b> The path you have entered is not an absolute path!");
171 vbox
->addWidget(absolutePathWarningLabel
);
173 updatePatternToolTip("");
174 updateAbsolutePathWarning(preferences
.get(Pref::OutputPath
).toString());
179 QWidget
*PreferencesDialog::createFormatTab() {
180 QWidget
*widget
= new QWidget
;
181 QVBoxLayout
*vbox
= new QVBoxLayout(widget
);
182 QGridLayout
*grid
= new QGridLayout
;
184 QLabel
*label
= new QLabel("Fil&e format:");
185 formatWidget
= new SmartComboBox(preferences
.get(Pref::OutputFormat
));
186 label
->setBuddy(formatWidget
);
187 formatWidget
->addItem("WAV PCM", "wav");
188 formatWidget
->addItem("MP3", "mp3");
189 formatWidget
->addItem("Ogg Vorbis", "vorbis");
190 formatWidget
->setupDone();
191 connect(formatWidget
, SIGNAL(currentIndexChanged(int)), this, SLOT(updateFormatSettings()));
192 grid
->addWidget(label
, 0, 0);
193 grid
->addWidget(formatWidget
, 0, 1);
195 label
= new QLabel("MP3 &bitrate:");
196 SmartComboBox
*combo
= new SmartComboBox(preferences
.get(Pref::OutputFormatMp3Bitrate
));
197 label
->setBuddy(combo
);
198 combo
->addItem("8 kbps", 8);
199 combo
->addItem("16 kbps", 16);
200 combo
->addItem("24 kbps", 24);
201 combo
->addItem("32 kbps (recommended for mono)", 32);
202 combo
->addItem("40 kbps", 40);
203 combo
->addItem("48 kbps", 48);
204 combo
->addItem("56 kbps", 56);
205 combo
->addItem("64 kbps (recommended for stereo)", 64);
206 combo
->addItem("80 kbps", 80);
207 combo
->addItem("96 kbps", 96);
208 combo
->addItem("112 kbps", 112);
209 combo
->addItem("128 kbps", 128);
210 combo
->addItem("144 kbps", 144);
211 combo
->addItem("160 kbps", 160);
213 mp3Settings
.append(label
);
214 mp3Settings
.append(combo
);
215 grid
->addWidget(label
, 1, 0);
216 grid
->addWidget(combo
, 1, 1);
218 label
= new QLabel("Ogg Vorbis &quality:");
219 combo
= new SmartComboBox(preferences
.get(Pref::OutputFormatVorbisQuality
));
220 label
->setBuddy(combo
);
221 combo
->addItem("Quality -1", -1);
222 combo
->addItem("Quality 0", 0);
223 combo
->addItem("Quality 1", 1);
224 combo
->addItem("Quality 2", 2);
225 combo
->addItem("Quality 3 (recommended)", 3);
226 combo
->addItem("Quality 4", 4);
227 combo
->addItem("Quality 5", 5);
228 combo
->addItem("Quality 6", 6);
229 combo
->addItem("Quality 7", 7);
230 combo
->addItem("Quality 8", 8);
231 combo
->addItem("Quality 9", 9);
232 combo
->addItem("Quality 10", 10);
234 vorbisSettings
.append(label
);
235 vorbisSettings
.append(combo
);
236 grid
->addWidget(label
, 2, 0);
237 grid
->addWidget(combo
, 2, 1);
239 vbox
->addLayout(grid
);
241 SmartCheckBox
*check
= new SmartCheckBox("Save to &stereo file", preferences
.get(Pref::OutputStereo
));
242 connect(check
, SIGNAL(clicked(bool)), this, SLOT(updateStereoSettings(bool)));
243 vbox
->addWidget(check
);
245 stereoMixLabel
= new QLabel("");
246 SmartSlider
*slider
= new SmartSlider(preferences
.get(Pref::OutputStereoMix
));
247 stereoMixLabel
->setBuddy(slider
);
248 slider
->setOrientation(Qt::Horizontal
);
249 slider
->setRange(0, 100);
250 slider
->setSingleStep(1);
251 slider
->setPageStep(10);
252 slider
->setTickPosition(QSlider::TicksBelow
);
253 slider
->setTickInterval(10);
255 connect(slider
, SIGNAL(valueChanged(int)), this, SLOT(updateStereoMixLabel(int)));
256 stereoSettings
.append(stereoMixLabel
);
257 stereoSettings
.append(slider
);
258 vbox
->addWidget(stereoMixLabel
);
259 vbox
->addWidget(slider
);
261 check
= new SmartCheckBox("Save call &information in files", preferences
.get(Pref::OutputSaveTags
));
262 mp3Settings
.append(check
);
263 vorbisSettings
.append(check
);
264 vbox
->addWidget(check
);
267 updateFormatSettings();
268 updateStereoSettings(preferences
.get(Pref::OutputStereo
).toBool());
269 updateStereoMixLabel(preferences
.get(Pref::OutputStereoMix
).toInt());
273 QWidget
*PreferencesDialog::createMiscTab() {
274 QWidget
*widget
= new QWidget
;
275 QVBoxLayout
*vbox
= new QVBoxLayout(widget
);
277 SmartCheckBox
*check
= new SmartCheckBox("&Display a small main window. Enable this if your\n"
278 "environment does not provide a system tray (needs restart)", preferences
.get(Pref::GuiWindowed
));
279 vbox
->addWidget(check
);
285 PreferencesDialog::PreferencesDialog() {
286 setWindowTitle(PROGRAM_NAME
" - Preferences");
287 setAttribute(Qt::WA_DeleteOnClose
);
289 QVBoxLayout
*vbox
= new QVBoxLayout(this);
290 vbox
->setSizeConstraint(QLayout::SetFixedSize
);
292 QTabWidget
*tabWidget
= new QTabWidget
;
293 vbox
->addWidget(tabWidget
);
295 tabWidget
->addTab(createRecordingTab(), "Au&tomatic Recording");
296 tabWidget
->addTab(createPathTab(), "&File names");
297 tabWidget
->addTab(createFormatTab(), "File F&ormat");
298 tabWidget
->addTab(createMiscTab(), "&Misc");
299 tabWidget
->setUsesScrollButtons(false);
301 QHBoxLayout
*hbox
= new QHBoxLayout
;
302 QPushButton
*button
= new QPushButton("&Close");
303 button
->setDefault(true);
304 connect(button
, SIGNAL(clicked(bool)), this, SLOT(accept()));
306 hbox
->addWidget(button
);
307 vbox
->addLayout(hbox
);
312 void PreferencesDialog::updateFormatSettings() {
313 QVariant v
= formatWidget
->itemData(formatWidget
->currentIndex());
316 for (int i
= 0; i
< mp3Settings
.size(); i
++)
317 mp3Settings
.at(i
)->setEnabled(false);
319 for (int i
= 0; i
< vorbisSettings
.size(); i
++)
320 vorbisSettings
.at(i
)->setEnabled(false);
323 for (int i
= 0; i
< mp3Settings
.size(); i
++)
324 mp3Settings
.at(i
)->setEnabled(true);
326 for (int i
= 0; i
< vorbisSettings
.size(); i
++)
327 vorbisSettings
.at(i
)->setEnabled(true);
330 void PreferencesDialog::updateStereoSettings(bool stereo
) {
331 for (int i
= 0; i
< stereoSettings
.size(); i
++)
333 stereoSettings
.at(i
)->setEnabled(true);
335 stereoSettings
.at(i
)->setEnabled(false);
338 void PreferencesDialog::updateStereoMixLabel(int value
) {
339 stereoMixLabel
->setText(QString("Stereo mi&x: (left channel: local %1%, remote %2%)").arg(100 - value
).arg(value
));
342 void PreferencesDialog::editPerCallerPreferences() {
343 perCallerDialog
= new PerCallerPreferencesDialog(this);
346 void PreferencesDialog::browseOutputPath() {
347 preferences
.get(Pref::OutputPath
).set(outputPathEdit
->text());
348 QFileDialog
dialog(this, "Select output path", getOutputPath());
349 dialog
.setFileMode(QFileDialog::DirectoryOnly
);
352 QStringList list
= dialog
.selectedFiles();
355 QString path
= list
.at(0);
356 QString home
= QDir::homePath();
357 if (path
.startsWith(home
+ '/') || path
== home
)
358 path
.replace(0, home
.size(), '~');
359 if (path
.endsWith('/') || path
.endsWith('\\'))
361 outputPathEdit
->setText(path
);
364 void PreferencesDialog::updateAbsolutePathWarning(const QString
&string
) {
365 if (string
.startsWith('/') || string
.startsWith("~/") || string
== "~")
366 absolutePathWarningLabel
->hide();
368 absolutePathWarningLabel
->show();
371 void PreferencesDialog::hideEvent(QHideEvent
*event
) {
373 perCallerDialog
->accept();
375 QDialog::hideEvent(event
);
378 void PreferencesDialog::updatePatternToolTip(const QString
&pattern
) {
380 "This pattern specifies how the file name for the recorded call is constructed.\n"
381 "You can use the following directives:\n\n"
383 #define X(a, b) "\t" a "\t" b "\n"
384 X("&s" , "The remote skype name or phone number")
385 X("&d" , "The remote display name")
386 X("&t" , "Your skype name")
387 X("&e" , "Your display name")
388 X("&&" , "Literal & character")
390 X("%A / %a", "Full / abbreviated weekday name")
391 X("%B / %b", "Full / abbreviated month name")
392 X("%m" , "Month as a number (01 - 12)")
393 X("%d" , "Day of the month (01 - 31)")
394 X("%H" , "Hour as a 24-hour clock (00 - 23)")
395 X("%I" , "Hour as a 12-hour clock (01 - 12)")
397 X("%M" , "Minutes (00 - 59)")
398 X("%S" , "Seconds (00 - 59)")
399 X("%%" , "Literal % character")
401 "\t...and all other directives provided by strftime()\n\n"
403 "With the current choice, the file name might look like this:\n";
405 QString fn
= getFileName("echo123", "Skype Test Service", "myskype", "My Full Name",
406 QDateTime::currentDateTime(), pattern
);
408 if (fn
.contains(':'))
409 tip
+= "\n\nWARNING: Microsoft Windows does not allow colon characters (:) in file names.";
410 patternWidget
->setToolTip(tip
);
413 void PreferencesDialog::closePerCallerDialog() {
415 perCallerDialog
->accept();
418 // per caller preferences editor
420 PerCallerPreferencesDialog::PerCallerPreferencesDialog(QWidget
*parent
) : QDialog(parent
) {
421 setWindowTitle("Per Caller Preferences");
422 setWindowModality(Qt::WindowModal
);
423 setAttribute(Qt::WA_DeleteOnClose
);
425 model
= new PerCallerModel(this);
427 QHBoxLayout
*bighbox
= new QHBoxLayout(this);
428 QVBoxLayout
*vbox
= new QVBoxLayout
;
430 listWidget
= new QListView
;
431 listWidget
->setModel(model
);
432 listWidget
->setSelectionMode(QAbstractItemView::ExtendedSelection
);
433 listWidget
->setEditTriggers(QAbstractItemView::SelectedClicked
| QAbstractItemView::DoubleClicked
);
434 connect(listWidget
->selectionModel(), SIGNAL(selectionChanged(const QItemSelection
&, const QItemSelection
&)), this, SLOT(selectionChanged()));
435 vbox
->addWidget(listWidget
);
437 QVBoxLayout
*frame
= makeVFrame(vbox
, "Preference for selected Skype names:");
438 radioYes
= new QRadioButton("Automatically &record calls");
439 radioAsk
= new QRadioButton("&Ask every time");
440 radioNo
= new QRadioButton("Do ¬ automatically record calls");
441 connect(radioYes
, SIGNAL(clicked(bool)), this, SLOT(radioChanged()));
442 connect(radioAsk
, SIGNAL(clicked(bool)), this, SLOT(radioChanged()));
443 connect(radioNo
, SIGNAL(clicked(bool)), this, SLOT(radioChanged()));
444 frame
->addWidget(radioYes
);
445 frame
->addWidget(radioAsk
);
446 frame
->addWidget(radioNo
);
448 bighbox
->addLayout(vbox
);
450 vbox
= new QVBoxLayout
;
452 QPushButton
*button
= new QPushButton("A&dd");
453 connect(button
, SIGNAL(clicked(bool)), this, SLOT(add()));
454 vbox
->addWidget(button
);
456 button
= new QPushButton("Re&move");
457 connect(button
, SIGNAL(clicked(bool)), this, SLOT(remove()));
458 vbox
->addWidget(button
);
462 button
= new QPushButton("&Close");
463 button
->setDefault(true);
464 connect(button
, SIGNAL(clicked(bool)), this, SLOT(accept()));
465 vbox
->addWidget(button
);
467 bighbox
->addLayout(vbox
);
473 QStringList list
= preferences
.get(Pref::AutoRecordYes
).toList();
474 for (int i
= 0; i
< list
.count(); i
++) {
475 QString sn
= list
.at(i
);
476 if (seen
.contains(sn
))
482 list
= preferences
.get(Pref::AutoRecordAsk
).toList();
483 for (int i
= 0; i
< list
.count(); i
++) {
484 QString sn
= list
.at(i
);
485 if (seen
.contains(sn
))
491 list
= preferences
.get(Pref::AutoRecordNo
).toList();
492 for (int i
= 0; i
< list
.count(); i
++) {
493 QString sn
= list
.at(i
);
494 if (seen
.contains(sn
))
501 connect(this, SIGNAL(finished(int)), this, SLOT(save()));
506 void PerCallerPreferencesDialog::add(const QString
&name
, int mode
, bool edit
) {
507 int i
= model
->rowCount();
510 QModelIndex idx
= model
->index(i
, 0);
511 model
->setData(idx
, name
, Qt::EditRole
);
512 model
->setData(idx
, mode
, Qt::UserRole
);
515 listWidget
->clearSelection();
516 listWidget
->setCurrentIndex(idx
);
517 listWidget
->edit(idx
);
521 void PerCallerPreferencesDialog::remove() {
522 QModelIndexList sel
= listWidget
->selectionModel()->selectedIndexes();
524 while (!sel
.isEmpty())
525 model
->removeRow(sel
.takeLast().row());
528 void PerCallerPreferencesDialog::selectionChanged() {
529 QModelIndexList sel
= listWidget
->selectionModel()->selectedIndexes();
530 bool notEmpty
= !sel
.isEmpty();
532 while (!sel
.isEmpty()) {
533 int m
= model
->data(sel
.takeLast(), Qt::UserRole
).toInt();
536 } else if (mode
!= m
) {
542 // Qt is a bit annoying about this: You can't deselect
543 // everything unless you disable auto-exclusive mode
544 radioYes
->setAutoExclusive(false);
545 radioAsk
->setAutoExclusive(false);
546 radioNo
->setAutoExclusive(false);
547 radioYes
->setChecked(false);
548 radioAsk
->setChecked(false);
549 radioNo
->setChecked(false);
550 radioYes
->setAutoExclusive(true);
551 radioAsk
->setAutoExclusive(true);
552 radioNo
->setAutoExclusive(true);
553 } else if (mode
== 0) {
554 radioNo
->setChecked(true);
555 } else if (mode
== 1) {
556 radioAsk
->setChecked(true);
557 } else if (mode
== 2) {
558 radioYes
->setChecked(true);
561 radioYes
->setEnabled(notEmpty
);
562 radioAsk
->setEnabled(notEmpty
);
563 radioNo
->setEnabled(notEmpty
);
566 void PerCallerPreferencesDialog::radioChanged() {
568 if (radioYes
->isChecked())
570 else if (radioNo
->isChecked())
573 QModelIndexList sel
= listWidget
->selectionModel()->selectedIndexes();
574 while (!sel
.isEmpty())
575 model
->setData(sel
.takeLast(), mode
, Qt::UserRole
);
578 void PerCallerPreferencesDialog::save() {
580 int n
= model
->rowCount();
581 QStringList yes
, ask
, no
;
582 for (int i
= 0; i
< n
; i
++) {
583 QModelIndex idx
= model
->index(i
, 0);
584 QString sn
= model
->data(idx
, Qt::EditRole
).toString();
587 int mode
= model
->data(idx
, Qt::UserRole
).toInt();
595 preferences
.get(Pref::AutoRecordYes
).set(yes
);
596 preferences
.get(Pref::AutoRecordAsk
).set(ask
);
597 preferences
.get(Pref::AutoRecordNo
).set(no
);
602 int PerCallerModel::rowCount(const QModelIndex
&) const {
603 return skypeNames
.count();
607 const char *PerCallerModel_data_table
[3] = {
608 "Don't record", "Ask", "Automatic"
612 QVariant
PerCallerModel::data(const QModelIndex
&index
, int role
) const {
613 if (!index
.isValid() || index
.row() >= skypeNames
.size())
615 if (role
== Qt::DisplayRole
) {
617 return skypeNames
.at(i
) + " - " + PerCallerModel_data_table
[modes
.at(i
)];
619 if (role
== Qt::EditRole
)
620 return skypeNames
.at(index
.row());
621 if (role
== Qt::UserRole
)
622 return modes
.at(index
.row());
626 bool PerCallerModel::setData(const QModelIndex
&index
, const QVariant
&value
, int role
) {
627 if (!index
.isValid() || index
.row() >= skypeNames
.size())
629 if (role
== Qt::EditRole
) {
630 skypeNames
[index
.row()] = value
.toString();
631 emit
dataChanged(index
, index
);
634 if (role
== Qt::UserRole
) {
635 modes
[index
.row()] = value
.toInt();
636 emit
dataChanged(index
, index
);
642 bool PerCallerModel::insertRows(int position
, int rows
, const QModelIndex
&) {
643 beginInsertRows(QModelIndex(), position
, position
+ rows
- 1);
644 for (int i
= 0; i
< rows
; i
++) {
645 skypeNames
.insert(position
, "");
646 modes
.insert(position
, 1);
652 bool PerCallerModel::removeRows(int position
, int rows
, const QModelIndex
&) {
653 beginRemoveRows(QModelIndex(), position
, position
+ rows
- 1);
654 for (int i
= 0; i
< rows
; i
++) {
655 skypeNames
.removeAt(position
);
656 modes
.removeAt(position
);
662 void PerCallerModel::sort(int, Qt::SortOrder
) {
663 typedef QPair
<QString
, int> Pair
;
664 typedef QList
<Pair
> List
;
666 for (int i
= 0; i
< skypeNames
.size(); i
++)
667 list
.append(Pair(skypeNames
.at(i
), modes
.at(i
)));
669 for (int i
= 0; i
< skypeNames
.size(); i
++) {
670 skypeNames
[i
] = list
.at(i
).first
;
671 modes
[i
] = list
.at(i
).second
;
676 Qt::ItemFlags
PerCallerModel::flags(const QModelIndex
&index
) const {
677 Qt::ItemFlags flags
= QAbstractListModel::flags(index
);
678 if (!index
.isValid() || index
.row() >= skypeNames
.size())
680 return flags
| Qt::ItemIsEditable
;
685 void Preference::listAdd(const QString
&value
) {
686 QStringList list
= toList();
687 if (!list
.contains(value
)) {
693 void Preference::listRemove(const QString
&value
) {
694 QStringList list
= toList();
695 if (list
.removeAll(value
))
699 bool Preference::listContains(const QString
&value
) {
700 QStringList list
= toList();
701 return list
.contains(value
);
706 BasePreferences::~BasePreferences() {
710 bool BasePreferences::load(const QString
&filename
) {
712 QFile
file(filename
);
713 if (!file
.open(QIODevice::ReadOnly
| QIODevice::Text
)) {
714 debug(QString("Can't open '%1' for loading preferences").arg(filename
));
718 while (!file
.atEnd()) {
719 qint64 len
= file
.readLine(buf
, sizeof(buf
));
722 QString line
= QString::fromUtf8(buf
);
723 line
= line
.trimmed();
724 if (line
.at(0) == '#')
726 int index
= line
.indexOf('=');
730 get(line
.left(index
).trimmed()).set(line
.mid(index
+ 1).trimmed());
732 debug(QString("Loaded %1 preferences from '%2'").arg(prefs
.size()).arg(filename
));
737 bool comparePreferencePointers(const Preference
*p1
, const Preference
*p2
)
743 bool BasePreferences::save(const QString
&filename
) {
744 qSort(prefs
.begin(), prefs
.end(), comparePreferencePointers
);
745 QFile
file(filename
);
746 if (!file
.open(QIODevice::WriteOnly
| QIODevice::Text
)) {
747 debug(QString("Can't open '%1' for saving preferences").arg(filename
));
750 QTextStream
out(&file
);
751 for (int i
= 0; i
< prefs
.size(); i
++) {
752 const Preference
&p
= *prefs
.at(i
);
753 out
<< p
.name() << " = " << p
.toString() << "\n";
755 debug(QString("Saved %1 preferences to '%2'").arg(prefs
.size()).arg(filename
));
759 Preference
&BasePreferences::get(const QString
&name
) {
760 for (int i
= 0; i
< prefs
.size(); i
++)
761 if (prefs
.at(i
)->name() == name
)
763 prefs
.append(new Preference(name
));
764 return *prefs
.last();
767 void BasePreferences::remove(const QString
&name
) {
768 for (int i
= 0; i
< prefs
.size(); i
++) {
769 if (prefs
.at(i
)->name() == name
) {
770 delete prefs
.takeAt(i
);
776 bool BasePreferences::exists(const QString
&name
) const {
777 for (int i
= 0; i
< prefs
.size(); i
++)
778 if (prefs
.at(i
)->name() == name
)
783 void BasePreferences::clear() {
784 for (int i
= 0; i
< prefs
.size(); i
++)
791 void Preferences::setPerCallerPreference(const QString
&sn
, int mode
) {
792 // this would interfer with the per caller dialog
793 recorderInstance
->closePerCallerDialog();
795 Preference
&pYes
= get(Pref::AutoRecordYes
);
796 Preference
&pAsk
= get(Pref::AutoRecordAsk
);
797 Preference
&pNo
= get(Pref::AutoRecordNo
);