A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 439 lines 12 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2010 Robert Bieber 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21 22#include "projectmodel.h" 23#include "configdocument.h" 24#include "ui_configdocument.h" 25#include "preferencesdialog.h" 26 27#include <QMessageBox> 28#include <QFile> 29#include <QSettings> 30#include <QFileDialog> 31#include <QPair> 32 33ConfigDocument::ConfigDocument(QMap<QString, QString>& settings, QString file, 34 QWidget *parent) 35 : TabContent(parent), 36 ui(new Ui::ConfigDocument), 37 filePath(file), block(false) 38{ 39 ui->setupUi(this); 40 editor = new CodeEditor(this); 41 editor->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); 42 editor->setLineWrapMode(CodeEditor::NoWrap); 43 ui->splitter->addWidget(editor); 44 45 QObject::connect(editor, SIGNAL(textChanged()), 46 this, SLOT(textChanged())); 47 48 /* Loading the splitter status */ 49 QSettings appSettings; 50 appSettings.beginGroup("ConfigDocument"); 51 52 if(!appSettings.value("textVisible", true).toBool()) 53 { 54 editor->setVisible(false); 55 ui->textButton->setChecked(false); 56 } 57 else 58 { 59 ui->textButton->setChecked(true); 60 } 61 if(!appSettings.value("linesVisible", false).toBool()) 62 { 63 ui->scrollArea->setVisible(false); 64 ui->linesButton->setChecked(false); 65 } 66 else 67 { 68 ui->linesButton->setChecked(true); 69 } 70 71 if(!appSettings.value("splitter", QByteArray()).toByteArray().isNull()) 72 ui->splitter->restoreState(appSettings.value("splitter").toByteArray()); 73 74 appSettings.endGroup(); 75 76 /* Populating the known keys list */ 77 QFile fin(":/resources/configkeys"); 78 fin.open(QFile::ReadOnly); 79 80 QStringList* container = &primaryKeys; 81 while(!fin.atEnd()) 82 { 83 QString current = QString(fin.readLine()); 84 if(current == "-\n") 85 container = &secondaryKeys; 86 else if(current != "\n") 87 container->append(current.trimmed()); 88 } 89 90 /* Loading the text file */ 91 QFile finT(settings.value("configfile", "")); 92 if(finT.open(QFile::Text | QFile::ReadOnly)) 93 { 94 editor->setPlainText(QString(finT.readAll())); 95 finT.close(); 96 } 97 98 saved = toPlainText(); 99 100 QObject::connect(ui->addKeyButton, SIGNAL(pressed()), 101 this, SLOT(addClicked())); 102 103 QObject::connect(ui->linesButton, SIGNAL(toggled(bool)), 104 this, SLOT(buttonChecked())); 105 QObject::connect(ui->textButton, SIGNAL(toggled(bool)), 106 this, SLOT(buttonChecked())); 107 108 settingsChanged(); 109} 110 111ConfigDocument::~ConfigDocument() 112{ 113 delete ui; 114 editor->deleteLater(); 115} 116 117void ConfigDocument::changeEvent(QEvent *e) 118{ 119 QWidget::changeEvent(e); 120 switch (e->type()) { 121 case QEvent::LanguageChange: 122 ui->retranslateUi(this); 123 break; 124 default: 125 break; 126 } 127} 128 129QString ConfigDocument::title() const 130{ 131 QStringList decompose = filePath.split("/"); 132 return decompose.last(); 133} 134 135void ConfigDocument::save() 136{ 137 QFile fout(filePath); 138 139 if(!fout.exists()) 140 { 141 saveAs(); 142 return; 143 } 144 145 fout.open(QFile::WriteOnly); 146 fout.write(toPlainText().toLatin1()); 147 fout.close(); 148 149 saved = toPlainText(); 150 emit titleChanged(title()); 151 emit configFileChanged(file()); 152} 153 154void ConfigDocument::saveAs() 155{ 156 /* Determining the directory to open */ 157 QString directory = filePath; 158 159 QSettings settings; 160 settings.beginGroup("ProjectModel"); 161 if(directory == "") 162 directory = settings.value("defaultDirectory", "").toString(); 163 164 filePath = QFileDialog::getSaveFileName(this, tr("Save Document"), 165 directory, 166 ProjectModel::fileFilter()); 167 directory = filePath; 168 if(filePath == "") 169 return; 170 171 directory.chop(filePath.length() - filePath.lastIndexOf('/') - 1); 172 settings.setValue("defaultDirectory", directory); 173 settings.endGroup(); 174 175 QFile fout(filePath); 176 fout.open(QFile::WriteOnly); 177 fout.write(toPlainText().toLatin1()); 178 fout.close(); 179 180 saved = toPlainText(); 181 emit titleChanged(title()); 182 emit configFileChanged(file()); 183 184} 185 186bool ConfigDocument::requestClose() 187{ 188 if(toPlainText() != saved) 189 { 190 /* Spawning the "Are you sure?" dialog */ 191 QMessageBox confirm(this); 192 confirm.setWindowTitle(tr("Confirm Close")); 193 confirm.setText(title() + tr(" has been modified.")); 194 confirm.setInformativeText(tr("Do you want to save your changes?")); 195 confirm.setStandardButtons(QMessageBox::Save | QMessageBox::Discard 196 | QMessageBox::Cancel); 197 confirm.setDefaultButton(QMessageBox::Save); 198 int confirmation = confirm.exec(); 199 200 switch(confirmation) 201 { 202 case QMessageBox::Save: 203 save(); 204 /* After calling save, make sure the user actually went through */ 205 if(toPlainText() != saved) 206 return false; 207 else 208 return true; 209 210 case QMessageBox::Discard: 211 return true; 212 213 case QMessageBox::Cancel: 214 return false; 215 } 216 } 217 return true; 218} 219 220QString ConfigDocument::toPlainText() const 221{ 222 return editor->toPlainText(); 223} 224 225void ConfigDocument::syncFromBoxes() 226{ 227 if(block) 228 return; 229 blockUpdates(); 230 231 QString buffer = ""; 232 233 for(int i = 0; i < keys.count(); i++) 234 { 235 buffer += keys[i]->currentText(); 236 buffer += ":"; 237 buffer += values[i]->text(); 238 buffer += "\n"; 239 } 240 241 editor->setPlainText(buffer); 242} 243 244void ConfigDocument::syncFromText() 245{ 246 if(block) 247 return; 248 249 blockUpdates(); 250 251 QStringList lines = editor->toPlainText().split("\n"); 252 QList<QPair<QString, QString> > splits; 253 for(int i = 0; i < lines.count(); i++) 254 { 255 QString line = lines[i]; 256 QStringList split = line.split(":"); 257 if(split.count() != 2) 258 continue; 259 260 splits.append(QPair<QString, QString>(split[0].trimmed(), 261 split[1].trimmed())); 262 } 263 264 while(deleteButtons.count() > splits.count()) 265 { 266 deleteButtons[0]->deleteLater(); 267 keys[0]->deleteLater(); 268 values[0]->deleteLater(); 269 containers[0]->deleteLater(); 270 labels[0]->deleteLater(); 271 272 deleteButtons.removeAt(0); 273 keys.removeAt(0); 274 values.removeAt(0); 275 containers.removeAt(0); 276 labels.removeAt(0); 277 } 278 279 int initialCount = deleteButtons.count(); 280 for(int i = 0; i < splits.count(); i++) 281 { 282 if(i >= initialCount) 283 { 284 addRow(splits[i].first, splits[i].second); 285 } 286 else 287 { 288 int index = keys[i]->findText(splits[i].first); 289 if(index != -1) 290 keys[i]->setCurrentIndex(index); 291 else 292 keys[i]->setEditText(splits[i].first); 293 values[i]->setText(splits[i].second); 294 } 295 } 296} 297 298void ConfigDocument::addRow(QString key, QString value) 299{ 300 QHBoxLayout* layout = new QHBoxLayout(); 301 NoScrollCombo* keyEdit = new NoScrollCombo(this); 302 QLineEdit* valueEdit = new QLineEdit(value, this); 303 QPushButton* delButton = new QPushButton(tr("-"), this); 304 QLabel* label = new QLabel(":"); 305 306 /* Loading the combo box options */ 307 keyEdit->setInsertPolicy(QComboBox::InsertAlphabetically); 308 keyEdit->setEditable(true); 309 keyEdit->addItems(primaryKeys); 310 keyEdit->insertSeparator(keyEdit->count()); 311 keyEdit->addItems(secondaryKeys); 312 if(keyEdit->findText(key) != -1) 313 keyEdit->setCurrentIndex(keyEdit->findText(key)); 314 else 315 keyEdit->setEditText(key); 316 317 318 layout->addWidget(keyEdit); 319 layout->addWidget(label); 320 layout->addWidget(valueEdit); 321 layout->addWidget(delButton); 322 323 delButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); 324 delButton->setMaximumWidth(35); 325 326 QObject::connect(delButton, SIGNAL(clicked()), 327 this, SLOT(deleteClicked())); 328 QObject::connect(keyEdit, SIGNAL(currentIndexChanged(QString)), 329 this, SLOT(boxesChanged())); 330 QObject::connect(keyEdit, SIGNAL(textChanged(QString)), 331 this, SLOT(boxesChanged())); 332 QObject::connect(valueEdit, SIGNAL(textChanged(QString)), 333 this, SLOT(boxesChanged())); 334 335 ui->configBoxes->addLayout(layout); 336 337 containers.append(layout); 338 keys.append(keyEdit); 339 values.append(valueEdit); 340 deleteButtons.append(delButton); 341 labels.append(label); 342 343} 344 345void ConfigDocument::deleteClicked() 346{ 347 QPushButton* button = dynamic_cast<QPushButton*>(sender()); 348 int row = deleteButtons.indexOf(button); 349 350 deleteButtons[row]->deleteLater(); 351 keys[row]->deleteLater(); 352 values[row]->deleteLater(); 353 containers[row]->deleteLater(); 354 labels[row]->deleteLater(); 355 356 deleteButtons.removeAt(row); 357 keys.removeAt(row); 358 values.removeAt(row); 359 containers.removeAt(row); 360 labels.removeAt(row); 361 362 if(saved != toPlainText()) 363 emit titleChanged(title() + "*"); 364 else 365 emit titleChanged(title()); 366} 367 368void ConfigDocument::addClicked() 369{ 370 addRow(tr("Key"), tr("Value")); 371} 372 373void ConfigDocument::boxesChanged() 374{ 375 syncFromBoxes(); 376 contentsChanged(); 377} 378 379void ConfigDocument::textChanged() 380{ 381 syncFromText(); 382 contentsChanged(); 383} 384 385void ConfigDocument::contentsChanged() 386{ 387 if(toPlainText() != saved) 388 emit titleChanged(title() + "*"); 389 else 390 emit titleChanged(title()); 391} 392 393void ConfigDocument::buttonChecked() 394{ 395 editor->setVisible(ui->textButton->isChecked()); 396 ui->scrollArea->setVisible(ui->linesButton->isChecked()); 397 398 QSettings settings; 399 settings.beginGroup("ConfigDocument"); 400 settings.setValue("textVisible", ui->textButton->isChecked()); 401 settings.setValue("linesVisible", ui->linesButton->isChecked()); 402 settings.endGroup(); 403} 404 405void ConfigDocument::connectPrefs(PreferencesDialog *prefs) 406{ 407 QObject::connect(prefs, SIGNAL(accepted()), 408 this, SLOT(settingsChanged())); 409} 410 411 412void ConfigDocument::settingsChanged() 413{ 414 /* Setting the editor colors */ 415 QSettings settings; 416 settings.beginGroup("SkinDocument"); 417 418 QColor fg = settings.value("fgColor", QColor(Qt::black)).value<QColor>(); 419 QColor bg = settings.value("bgColor", QColor(Qt::white)).value<QColor>(); 420 QPalette palette; 421 palette.setColor(QPalette::All, QPalette::Base, bg); 422 palette.setColor(QPalette::All, QPalette::Text, fg); 423 editor->setPalette(palette); 424 425 QColor highlight = settings.value("errorColor", QColor(Qt::red)).value<QColor>(); 426 editor->setErrorColor(highlight); 427 428 /* Setting the font */ 429 QFont def("Monospace"); 430 def.setStyleHint(QFont::TypeWriter); 431 QFont family = settings.value("fontFamily", def).value<QFont>(); 432 family.setPointSize(settings.value("fontSize", 12).toInt()); 433 editor->setFont(family); 434 435 editor->repaint(); 436 437 settings.endGroup(); 438 439}