3 Copyright (C) 2008 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
&pattern
)
73 if (pattern
.isEmpty())
74 fileName
= preferences
.get(Pref::OutputPattern
).toString();
78 fileName
.replace("&s", escape(skypeName
));
79 fileName
.replace("&d", escape(displayName
));
80 fileName
.replace("&t", escape(mySkypeName
));
81 fileName
.replace("&e", escape(myDisplayName
));
82 fileName
.replace("&&", "&");
84 // TODO: uhm, does QT provide any time formatting the strftime() way?
85 char *buf
= new char[fileName
.size() + 1024];
86 time_t t
= timestamp
.toTime_t();
87 struct tm
*tm
= std::localtime(&t
);
88 std::strftime(buf
, fileName
.size() + 1024, fileName
.toUtf8().constData(), tm
);
92 return getOutputPath() + '/' + fileName
;
97 static QVBoxLayout
*makeVFrame(QVBoxLayout
*parentLayout
, const char *title
) {
98 QGroupBox
*box
= new QGroupBox(title
);
99 QVBoxLayout
*vbox
= new QVBoxLayout(box
);
100 parentLayout
->addWidget(box
);
104 QWidget
*PreferencesDialog::createRecordingTab() {
105 QWidget
*widget
= new QWidget
;
106 QVBoxLayout
*vbox
= new QVBoxLayout(widget
);
108 Preference
&preference
= preferences
.get(Pref::AutoRecordDefault
);
109 SmartRadioButton
*radio
= new SmartRadioButton("Automatically &record all calls", preference
, "yes");
110 vbox
->addWidget(radio
);
111 radio
= new SmartRadioButton("&Ask for every call", preference
, "ask");
112 vbox
->addWidget(radio
);
113 radio
= new SmartRadioButton("Do ¬ automatically record calls", preference
, "no");
114 vbox
->addWidget(radio
);
116 QPushButton
*button
= new QPushButton("Edit &per caller preferences");
117 connect(button
, SIGNAL(clicked(bool)), this, SLOT(editPerCallerPreferences()));
118 vbox
->addWidget(button
);
120 SmartCheckBox
*check
= new SmartCheckBox("Show &balloon notification when recording starts", preferences
.get(Pref::NotifyRecordingStart
));
121 vbox
->addWidget(check
);
127 QWidget
*PreferencesDialog::createPathTab() {
128 QWidget
*widget
= new QWidget
;
129 QVBoxLayout
*vbox
= new QVBoxLayout(widget
);
131 QLabel
*label
= new QLabel("&Save recorded calls here:");
132 outputPathEdit
= new SmartLineEdit(preferences
.get(Pref::OutputPath
));
133 label
->setBuddy(outputPathEdit
);
134 connect(outputPathEdit
, SIGNAL(textChanged(const QString
&)), this, SLOT(updateAbsolutePathWarning(const QString
&)));
135 QPushButton
*button
= new QPushButton(QFileIconProvider().icon(QFileIconProvider::Folder
), "Browse");
136 connect(button
, SIGNAL(clicked(bool)), this, SLOT(browseOutputPath()));
137 QHBoxLayout
*hbox
= new QHBoxLayout
;
138 hbox
->addWidget(outputPathEdit
);
139 hbox
->addWidget(button
);
140 vbox
->addWidget(label
);
141 vbox
->addLayout(hbox
);
143 label
= new QLabel("File &name:");
144 patternWidget
= new SmartEditableComboBox(preferences
.get(Pref::OutputPattern
));
145 label
->setBuddy(patternWidget
);
146 patternWidget
->addItem("%Y-%m-%d %H:%M:%S Call with &s");
147 patternWidget
->addItem("Call with &s, %a %b %d %Y, %H:%M:%S");
148 patternWidget
->addItem("%Y, %B/Call with &s, %a %b %d %Y, %H:%M:%S");
149 patternWidget
->addItem("Calls with &s/Call with &s, %a %b %d %Y, %H:%M:%S");
150 patternWidget
->setupDone();
151 connect(patternWidget
, SIGNAL(editTextChanged(const QString
&)), this, SLOT(updatePatternToolTip(const QString
&)));
152 vbox
->addWidget(label
);
153 vbox
->addWidget(patternWidget
);
157 absolutePathWarningLabel
= new QLabel("<b>Warning:</b> The path you have entered is not an absolute path!");
158 vbox
->addWidget(absolutePathWarningLabel
);
160 updatePatternToolTip("");
161 updateAbsolutePathWarning(preferences
.get(Pref::OutputPath
).toString());
166 QWidget
*PreferencesDialog::createFormatTab() {
167 QWidget
*widget
= new QWidget
;
168 QVBoxLayout
*vbox
= new QVBoxLayout(widget
);
169 QGridLayout
*grid
= new QGridLayout
;
171 QLabel
*label
= new QLabel("Fil&e format:");
172 formatWidget
= new SmartComboBox(preferences
.get(Pref::OutputFormat
));
173 label
->setBuddy(formatWidget
);
174 formatWidget
->addItem("WAV PCM", "wav");
175 formatWidget
->addItem("MP3", "mp3");
176 formatWidget
->addItem("Ogg Vorbis", "vorbis");
177 formatWidget
->setupDone();
178 connect(formatWidget
, SIGNAL(currentIndexChanged(int)), this, SLOT(updateFormatSettings()));
179 grid
->addWidget(label
, 0, 0);
180 grid
->addWidget(formatWidget
, 0, 1);
182 label
= new QLabel("MP3 &bitrate:");
183 SmartComboBox
*combo
= new SmartComboBox(preferences
.get(Pref::OutputFormatMp3Bitrate
));
184 label
->setBuddy(combo
);
185 combo
->addItem("8 kbps", 8);
186 combo
->addItem("16 kbps", 16);
187 combo
->addItem("24 kbps", 24);
188 combo
->addItem("32 kbps (recommended for mono)", 32);
189 combo
->addItem("40 kbps", 40);
190 combo
->addItem("48 kbps", 48);
191 combo
->addItem("56 kbps", 56);
192 combo
->addItem("64 kbps (recommended for stereo)", 64);
193 combo
->addItem("80 kbps", 80);
194 combo
->addItem("96 kbps", 96);
195 combo
->addItem("112 kbps", 112);
196 combo
->addItem("128 kbps", 128);
197 combo
->addItem("144 kbps", 144);
198 combo
->addItem("160 kbps", 160);
200 mp3Settings
.append(label
);
201 mp3Settings
.append(combo
);
202 grid
->addWidget(label
, 1, 0);
203 grid
->addWidget(combo
, 1, 1);
205 label
= new QLabel("Ogg Vorbis &quality:");
206 combo
= new SmartComboBox(preferences
.get(Pref::OutputFormatVorbisQuality
));
207 label
->setBuddy(combo
);
208 combo
->addItem("Quality -1", -1);
209 combo
->addItem("Quality 0", 0);
210 combo
->addItem("Quality 1", 1);
211 combo
->addItem("Quality 2", 2);
212 combo
->addItem("Quality 3 (recommended)", 3);
213 combo
->addItem("Quality 4", 4);
214 combo
->addItem("Quality 5", 5);
215 combo
->addItem("Quality 6", 6);
216 combo
->addItem("Quality 7", 7);
217 combo
->addItem("Quality 8", 8);
218 combo
->addItem("Quality 9", 9);
219 combo
->addItem("Quality 10", 10);
221 vorbisSettings
.append(label
);
222 vorbisSettings
.append(combo
);
223 grid
->addWidget(label
, 2, 0);
224 grid
->addWidget(combo
, 2, 1);
226 vbox
->addLayout(grid
);
228 SmartCheckBox
*check
= new SmartCheckBox("Save to &stereo file", preferences
.get(Pref::OutputStereo
));
229 connect(check
, SIGNAL(clicked(bool)), this, SLOT(updateStereoSettings(bool)));
230 vbox
->addWidget(check
);
232 stereoMixLabel
= new QLabel("");
233 SmartSlider
*slider
= new SmartSlider(preferences
.get(Pref::OutputStereoMix
));
234 stereoMixLabel
->setBuddy(slider
);
235 slider
->setOrientation(Qt::Horizontal
);
236 slider
->setRange(0, 100);
237 slider
->setSingleStep(1);
238 slider
->setPageStep(10);
239 slider
->setTickPosition(QSlider::TicksBelow
);
240 slider
->setTickInterval(10);
242 connect(slider
, SIGNAL(valueChanged(int)), this, SLOT(updateStereoMixLabel(int)));
243 stereoSettings
.append(stereoMixLabel
);
244 stereoSettings
.append(slider
);
245 vbox
->addWidget(stereoMixLabel
);
246 vbox
->addWidget(slider
);
248 check
= new SmartCheckBox("Save call &information in files", preferences
.get(Pref::OutputSaveTags
));
249 mp3Settings
.append(check
);
250 vorbisSettings
.append(check
);
251 vbox
->addWidget(check
);
254 updateFormatSettings();
255 updateStereoSettings(preferences
.get(Pref::OutputStereo
).toBool());
256 updateStereoMixLabel(preferences
.get(Pref::OutputStereoMix
).toInt());
260 QWidget
*PreferencesDialog::createMiscTab() {
261 QWidget
*widget
= new QWidget
;
262 QVBoxLayout
*vbox
= new QVBoxLayout(widget
);
264 SmartCheckBox
*check
= new SmartCheckBox("&Display a small main window. Enable this if your\n"
265 "environment does not provide a system tray (needs restart)", preferences
.get(Pref::GuiWindowed
));
266 vbox
->addWidget(check
);
272 PreferencesDialog::PreferencesDialog() {
273 setWindowTitle(PROGRAM_NAME
" - Preferences");
274 setAttribute(Qt::WA_DeleteOnClose
);
276 QVBoxLayout
*vbox
= new QVBoxLayout(this);
277 vbox
->setSizeConstraint(QLayout::SetFixedSize
);
279 QTabWidget
*tabWidget
= new QTabWidget
;
280 vbox
->addWidget(tabWidget
);
282 tabWidget
->addTab(createRecordingTab(), "Au&tomatic Recording");
283 tabWidget
->addTab(createPathTab(), "&File names");
284 tabWidget
->addTab(createFormatTab(), "File F&ormat");
285 tabWidget
->addTab(createMiscTab(), "&Misc");
286 tabWidget
->setUsesScrollButtons(false);
288 QHBoxLayout
*hbox
= new QHBoxLayout
;
289 QPushButton
*button
= new QPushButton("&Close");
290 button
->setDefault(true);
291 connect(button
, SIGNAL(clicked(bool)), this, SLOT(accept()));
293 hbox
->addWidget(button
);
294 vbox
->addLayout(hbox
);
299 void PreferencesDialog::updateFormatSettings() {
300 QVariant v
= formatWidget
->itemData(formatWidget
->currentIndex());
303 for (int i
= 0; i
< mp3Settings
.size(); i
++)
304 mp3Settings
.at(i
)->setEnabled(false);
306 for (int i
= 0; i
< vorbisSettings
.size(); i
++)
307 vorbisSettings
.at(i
)->setEnabled(false);
310 for (int i
= 0; i
< mp3Settings
.size(); i
++)
311 mp3Settings
.at(i
)->setEnabled(true);
313 for (int i
= 0; i
< vorbisSettings
.size(); i
++)
314 vorbisSettings
.at(i
)->setEnabled(true);
317 void PreferencesDialog::updateStereoSettings(bool stereo
) {
318 for (int i
= 0; i
< stereoSettings
.size(); i
++)
320 stereoSettings
.at(i
)->setEnabled(true);
322 stereoSettings
.at(i
)->setEnabled(false);
325 void PreferencesDialog::updateStereoMixLabel(int value
) {
326 stereoMixLabel
->setText(QString("Stereo mi&x: (left channel: local %1%, remote %2%)").arg(100 - value
).arg(value
));
329 void PreferencesDialog::editPerCallerPreferences() {
330 perCallerDialog
= new PerCallerPreferencesDialog(this);
333 void PreferencesDialog::browseOutputPath() {
334 preferences
.get(Pref::OutputPath
).set(outputPathEdit
->text());
335 QFileDialog
dialog(this, "Select output path", getOutputPath());
336 dialog
.setFileMode(QFileDialog::DirectoryOnly
);
339 QStringList list
= dialog
.selectedFiles();
342 QString path
= list
.at(0);
343 QString home
= QDir::homePath();
344 if (path
.startsWith(home
+ '/') || path
== home
)
345 path
.replace(0, home
.size(), '~');
346 if (path
.endsWith('/') || path
.endsWith('\\'))
348 outputPathEdit
->setText(path
);
351 void PreferencesDialog::updateAbsolutePathWarning(const QString
&string
) {
352 if (string
.startsWith('/') || string
.startsWith("~/") || string
== "~")
353 absolutePathWarningLabel
->hide();
355 absolutePathWarningLabel
->show();
358 void PreferencesDialog::hideEvent(QHideEvent
*event
) {
360 perCallerDialog
->accept();
362 QDialog::hideEvent(event
);
365 void PreferencesDialog::updatePatternToolTip(const QString
&pattern
) {
367 "This pattern specifies how the file name for the recorded call is constructed.\n"
368 "You can use the following directives:\n\n"
370 #define X(a, b) "\t" a "\t" b "\n"
371 X("&s" , "The remote skype name or phone number")
372 X("&d" , "The remote display name")
373 X("&t" , "Your skype name")
374 X("&e" , "Your display name")
375 X("&&" , "Literal & character")
377 X("%A / %a", "Full / abbreviated weekday name")
378 X("%B / %b", "Full / abbreviated month name")
379 X("%m" , "Month as a number (01 - 12)")
380 X("%d" , "Day of the month (01 - 31)")
381 X("%H" , "Hour as a 24-hour clock (00 - 23)")
382 X("%I" , "Hour as a 12-hour clock (01 - 12)")
384 X("%M" , "Minutes (00 - 59)")
385 X("%S" , "Seconds (00 - 59)")
386 X("%%" , "Literal % character")
388 "\t...and all other directives provided by strftime()\n\n"
390 "With the current choice, the file name might look like this:\n";
392 QString fn
= getFileName("echo123", "Skype Test Service", "myskype", "My Full Name",
393 QDateTime::currentDateTime(), pattern
);
395 if (fn
.contains(':'))
396 tip
+= "\n\nWARNING: Microsoft Windows does not allow colon characters (:) in file names.";
397 patternWidget
->setToolTip(tip
);
400 void PreferencesDialog::closePerCallerDialog() {
402 perCallerDialog
->accept();
405 // per caller preferences editor
407 PerCallerPreferencesDialog::PerCallerPreferencesDialog(QWidget
*parent
) : QDialog(parent
) {
408 setWindowTitle("Per Caller Preferences");
409 setWindowModality(Qt::WindowModal
);
410 setAttribute(Qt::WA_DeleteOnClose
);
412 model
= new PerCallerModel(this);
414 QHBoxLayout
*bighbox
= new QHBoxLayout(this);
415 QVBoxLayout
*vbox
= new QVBoxLayout
;
417 listWidget
= new QListView
;
418 listWidget
->setModel(model
);
419 listWidget
->setSelectionMode(QAbstractItemView::ExtendedSelection
);
420 listWidget
->setEditTriggers(QAbstractItemView::SelectedClicked
| QAbstractItemView::DoubleClicked
);
421 connect(listWidget
->selectionModel(), SIGNAL(selectionChanged(const QItemSelection
&, const QItemSelection
&)), this, SLOT(selectionChanged()));
422 vbox
->addWidget(listWidget
);
424 QVBoxLayout
*frame
= makeVFrame(vbox
, "Preference for selected Skype names:");
425 radioYes
= new QRadioButton("Automatically &record calls");
426 radioAsk
= new QRadioButton("&Ask every time");
427 radioNo
= new QRadioButton("Do ¬ automatically record calls");
428 connect(radioYes
, SIGNAL(clicked(bool)), this, SLOT(radioChanged()));
429 connect(radioAsk
, SIGNAL(clicked(bool)), this, SLOT(radioChanged()));
430 connect(radioNo
, SIGNAL(clicked(bool)), this, SLOT(radioChanged()));
431 frame
->addWidget(radioYes
);
432 frame
->addWidget(radioAsk
);
433 frame
->addWidget(radioNo
);
435 bighbox
->addLayout(vbox
);
437 vbox
= new QVBoxLayout
;
439 QPushButton
*button
= new QPushButton("A&dd");
440 connect(button
, SIGNAL(clicked(bool)), this, SLOT(add()));
441 vbox
->addWidget(button
);
443 button
= new QPushButton("Re&move");
444 connect(button
, SIGNAL(clicked(bool)), this, SLOT(remove()));
445 vbox
->addWidget(button
);
449 button
= new QPushButton("&Close");
450 button
->setDefault(true);
451 connect(button
, SIGNAL(clicked(bool)), this, SLOT(accept()));
452 vbox
->addWidget(button
);
454 bighbox
->addLayout(vbox
);
460 QStringList list
= preferences
.get(Pref::AutoRecordYes
).toList();
461 for (int i
= 0; i
< list
.count(); i
++) {
462 QString sn
= list
.at(i
);
463 if (seen
.contains(sn
))
469 list
= preferences
.get(Pref::AutoRecordAsk
).toList();
470 for (int i
= 0; i
< list
.count(); i
++) {
471 QString sn
= list
.at(i
);
472 if (seen
.contains(sn
))
478 list
= preferences
.get(Pref::AutoRecordNo
).toList();
479 for (int i
= 0; i
< list
.count(); i
++) {
480 QString sn
= list
.at(i
);
481 if (seen
.contains(sn
))
488 connect(this, SIGNAL(finished(int)), this, SLOT(save()));
493 void PerCallerPreferencesDialog::add(const QString
&name
, int mode
, bool edit
) {
494 int i
= model
->rowCount();
497 QModelIndex idx
= model
->index(i
, 0);
498 model
->setData(idx
, name
, Qt::EditRole
);
499 model
->setData(idx
, mode
, Qt::UserRole
);
502 listWidget
->clearSelection();
503 listWidget
->setCurrentIndex(idx
);
504 listWidget
->edit(idx
);
508 void PerCallerPreferencesDialog::remove() {
509 QModelIndexList sel
= listWidget
->selectionModel()->selectedIndexes();
511 while (!sel
.isEmpty())
512 model
->removeRow(sel
.takeLast().row());
515 void PerCallerPreferencesDialog::selectionChanged() {
516 QModelIndexList sel
= listWidget
->selectionModel()->selectedIndexes();
517 bool notEmpty
= !sel
.isEmpty();
519 while (!sel
.isEmpty()) {
520 int m
= model
->data(sel
.takeLast(), Qt::UserRole
).toInt();
523 } else if (mode
!= m
) {
529 // Qt is a bit annoying about this: You can't deselect
530 // everything unless you disable auto-exclusive mode
531 radioYes
->setAutoExclusive(false);
532 radioAsk
->setAutoExclusive(false);
533 radioNo
->setAutoExclusive(false);
534 radioYes
->setChecked(false);
535 radioAsk
->setChecked(false);
536 radioNo
->setChecked(false);
537 radioYes
->setAutoExclusive(true);
538 radioAsk
->setAutoExclusive(true);
539 radioNo
->setAutoExclusive(true);
540 } else if (mode
== 0) {
541 radioNo
->setChecked(true);
542 } else if (mode
== 1) {
543 radioAsk
->setChecked(true);
544 } else if (mode
== 2) {
545 radioYes
->setChecked(true);
548 radioYes
->setEnabled(notEmpty
);
549 radioAsk
->setEnabled(notEmpty
);
550 radioNo
->setEnabled(notEmpty
);
553 void PerCallerPreferencesDialog::radioChanged() {
555 if (radioYes
->isChecked())
557 else if (radioNo
->isChecked())
560 QModelIndexList sel
= listWidget
->selectionModel()->selectedIndexes();
561 while (!sel
.isEmpty())
562 model
->setData(sel
.takeLast(), mode
, Qt::UserRole
);
565 void PerCallerPreferencesDialog::save() {
567 int n
= model
->rowCount();
568 QStringList yes
, ask
, no
;
569 for (int i
= 0; i
< n
; i
++) {
570 QModelIndex idx
= model
->index(i
, 0);
571 QString sn
= model
->data(idx
, Qt::EditRole
).toString();
574 int mode
= model
->data(idx
, Qt::UserRole
).toInt();
582 preferences
.get(Pref::AutoRecordYes
).set(yes
);
583 preferences
.get(Pref::AutoRecordAsk
).set(ask
);
584 preferences
.get(Pref::AutoRecordNo
).set(no
);
589 int PerCallerModel::rowCount(const QModelIndex
&) const {
590 return skypeNames
.count();
594 const char *PerCallerModel_data_table
[3] = {
595 "Don't record", "Ask", "Automatic"
599 QVariant
PerCallerModel::data(const QModelIndex
&index
, int role
) const {
600 if (!index
.isValid() || index
.row() >= skypeNames
.size())
602 if (role
== Qt::DisplayRole
) {
604 return skypeNames
.at(i
) + " - " + PerCallerModel_data_table
[modes
.at(i
)];
606 if (role
== Qt::EditRole
)
607 return skypeNames
.at(index
.row());
608 if (role
== Qt::UserRole
)
609 return modes
.at(index
.row());
613 bool PerCallerModel::setData(const QModelIndex
&index
, const QVariant
&value
, int role
) {
614 if (!index
.isValid() || index
.row() >= skypeNames
.size())
616 if (role
== Qt::EditRole
) {
617 skypeNames
[index
.row()] = value
.toString();
618 emit
dataChanged(index
, index
);
621 if (role
== Qt::UserRole
) {
622 modes
[index
.row()] = value
.toInt();
623 emit
dataChanged(index
, index
);
629 bool PerCallerModel::insertRows(int position
, int rows
, const QModelIndex
&) {
630 beginInsertRows(QModelIndex(), position
, position
+ rows
- 1);
631 for (int i
= 0; i
< rows
; i
++) {
632 skypeNames
.insert(position
, "");
633 modes
.insert(position
, 1);
639 bool PerCallerModel::removeRows(int position
, int rows
, const QModelIndex
&) {
640 beginRemoveRows(QModelIndex(), position
, position
+ rows
- 1);
641 for (int i
= 0; i
< rows
; i
++) {
642 skypeNames
.removeAt(position
);
643 modes
.removeAt(position
);
649 void PerCallerModel::sort(int, Qt::SortOrder
) {
650 typedef QPair
<QString
, int> Pair
;
651 typedef QList
<Pair
> List
;
653 for (int i
= 0; i
< skypeNames
.size(); i
++)
654 list
.append(Pair(skypeNames
.at(i
), modes
.at(i
)));
656 for (int i
= 0; i
< skypeNames
.size(); i
++) {
657 skypeNames
[i
] = list
.at(i
).first
;
658 modes
[i
] = list
.at(i
).second
;
663 Qt::ItemFlags
PerCallerModel::flags(const QModelIndex
&index
) const {
664 Qt::ItemFlags flags
= QAbstractListModel::flags(index
);
665 if (!index
.isValid() || index
.row() >= skypeNames
.size())
667 return flags
| Qt::ItemIsEditable
;
672 void Preference::listAdd(const QString
&value
) {
673 QStringList list
= toList();
674 if (!list
.contains(value
)) {
680 void Preference::listRemove(const QString
&value
) {
681 QStringList list
= toList();
682 if (list
.removeAll(value
))
686 bool Preference::listContains(const QString
&value
) {
687 QStringList list
= toList();
688 return list
.contains(value
);
693 BasePreferences::~BasePreferences() {
697 bool BasePreferences::load(const QString
&filename
) {
699 QFile
file(filename
);
700 if (!file
.open(QIODevice::ReadOnly
| QIODevice::Text
)) {
701 debug(QString("Can't open '%1' for loading preferences").arg(filename
));
705 while (!file
.atEnd()) {
706 qint64 len
= file
.readLine(buf
, sizeof(buf
));
709 QString line
= QString::fromUtf8(buf
);
710 line
= line
.trimmed();
711 if (line
.at(0) == '#')
713 int index
= line
.indexOf('=');
717 get(line
.left(index
).trimmed()).set(line
.mid(index
+ 1).trimmed());
719 debug(QString("Loaded %1 preferences from '%2'").arg(prefs
.size()).arg(filename
));
724 bool comparePreferencePointers(const Preference
*p1
, const Preference
*p2
)
730 bool BasePreferences::save(const QString
&filename
) {
731 qSort(prefs
.begin(), prefs
.end(), comparePreferencePointers
);
732 QFile
file(filename
);
733 if (!file
.open(QIODevice::WriteOnly
| QIODevice::Text
)) {
734 debug(QString("Can't open '%1' for saving preferences").arg(filename
));
737 QTextStream
out(&file
);
738 for (int i
= 0; i
< prefs
.size(); i
++) {
739 const Preference
&p
= *prefs
.at(i
);
740 out
<< p
.name() << " = " << p
.toString() << "\n";
742 debug(QString("Saved %1 preferences to '%2'").arg(prefs
.size()).arg(filename
));
746 Preference
&BasePreferences::get(const QString
&name
) {
747 for (int i
= 0; i
< prefs
.size(); i
++)
748 if (prefs
.at(i
)->name() == name
)
750 prefs
.append(new Preference(name
));
751 return *prefs
.last();
754 void BasePreferences::remove(const QString
&name
) {
755 for (int i
= 0; i
< prefs
.size(); i
++) {
756 if (prefs
.at(i
)->name() == name
) {
757 delete prefs
.takeAt(i
);
763 bool BasePreferences::exists(const QString
&name
) const {
764 for (int i
= 0; i
< prefs
.size(); i
++)
765 if (prefs
.at(i
)->name() == name
)
770 void BasePreferences::clear() {
771 for (int i
= 0; i
< prefs
.size(); i
++)
778 void Preferences::setPerCallerPreference(const QString
&sn
, int mode
) {
779 // this would interfer with the per caller dialog
780 recorderInstance
->closePerCallerDialog();
782 Preference
&pYes
= get(Pref::AutoRecordYes
);
783 Preference
&pAsk
= get(Pref::AutoRecordAsk
);
784 Preference
&pNo
= get(Pref::AutoRecordNo
);