Created
March 18, 2015 00:07
-
-
Save anonymous/54424daa79a8bc6b0690 to your computer and use it in GitHub Desktop.
qtunes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ====================================================================== | |
// IMPROC: Image Processing Software Package | |
// Copyright (C) 2015 by George Wolberg | |
// | |
// main.cpp - main() function. | |
// | |
// Written by: George Wolberg, 2015 | |
// ====================================================================== | |
#include <QApplication> | |
#include "MainWindow.h" | |
int main(int argc, char **argv) { | |
// init variables and application font | |
QString program = argv[0]; | |
QApplication app(argc, argv); | |
// invoke MainWindow constructor | |
MainWindow window(program); | |
// display MainWindow | |
window.show(); | |
return app.exec(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ====================================================================== | |
// IMPROC: Image Processing Software Package | |
// Copyright (C) 2015 by George Wolberg | |
// | |
// MainWindow.cpp - Main Window widget | |
// | |
// Written by: George Wolberg, 2015 | |
// ====================================================================== | |
#include <QtWidgets> | |
//#include <audiere.h> | |
#include <fileref.h> | |
#include <tag.h> | |
#include <tpropertymap.h> | |
#include "MainWindow.h" | |
#include <iostream> | |
#include <iomanip> | |
#include <stdio.h> | |
#include <QString> | |
#include <QByteArray> | |
#include <sstream> | |
#include <audioproperties.h> | |
#include <tfile.h> | |
using namespace std; | |
//using namespace audiere; | |
enum {TITLE, TRACK, TIME, ARTIST, ALBUM, GENRE, PATH}; | |
const int COLS = PATH; | |
bool caseInsensitive(const QString &s1, const QString &s2) | |
{ | |
return s1.toLower() < s2.toLower(); | |
} | |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
// MainWindow::MainWindow: | |
// | |
// Constructor. Initialize user-interface elements. | |
// | |
MainWindow::MainWindow (QString program) | |
: m_directory(".") | |
{ | |
// setup GUI with actions, menus, widgets, and layouts | |
createActions(); // create actions for each menu item | |
createMenus (); // create menus and associate actions | |
createWidgets(); // create window widgets | |
createLayouts(); // create widget layouts | |
// populate the list widgets with music library data | |
initLists(); // init list widgets | |
// set main window titlebar | |
QString copyright = "Copyright (C) 2015 by George Wolberg"; | |
QString version = "Version 1.0"; | |
QString title = QString("%1 (%2) %3") | |
.arg(program).arg(version).arg(copyright); | |
setWindowTitle(title); | |
// set central widget and default size | |
setCentralWidget(m_mainSplit); | |
setMinimumSize(400, 300); | |
resize(800, 600); | |
} | |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
// MainWindow::~MainWindow: | |
// | |
// Destructor. Save settings. | |
// | |
MainWindow::~MainWindow() {} | |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
// MainWindow::createActions: | |
// | |
// Create actions to associate with menu and toolbar selection. | |
// | |
void | |
MainWindow::createActions() | |
{ | |
m_loadAction = new QAction("&Load Music Folder", this); | |
m_loadAction->setShortcut(tr("Ctrl+L")); | |
connect(m_loadAction, SIGNAL(triggered()), this, SLOT(s_load())); | |
m_quitAction = new QAction("&Quit", this); | |
m_quitAction->setShortcut(tr("Ctrl+Q")); | |
connect(m_quitAction, SIGNAL(triggered()), this, SLOT(close())); | |
m_aboutAction = new QAction("&About", this); | |
m_aboutAction->setShortcut(tr("Ctrl+A")); | |
connect(m_aboutAction, SIGNAL(triggered()), this, SLOT(s_about())); | |
} | |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
// MainWindow::createMenus: | |
// | |
// Create menus and install in menubar. | |
// | |
void | |
MainWindow::createMenus() | |
{ | |
m_fileMenu = menuBar()->addMenu("&File"); | |
m_fileMenu->addAction(m_loadAction); | |
m_fileMenu->addAction(m_quitAction); | |
m_helpMenu = menuBar()->addMenu("&Help"); | |
m_helpMenu->addAction(m_aboutAction); | |
} | |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
// MainWindow::createWidgets: | |
// | |
// Create widgets to put in the layout. | |
// | |
void | |
MainWindow::createWidgets() | |
{ | |
// initialize splitters | |
m_mainSplit = new QSplitter(this); | |
m_leftSplit = new QSplitter(Qt::Vertical, m_mainSplit); | |
m_rightSplit = new QSplitter(Qt::Vertical, m_mainSplit); | |
// init labels on left side of main splitter | |
for(int i=0; i<2; i++) { | |
m_labelSide[i] = new QLabel(QString("Label%1").arg(i)); | |
m_labelSide[i]->setAlignment(Qt::AlignCenter); | |
} | |
// initialize label on right side of main splitter | |
for(int i=0; i<3; i++) { | |
// make label widget with centered text and sunken panels | |
m_label[i] = new QLabel; | |
m_label[i]->setAlignment(Qt::AlignCenter); | |
m_label[i]->setFrameStyle(QFrame::Panel | QFrame::Sunken); | |
} | |
// initialize label text | |
m_label[0]->setText("<b>Genre<\b>" ); | |
m_label[1]->setText("<b>Artist<\b>"); | |
m_label[2]->setText("<b>Album<\b>" ); | |
// initialize list widgets: genre, artist, album | |
for(int i=0; i<3; i++) | |
m_panel[i] = new QListWidget; | |
// initialize table widget: complete song data | |
m_table = new QTableWidget(0, COLS); | |
QHeaderView *header = new QHeaderView(Qt::Horizontal,m_table); | |
//header->setResizeMode(QHeaderView::Stretch); | |
m_table->setHorizontalHeader(header); | |
m_table->setHorizontalHeaderLabels(QStringList() << | |
"Name" << "Track" << "Time" << "Artist" << "Album" << "Genre"); | |
m_table->setAlternatingRowColors(1); | |
m_table->setShowGrid(1); | |
m_table->setEditTriggers (QAbstractItemView::NoEditTriggers); | |
m_table->setSelectionBehavior(QAbstractItemView::SelectRows); | |
// init signal/slot connections | |
connect(m_panel[0], SIGNAL(itemClicked(QListWidgetItem*)), | |
this, SLOT(s_panel1 (QListWidgetItem*))); | |
connect(m_panel[1], SIGNAL(itemClicked(QListWidgetItem*)), | |
this, SLOT(s_panel2 (QListWidgetItem*))); | |
connect(m_panel[2], SIGNAL(itemClicked(QListWidgetItem*)), | |
this, SLOT(s_panel3 (QListWidgetItem*))); | |
// connect(m_table, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), | |
// this, SLOT(s_play (QTableWidgetItem*))); | |
} | |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
// MainWindow::createLayouts: | |
// | |
// Create layouts for widgets. | |
// | |
void | |
MainWindow::createLayouts() | |
{ | |
// create a 2-row, 3-column grid layout, where row0 and | |
// row1 consist of labels and list widgets, respectively. | |
QWidget *widget = new QWidget(this); | |
QGridLayout *grid = new QGridLayout(widget); | |
grid->addWidget(m_label[0], 0, 0); | |
grid->addWidget(m_label[1], 0, 1); | |
grid->addWidget(m_label[2], 0, 2); | |
grid->addWidget(m_panel[0], 1, 0); | |
grid->addWidget(m_panel[1], 1, 1); | |
grid->addWidget(m_panel[2], 1, 2); | |
// add widgets to the splitters | |
m_stop = new QPushButton("Stop", m_labelSide[0]); | |
m_leftSplit ->addWidget(m_labelSide[0]); | |
m_leftSplit ->addWidget(m_labelSide[1]); | |
m_rightSplit->addWidget(widget ); | |
m_rightSplit->addWidget(m_table); | |
// set main splitter sizes | |
setSizes(m_mainSplit, (int)(width ()*.2), (int)(width ()*.8)); | |
setSizes(m_leftSplit, (int)(height()*.5), (int)(height()*.5)); | |
setSizes(m_rightSplit,(int)(height()*.4), (int)(height()*.6)); | |
} | |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
// MainWindow::initLists: | |
// | |
// Populate lists with data (first time). | |
// | |
void | |
MainWindow::initLists() | |
{ | |
// error checking | |
if(m_listSongs.isEmpty()) return; | |
// create separate lists for genres, artists, and albums | |
for(int i=0; i<m_listSongs.size(); i++) { | |
m_listGenre << m_listSongs[i][GENRE ]; | |
// do same for m_listArtist and m_listAlbum using ARTIST and ALBUM constants | |
m_listArtist << m_listSongs[i][ARTIST ]; | |
m_listAlbum << m_listSongs[i][ALBUM ]; | |
} | |
// sort each list | |
qStableSort(m_listGenre .begin(), m_listGenre .end(), caseInsensitive); | |
qStableSort(m_listArtist.begin(), m_listArtist.end(), caseInsensitive); | |
qStableSort(m_listAlbum .begin(), m_listAlbum .end(), caseInsensitive); | |
// add each list to list widgets, filtering out repeated strings | |
for(int i=0; i<m_listGenre.size(); i+=m_listGenre.count(m_listGenre[i])) | |
m_panel[0]->addItem(m_listGenre [i]); | |
// do same for m_listArtist and m_listAlbum to populate m_panel[1] and m_panel[2] | |
for(int i=0; i<m_listArtist.size(); i+=m_listArtist.count(m_listArtist[i])) | |
m_panel[1]->addItem(m_listArtist [i]); | |
for(int i=0; i<m_listAlbum.size(); i+=m_listAlbum.count(m_listAlbum[i])) | |
m_panel[2]->addItem(m_listAlbum [i]); | |
// copy data to table widget | |
QTableWidgetItem *item[COLS]; | |
for(int i=0; i<m_listSongs.size(); i++) { | |
m_table->insertRow(i); | |
for(int j=0; j<COLS; j++) { | |
item[j] = new QTableWidgetItem; | |
item[j]->setText(m_listSongs[i][j]); | |
item[j]->setTextAlignment(Qt::AlignCenter); | |
m_table->setItem(i, j, item[j]); | |
} | |
} | |
} | |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
// MainWindow::redrawLists: | |
// | |
// Re-populate lists with data matching item's text in field x. | |
// | |
void | |
MainWindow::redrawLists(QListWidgetItem *listItem, int x) | |
{ | |
m_table->setRowCount(0); | |
// copy data to table widget | |
for(int i=0,row=0; i<m_listSongs.size(); i++) { | |
// skip rows whose field doesn't match text | |
if(m_listSongs[i][x] != listItem->text()) continue; | |
m_table->insertRow(row); | |
QTableWidgetItem *item[COLS]; | |
for(int j=0; j<COLS; j++) { | |
item[j] = new QTableWidgetItem; | |
item[j]->setText(m_listSongs[i][j]); | |
item[j]->setTextAlignment(Qt::AlignCenter); | |
// put item[j] into m_table in proper row and column j | |
m_table->setItem(i, j, item[j]); | |
} | |
// increment table row index (row <= i) | |
row++; | |
} | |
} | |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
// MainWindow::traverseDirs: | |
// | |
// Traverse all subdirectories and collect filenames into m_listSongs. | |
// | |
void | |
MainWindow::traverseDirs(QString path) | |
{ | |
QString key, val; | |
QStringList list; | |
// init listDirs with subdirectories of path | |
QDir dir(path); | |
dir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot); | |
QFileInfoList listDirs = dir.entryInfoList(); | |
// init listFiles with all *.mp3 files in path | |
QDir files(path); | |
files.setFilter(QDir::Files); | |
files.setNameFilters(QStringList("*.mp3")); | |
QFileInfoList listFiles = files.entryInfoList(); | |
m_progressBar->setMaximum(listFiles.size()); | |
for(int i=0; i < listFiles.size(); i++) { | |
// adjust progress dialog to current settings (optional for now) | |
//.... | |
// init list with default values: "" | |
for(int j=0; j<=COLS; j++) | |
list.insert(j, ""); | |
// store file pathname into 0th position in list | |
QFileInfo fileInfo = listFiles.at(i); | |
list.replace(PATH, fileInfo.filePath()); | |
TagLib::FileRef f(list[PATH].toAscii()); | |
TagLib::Tag *tag = f.tag(); | |
list.replace(TITLE , QString::fromStdString(tag->title().to8Bit())); | |
list.replace(TIME , "Not Yet"); | |
list.replace(ARTIST , QString::fromStdString(tag->artist().to8Bit())); | |
list.replace(ALBUM , QString::fromStdString(tag->album().to8Bit())); | |
list.replace(GENRE , QString::fromStdString(tag->genre().to8Bit())); | |
std::ostringstream oss; | |
oss << tag->track(); | |
list.replace(TRACK , QString::fromStdString(oss.str().c_str())); | |
// append list (song data) into songlist m_listSongs; | |
// uninitialized fields are empty strings | |
m_listSongs << list; | |
} | |
// base case: no more subdirectories | |
if(listDirs.size() == 0) return; | |
// recursively descend through all subdirectories | |
for(int i=0; i<listDirs.size(); i++) { | |
QFileInfo fileInfo = listDirs.at(i); | |
traverseDirs( fileInfo.filePath() ); | |
} | |
return; | |
} | |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
// MainWindow::setSizes: | |
// | |
// Set splitter sizes. | |
// | |
void | |
MainWindow::setSizes(QSplitter *splitter, int size1, int size2) | |
{ | |
QList<int> sizes; | |
sizes.append(size1); | |
sizes.append(size2); | |
splitter->setSizes(sizes); | |
} | |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
// MainWindow::s_load: | |
// | |
// Slot function for File|Load | |
// | |
void | |
MainWindow::s_load() | |
{ | |
// open a file dialog box | |
QFileDialog *fd = new QFileDialog; | |
fd->setFileMode(QFileDialog::Directory); | |
QString s = fd->getExistingDirectory(0, "Select Folder", m_directory, | |
QFileDialog::ShowDirsOnly | | |
QFileDialog::DontResolveSymlinks); | |
// check if cancel was selected | |
if(s == NULL) return; | |
// copy full pathname of selected directory into m_directory | |
m_directory = s; | |
// init progress bar | |
m_progressBar = new QProgressDialog(this); | |
m_progressBar->setWindowTitle("Updating"); | |
m_progressBar->setFixedSize(300,100); | |
m_progressBar->setCancelButtonText("Cancel"); | |
traverseDirs(m_directory); | |
initLists(); | |
m_progressBar->close(); | |
} | |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
// MainWindow::s_panel1: | |
// | |
// Slot function to adjust data if an item in panel1 (genre) is selected. | |
// | |
void | |
MainWindow::s_panel1(QListWidgetItem *item) | |
{ | |
if(item->text() == "ALL") { | |
initLists(); | |
return; | |
} | |
// clear lists | |
m_panel[1] ->clear(); | |
m_panel[2] ->clear(); | |
m_listArtist.clear(); | |
m_listAlbum .clear(); | |
// collect list of artists and albums | |
for(int i=0; i<m_listSongs.size(); i++) { | |
if(m_listSongs[i][ARTIST] == item->text()) | |
m_listArtist << m_listSongs[i][ARTIST]; | |
} | |
for(int i=0; i<m_listSongs.size(); i++) { | |
if(m_listSongs[i][ARTIST] == item->text()) | |
m_listAlbum << m_listSongs[i][ALBUM]; | |
} | |
// sort remaining two panels for artists and albums | |
qStableSort(m_listArtist.begin(), m_listArtist.end(), caseInsensitive); | |
qStableSort(m_listAlbum.begin(), m_listAlbum.end(), caseInsensitive); | |
// add items to panels; skip over non-unique entries | |
for(int i=0; i<m_listArtist.size(); i+=m_listArtist.count(m_listArtist[i])) | |
m_panel[1]->addItem(m_listArtist [i]); | |
for(int i=0; i<m_listAlbum.size(); i+=m_listAlbum.count(m_listAlbum[i])) | |
m_panel[2]->addItem(m_listAlbum [i]); | |
redrawLists(item, GENRE); | |
} | |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
// MainWindow::s_panel2: | |
// | |
// Slot function to adjust data if an item in panel2 (artist) is selected. | |
// | |
void | |
MainWindow::s_panel2(QListWidgetItem *item) | |
{ | |
// clear lists | |
m_panel[2]->clear(); | |
m_listAlbum.clear(); | |
// collect list of albums | |
for(int i=0; i<m_listSongs.size(); i++) { | |
if(m_listSongs[i][ARTIST] == item->text()) | |
m_listAlbum << m_listSongs[i][ALBUM]; | |
} | |
// sort remaining panel for albums | |
qStableSort(m_listAlbum.begin(), m_listAlbum.end(), caseInsensitive); | |
// add items to panel; skip over non-unique entries | |
for(int i=0; i<m_listAlbum.size(); i+=m_listAlbum.count(m_listAlbum[i])) | |
m_panel[2]->addItem(m_listAlbum [i]); | |
redrawLists(item, ARTIST); | |
} | |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
// MainWindow::s_panel3: | |
// | |
// Slot function to adjust data if an item in panel3 (album) is selected. | |
// | |
void | |
MainWindow::s_panel3(QListWidgetItem *item) | |
{ | |
redrawLists(item, ALBUM); | |
} | |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
// MainWindow::s_about: | |
// | |
// Slot function for Help|About | |
// | |
void | |
MainWindow::s_about() | |
{ | |
QMessageBox::about(this, "About qTunes", | |
"<center> qTunes 1.0 </center> \ | |
<center> by George Wolberg, 2015 </center>"); | |
} | |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
// MainWindow::s_play: | |
// | |
// Slot function to play an mp3 song. | |
// This uses audiere. Replace with functions from Qt5 multimedia module | |
// | |
/*void | |
MainWindow::s_play(QTableWidgetItem *item) | |
{ | |
// open device and do error checking | |
AudioDevicePtr device = OpenDevice(""); | |
if (!device) return; | |
for(int i=0; i<m_listSongs.size(); i++) { | |
// skip over songs whose title does not match | |
if(m_listSongs[i][TITLE] != item->text()) continue; | |
OutputStreamPtr sound = OpenSound(device, | |
m_listSongs[i][PATH].toLatin1().data()); | |
sound->play(); | |
while (sound->isPlaying()) { | |
if(m_stop->isDown()) sound->stop(); | |
//sleepSecond(); | |
qApp->processEvents(); | |
} | |
} | |
} | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ====================================================================== | |
// IMPROC: Image Processing Software Package | |
// Copyright (C) 2015 by George Wolberg | |
// | |
// MainWindow.h - Main Window widget class | |
// | |
// Written by: George Wolberg, 2015 | |
// ====================================================================== | |
#ifndef MAINWINDOW_H | |
#define MAINWINDOW_H | |
#include <QtWidgets> | |
/////////////////////////////////////////////////////////////////////////////// | |
/// | |
/// \class MainWindow | |
/// \brief IMPROC main window. | |
/// | |
/// The IMPROC main window consists of three main areas: a tree view | |
/// in the top-left corner, an information view directly below the | |
/// tree view, and a frame array that takes up the entire right side | |
/// of the screen. | |
/// | |
/////////////////////////////////////////////////////////////////////////////// | |
class MainWindow : public QMainWindow { | |
Q_OBJECT | |
public: | |
//! Constructor. | |
MainWindow(QString); | |
//! Destructor. | |
~MainWindow(); | |
public slots: | |
// slots | |
void s_load (); | |
void s_panel1(QListWidgetItem*); | |
void s_panel2(QListWidgetItem*); | |
void s_panel3(QListWidgetItem*); | |
// void s_play (QTableWidgetItem*); | |
void s_about (); | |
private: | |
void createActions(); | |
void createMenus (); | |
void createWidgets(); | |
void createLayouts(); | |
void initLists (); | |
void redrawLists (QListWidgetItem *, int); | |
void traverseDirs (QString); | |
void setSizes (QSplitter *, int, int); | |
// actions | |
QAction *m_loadAction; | |
QAction *m_quitAction; | |
QAction *m_aboutAction; | |
QAction *m_selectAction; | |
// menus | |
QMenu *m_fileMenu; | |
QMenu *m_helpMenu; | |
// widgets | |
QSplitter *m_mainSplit; | |
QSplitter *m_leftSplit; | |
QSplitter *m_rightSplit; | |
QLabel *m_labelSide[2]; | |
QLabel *m_label[3]; | |
QListWidget *m_panel[3]; | |
QTableWidget *m_table; | |
QProgressDialog *m_progressBar; | |
QPushButton *m_stop; | |
// string lists | |
QString m_directory; | |
QStringList m_listGenre; | |
QStringList m_listArtist; | |
QStringList m_listAlbum; | |
QList<QStringList> m_listSongs; | |
}; | |
#endif // MAINWINDOW_H |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment