A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 570 lines 16 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 "devicestate.h" 23 24#include <QScrollArea> 25#include <QFile> 26#include <QCheckBox> 27#include <QSpinBox> 28#include <QComboBox> 29#include <QVBoxLayout> 30#include <QLabel> 31#include <QLineEdit> 32#include <QFormLayout> 33#include <QTime> 34 35#include <cstdlib> 36 37DeviceState::DeviceState(QWidget *parent) : 38 QWidget(parent), tabs(this) 39{ 40 /* UI stuff */ 41 resize(500,400); 42 setWindowIcon(QIcon(":/resources/windowicon.png")); 43 setWindowTitle(tr("Device Settings")); 44 45 QFormLayout* layout = new QFormLayout(this); 46 layout->addWidget(&tabs); 47 this->setLayout(layout); 48 49 /* Loading the tabs */ 50 QScrollArea* currentArea = 0; 51 QWidget* panel; 52 53 QFile fin(":/resources/deviceoptions"); 54 fin.open(QFile::Text | QFile::ReadOnly); 55 while(!fin.atEnd()) 56 { 57 QString line = QString(fin.readLine()); 58 line = line.trimmed(); 59 60 /* Continue on a comment or an empty line */ 61 if(line[0] == '#' || line.length() == 0) 62 continue; 63 64 if(line[0] == '[') 65 { 66 QString buffer; 67 for(int i = 1; line[i] != ']'; i++) 68 buffer.append(line[i]); 69 buffer = buffer.trimmed(); 70 71 panel = new QWidget(); 72 currentArea = new QScrollArea(); 73 layout = new QFormLayout(panel); 74 currentArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); 75 currentArea->setWidget(panel); 76 currentArea->setWidgetResizable(true); 77 78 tabs.addTab(currentArea, buffer); 79 80 continue; 81 } 82 83 QStringList elements = line.split(";"); 84 QString tag = elements[0].trimmed(); 85 QString title = elements[1].trimmed(); 86 QString type = elements[2].trimmed(); 87 QString defVal = elements[3].trimmed(); 88 89 elements = type.split("("); 90 if(elements[0].trimmed() == "text") 91 { 92 QLineEdit* temp = new QLineEdit(defVal, currentArea); 93 layout->addRow(title, temp); 94 inputs.insert(tag, QPair<InputType, QWidget*>(Text, temp)); 95 96 temp->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, 97 QSizePolicy::Fixed)); 98 99 QObject::connect(temp, SIGNAL(textChanged(QString)), 100 this, SLOT(input())); 101 } 102 else if(elements[0].trimmed() == "check") 103 { 104 QCheckBox* temp = new QCheckBox(title, currentArea); 105 layout->addRow(temp); 106 if(defVal.toLower() == "true") 107 temp->setChecked(true); 108 else 109 temp->setChecked(false); 110 inputs.insert(tag, QPair<InputType, QWidget*>(Check, temp)); 111 112 QObject::connect(temp, SIGNAL(toggled(bool)), 113 this, SLOT(input())); 114 } 115 else if(elements[0].trimmed() == "slider") 116 { 117 elements = elements[1].trimmed().split(","); 118 int min = elements[0].trimmed().toInt(); 119 QString maxS = elements[1].trimmed(); 120 maxS.chop(1); 121 int max = maxS.toInt(); 122 123 QSlider* temp = new QSlider(Qt::Horizontal, currentArea); 124 temp->setMinimum(min); 125 temp->setMaximum(max); 126 temp->setValue(defVal.toInt()); 127 layout->addRow(title, temp); 128 inputs.insert(tag, QPair<InputType, QWidget*>(Slide, temp)); 129 130 QObject::connect(temp, SIGNAL(valueChanged(int)), 131 this, SLOT(input())); 132 } 133 else if(elements[0].trimmed() == "spin") 134 { 135 elements = elements[1].trimmed().split(","); 136 int min = elements[0].trimmed().toInt(); 137 QString maxS = elements[1].trimmed(); 138 maxS.chop(1); 139 int max = maxS.toInt(); 140 141 QSpinBox* temp = new QSpinBox(currentArea); 142 temp->setMinimum(min); 143 temp->setMaximum(max); 144 temp->setValue(defVal.toInt()); 145 layout->addRow(title, temp); 146 inputs.insert(tag, QPair<InputType, QWidget*>(Spin, temp)); 147 148 QObject::connect(temp, SIGNAL(valueChanged(int)), 149 this, SLOT(input())); 150 } 151 else if(elements[0].trimmed() == "fspin") 152 { 153 elements = elements[1].trimmed().split(","); 154 int min = elements[0].trimmed().toDouble(); 155 QString maxS = elements[1].trimmed(); 156 maxS.chop(1); 157 int max = maxS.toDouble(); 158 159 QDoubleSpinBox* temp = new QDoubleSpinBox(currentArea); 160 temp->setMinimum(min); 161 temp->setMaximum(max); 162 temp->setValue(defVal.toDouble()); 163 temp->setSingleStep(0.1); 164 layout->addRow(title, temp); 165 inputs.insert(tag, QPair<InputType, QWidget*>(DSpin, temp)); 166 167 QObject::connect(temp, SIGNAL(valueChanged(double)), 168 this, SLOT(input())); 169 } 170 else if(elements[0].trimmed() == "combo") 171 { 172 elements = elements[1].trimmed().split(","); 173 174 int defIndex = 0; 175 QComboBox* temp = new QComboBox(currentArea); 176 for(int i = 0; i < elements.count(); i++) 177 { 178 QString current = elements[i].trimmed(); 179 if(i == elements.count() - 1) 180 current.chop(1); 181 temp->addItem(current, i); 182 if(current == defVal) 183 defIndex = i; 184 } 185 temp->setCurrentIndex(defIndex); 186 layout->addRow(title, temp); 187 inputs.insert(tag, QPair<InputType, QWidget*>(Combo, temp)); 188 189 QObject::connect(temp, SIGNAL(currentIndexChanged(int)), 190 this, SLOT(input())); 191 } 192 193 } 194} 195 196DeviceState::~DeviceState() 197{ 198} 199 200QVariant DeviceState::data(QString tag, int paramCount, 201 skin_tag_parameter *params) 202{ 203 /* Handling special cases */ 204 if(tag.toLower() == "fm") 205 { 206 QString path = tag[0].isLower() 207 ? data("file").toString() : data("nextfile").toString(); 208 return fileName(path, true); 209 } 210 else if(tag.toLower() == "fn") 211 { 212 QString path = tag[0].isLower() 213 ? data("file").toString() : data("nextfile").toString(); 214 return fileName(path, false); 215 } 216 else if(tag.toLower() == "fp") 217 { 218 if(tag[0].isLower()) 219 return data("file").toString(); 220 else 221 return data("nextfile").toString(); 222 } 223 else if(tag.toLower() == "d") 224 { 225 QString path = tag[0].isLower() 226 ? data("file").toString() : data("nextfile").toString(); 227 if(paramCount > 0) 228 return directory(path, params[0].data.number); 229 else 230 return QVariant(); 231 } 232 else if(tag == "pc") 233 { 234 int secs = data("?pc").toInt(); 235 return secsToString(secs); 236 } 237 else if(tag == "pr") 238 { 239 int secs = data("?pt").toInt() - data("?pc").toInt(); 240 if(secs < 0) 241 secs = 0; 242 return secsToString(secs); 243 } 244 else if(tag == "pt") 245 { 246 int secs = data("?pt").toInt(); 247 return secsToString(secs); 248 } 249 else if(tag == "px") 250 { 251 int totalTime = data("?pt").toInt(); 252 int currentTime = data("?pc").toInt(); 253 return currentTime * 100 / totalTime; 254 } 255 else if(tag == "pS") 256 { 257 double threshhold = paramCount > 0 258 ? params[0].data.number / 10. : 10; 259 if(data("?pc").toDouble() <= threshhold) 260 return true; 261 else 262 return false; 263 } 264 else if(tag == "pE") 265 { 266 double threshhold = paramCount > 0 267 ? params[0].data.number / 10. : 10; 268 if(data("?pt").toDouble() - data("?pc").toDouble() <= threshhold) 269 return true; 270 else 271 return false; 272 } 273 else if(tag == "ce") 274 { 275 return data("month"); 276 } 277 else if(tag == "cH") 278 { 279 int hour = data("hour").toInt(); 280 if(hour < 10) 281 return "0" + QString::number(hour); 282 else 283 return hour; 284 } 285 else if(tag == "cK") 286 { 287 return data("hour"); 288 } 289 else if(tag == "cI") 290 { 291 int hour = data("hour").toInt(); 292 if(hour > 12) 293 hour -= 12; 294 if(hour == 0) 295 hour = 12; 296 297 if(hour < 10) 298 return "0" + QString::number(hour); 299 else 300 return hour; 301 } 302 else if(tag == "cl") 303 { 304 int hour = data("hour").toInt(); 305 if(hour > 12) 306 hour -= 12; 307 if(hour == 0) 308 hour = 12; 309 310 return hour; 311 } 312 else if(tag == "cm") 313 { 314 int month = data("?cm").toInt() + 1; 315 if(month < 10) 316 return "0" + QString::number(month); 317 else 318 return month; 319 } 320 else if(tag == "cd") 321 { 322 int day = data("day").toInt(); 323 if(day < 10) 324 return "0" + QString::number(day); 325 else 326 return day; 327 } 328 else if(tag == "cM") 329 { 330 int minute = data("minute").toInt(); 331 if(minute < 10) 332 return "0" + QString::number(minute); 333 else 334 return minute; 335 } 336 else if(tag == "cS") 337 { 338 int second = data("second").toInt(); 339 if(second < 10) 340 return "0" + QString::number(second); 341 else 342 return second; 343 } 344 else if(tag == "cy") 345 { 346 QString year = data("cY").toString(); 347 return year.right(2); 348 } 349 else if(tag == "cP") 350 { 351 if(data("hour").toInt() >= 12) 352 return "PM"; 353 else 354 return "AM"; 355 } 356 else if(tag == "cp") 357 { 358 if(data("hour").toInt() >= 12) 359 return "pm"; 360 else 361 return "am"; 362 } 363 else if(tag == "ca") 364 { 365 switch(data("cw").toInt()) 366 { 367 case 0: return "Sun"; 368 case 1: return "Mon"; 369 case 2: return "Tue"; 370 case 3: return "Wed"; 371 case 4: return "Thu"; 372 case 5: return "Fri"; 373 case 6: return "Sat"; 374 default: return tr("Error, invalid weekday number"); 375 } 376 } 377 else if(tag == "cb") 378 { 379 int month = data("cm").toInt(); 380 switch(month) 381 { 382 case 1: return "Jan"; 383 case 2: return "Feb"; 384 case 3: return "Mar"; 385 case 4: return "Apr"; 386 case 5: return "May"; 387 case 6: return "Jun"; 388 case 7: return "Jul"; 389 case 8: return "Aug"; 390 case 9: return "Sep"; 391 case 10: return "Oct"; 392 case 11: return "Nov"; 393 case 12: return "Dec"; 394 } 395 } 396 else if(tag == "cu") 397 { 398 int day = data("?cw").toInt(); 399 if(day == 0) 400 day = 7; 401 return day; 402 } 403 else if(tag == "?cu") 404 { 405 int day = data("?cw").toInt() - 1; 406 if(day == -1) 407 day = 6; 408 return day; 409 } 410 else if(tag == "cw") 411 { 412 return data("?cw"); 413 } 414 else if(tag == "cs") 415 { 416 int seconds = data("seconds").toInt(); 417 if(seconds < 10) 418 return "0" + QString::number(seconds); 419 else 420 return seconds; 421 } 422 423 QPair<InputType, QWidget*> found = 424 inputs.value(tag, QPair<InputType, QWidget*>(Slide, 0)); 425 426 if(found.second == 0 && tag[0] == '?') 427 found = inputs.value(tag.right(2), QPair<InputType, QWidget*>(Slide,0)); 428 429 if(found.second == 0) 430 return QVariant(); 431 432 switch(found.first) 433 { 434 case Text: 435 return dynamic_cast<QLineEdit*>(found.second)->text(); 436 437 case Slide: 438 return dynamic_cast<QSlider*>(found.second)->value(); 439 440 case Spin: 441 return dynamic_cast<QSpinBox*>(found.second)->value(); 442 443 case DSpin: 444 return dynamic_cast<QDoubleSpinBox*>(found.second)->value(); 445 446 case Combo: 447 if(tag[0] == '?') 448 return dynamic_cast<QComboBox*>(found.second)->currentIndex(); 449 else 450 return dynamic_cast<QComboBox*>(found.second)->currentText(); 451 452 case Check: 453 return dynamic_cast<QCheckBox*>(found.second)->isChecked(); 454 } 455 456 return QVariant(); 457} 458 459void DeviceState::setData(QString tag, QVariant data) 460{ 461 QPair<InputType, QWidget*> found = 462 inputs.value(tag, QPair<InputType, QWidget*>(Slide, 0)); 463 464 if(found.second == 0) 465 return; 466 467 switch(found.first) 468 { 469 case Text: 470 dynamic_cast<QLineEdit*>(found.second)->setText(data.toString()); 471 break; 472 473 case Slide: 474 dynamic_cast<QSlider*>(found.second)->setValue(data.toInt()); 475 break; 476 477 case Spin: 478 dynamic_cast<QSpinBox*>(found.second)->setValue(data.toInt()); 479 break; 480 481 case DSpin: 482 dynamic_cast<QDoubleSpinBox*>(found.second)->setValue(data.toDouble()); 483 break; 484 485 case Combo: 486 if(data.type() == QVariant::String) 487 dynamic_cast<QComboBox*> 488 (found.second)-> 489 setCurrentIndex(dynamic_cast<QComboBox*> 490 (found.second)->findText(data.toString())); 491 else 492 dynamic_cast<QComboBox*>(found.second)-> 493 setCurrentIndex(data.toInt()); 494 break; 495 496 case Check: 497 dynamic_cast<QCheckBox*>(found.second)->setChecked(data.toBool()); 498 break; 499 } 500 501 emit settingsChanged(); 502} 503 504void DeviceState::input() 505{ 506 emit settingsChanged(); 507} 508 509QString DeviceState::fileName(QString path, bool extension) 510{ 511 path = path.split("/").last(); 512 if(!extension) 513 { 514 QString sum; 515 QStringList name = path.split("."); 516 for(int i = 0; i < name.count() - 1; i++) 517 sum.append(name[i]); 518 return sum; 519 } 520 else 521 { 522 return path; 523 } 524} 525 526QString DeviceState::directory(QString path, int level) 527{ 528 QStringList dirs = path.split("/"); 529 int index = dirs.count() - 1 - level; 530 if(index < 0) 531 index = 0; 532 return dirs[index]; 533} 534 535QString DeviceState::secsToString(int secs) 536{ 537 int hours = 0; 538 int minutes = 0; 539 while(secs >= 60) 540 { 541 minutes++; 542 secs -= 60; 543 } 544 545 while(minutes >= 60) 546 { 547 hours++; 548 minutes -= 60; 549 } 550 551 QString retval; 552 553 if(hours > 0) 554 { 555 retval += QString::number(hours); 556 if(minutes < 10) 557 retval += ":0"; 558 else 559 retval += ":"; 560 } 561 562 retval += QString::number(minutes); 563 if(secs < 10) 564 retval += ":0"; 565 else 566 retval += ":"; 567 568 retval += QString::number(secs); 569 return retval; 570}