<commit_before>#include "data_generator.hpp"
#include "feature_generator.hpp"
#include "feature_sorter.hpp"
#include "update_generator.hpp"
#include "feature_bucketer.hpp"
#include "grid_generator.hpp"
#include "statistics.hpp"

#include "../classif_routine.hpp"
#include "../features_vector.hpp"
#include "../index_builder.hpp"
#include "../osm_decl.hpp"
#include "../data_header.hpp"

#include "../../defines.hpp"

#include "../../platform/platform.hpp"

#include "../../3party/gflags/src/gflags/gflags.h"

#include "../../std/ctime.hpp"
#include "../../std/iostream.hpp"
#include "../../std/iomanip.hpp"
#include "../../std/numeric.hpp"

#include "../../version/version.hpp"

#include "../../base/start_mem_debug.hpp"

DEFINE_bool(version, false, "Display version");
DEFINE_bool(generate_update, false,
              "If specified, update.maps file will be generated from cells in the data path");

DEFINE_bool(sort_features, true, "Sort features data for better cache-friendliness.");
DEFINE_bool(generate_classif, false, "Generate classificator.");
DEFINE_bool(preprocess_xml, false, "1st pass - create nodes/ways/relations data");
DEFINE_bool(generate_features, false, "2nd pass - generate intermediate features");
DEFINE_bool(generate_geometry, false, "3rd pass - split and simplify geometry and triangles for features");
DEFINE_bool(generate_index, false, "4rd pass - generate index");
DEFINE_bool(generate_grid, false, "Generate grid for given bucketing_level");
DEFINE_bool(calc_statistics, false, "Calculate feature statistics for specified mwm bucket files");
DEFINE_bool(use_light_nodes, false,
            "If true, use temporary vector of nodes, instead of huge temp file");
DEFINE_string(data_path, "", "Working directory, 'path_to_exe/../../data' if empty.");
DEFINE_string(output, "", "Prefix of filenames of outputted .dat and .idx files.");
DEFINE_string(intermediate_data_path, "", "Path to store nodes, ways, relations.");
DEFINE_int32(bucketing_level, -1, "If positive, level of cell ids for bucketing.");
DEFINE_int32(generate_world_scale, -1, "If specified, features for zoomlevels [0..this_value] "
             "which are enabled in classificator will be MOVED to the separate world file");
DEFINE_bool(split_by_polygons, false, "Use kml shape files to split planet by regions and countries");
DEFINE_int32(simplify_countries_level, -1, "If positive, simplifies country polygons. Recommended values [10..15]");
DEFINE_bool(merge_coastlines, false, "If defined, tries to merge coastlines when renerating World file");

string AddSlashIfNeeded(string const & str)
{
  string result(str);
  size_t const size = result.size();
  if (size)
  {
    if (result.find_last_of('\\') == size - 1)
      result[size - 1] = '/';
    else
      if (result.find_last_of('/') != size - 1)
        result.push_back('/');
  }
  return result;
}

int main(int argc, char ** argv)
{
  google::SetUsageMessage(
      "Takes OSM XML data from stdin and creates data and index files in several passes.");

  google::ParseCommandLineFlags(&argc, &argv, true);

  string const path =
      FLAGS_data_path.empty() ? GetPlatform().WritableDir() : AddSlashIfNeeded(FLAGS_data_path);

  if (FLAGS_version)
  {
    cout << "Tool version: " << VERSION_STRING << endl;
    cout << "Built on: " << VERSION_DATE_STRING << endl;
  }

  // Make a classificator
  if (FLAGS_generate_classif)
  {
    classificator::GenerateAndWrite(path);
  }

  if (FLAGS_generate_grid)
  {
    grid::GenerateGridToStdout(FLAGS_bucketing_level);
  }

  // Generating intermediate files
  if (FLAGS_preprocess_xml)
  {
    LOG(LINFO, ("Generating intermediate data ...."));
    if (!data::GenerateToFile(FLAGS_intermediate_data_path, FLAGS_use_light_nodes))
      return -1;
  }

  feature::GenerateInfo genInfo;
  genInfo.tmpDir = FLAGS_intermediate_data_path;

  // load classificator only if necessary
  if (FLAGS_generate_features || FLAGS_generate_geometry ||
      FLAGS_generate_index || FLAGS_calc_statistics)
  {
    classificator::Read(path + "drawing_rules.bin",
                        path + "classificator.txt",
                        path + "visibility.txt");
    classificator::PrepareForFeatureGeneration();
  }

  // Generate dat file
  if (FLAGS_generate_features)
  {
    LOG(LINFO, ("Generating final data ..."));

    if (FLAGS_output.empty())
      genInfo.datFilePrefix = path;
    else
      genInfo.datFilePrefix = path + FLAGS_output + (FLAGS_bucketing_level > 0 ? "-" : "");
    genInfo.datFileSuffix = DATA_FILE_EXTENSION;

    // split data by countries polygons
    genInfo.splitByPolygons = FLAGS_split_by_polygons;
    genInfo.simplifyCountriesLevel = FLAGS_simplify_countries_level;

    genInfo.cellBucketingLevel = FLAGS_bucketing_level;
    genInfo.maxScaleForWorldFeatures = FLAGS_generate_world_scale;
    genInfo.mergeCoastlines = FLAGS_merge_coastlines;

    if (!feature::GenerateFeatures(genInfo, FLAGS_use_light_nodes))
      return -1;

    for (size_t i = 0; i < genInfo.bucketNames.size(); ++i)
      genInfo.bucketNames[i] = genInfo.datFilePrefix + genInfo.bucketNames[i] + genInfo.datFileSuffix;
    if (FLAGS_generate_world_scale >= 0)
      genInfo.bucketNames.push_back(genInfo.datFilePrefix + WORLD_FILE_NAME + genInfo.datFileSuffix);
  }
  else
  {
    genInfo.bucketNames.push_back(path + FLAGS_output + DATA_FILE_EXTENSION);
  }

  // Enumerate over all dat files that were created.
  for (size_t i = 0; i < genInfo.bucketNames.size(); ++i)
  {
    string const & datFile = genInfo.bucketNames[i];

    if (FLAGS_generate_geometry)
    {
      LOG(LINFO, ("Generating result features for ", datFile));
      if (!feature::GenerateFinalFeatures(datFile, FLAGS_sort_features))
      {
        // If error - move to next bucket without index generation
        continue;
      }
    }

    if (FLAGS_generate_index)
    {
      LOG(LINFO, ("Generating index for ", datFile));
      if (!indexer::BuildIndexFromDatFile(datFile, FLAGS_intermediate_data_path + FLAGS_output))
      {
        LOG(LCRITICAL, ("Error generating index."));
      }
    }

    if (FLAGS_calc_statistics)
    {
      LOG(LINFO, ("Calculating statistics for ", datFile));

      stats::FileContainerStatistic(datFile);

      stats::MapInfo info;
      stats::CalcStatistic(datFile, info);
      stats::PrintStatistic(info);
    }
  }

  // Create http update list for countries and corresponding files
  if (FLAGS_generate_update)
  {
    LOG(LINFO, ("Creating maps.update file..."));
    update::GenerateFilesList(path);
  }

  return 0;
}
<commit_msg>[indexer_tool] Fixed incompatible split_by_polygons and output flags<commit_after>#include "data_generator.hpp"
#include "feature_generator.hpp"
#include "feature_sorter.hpp"
#include "update_generator.hpp"
#include "feature_bucketer.hpp"
#include "grid_generator.hpp"
#include "statistics.hpp"

#include "../classif_routine.hpp"
#include "../features_vector.hpp"
#include "../index_builder.hpp"
#include "../osm_decl.hpp"
#include "../data_header.hpp"

#include "../../defines.hpp"

#include "../../platform/platform.hpp"

#include "../../3party/gflags/src/gflags/gflags.h"

#include "../../std/ctime.hpp"
#include "../../std/iostream.hpp"
#include "../../std/iomanip.hpp"
#include "../../std/numeric.hpp"

#include "../../version/version.hpp"

#include "../../base/start_mem_debug.hpp"

DEFINE_bool(version, false, "Display version");
DEFINE_bool(generate_update, false,
              "If specified, update.maps file will be generated from cells in the data path");

DEFINE_bool(sort_features, true, "Sort features data for better cache-friendliness.");
DEFINE_bool(generate_classif, false, "Generate classificator.");
DEFINE_bool(preprocess_xml, false, "1st pass - create nodes/ways/relations data");
DEFINE_bool(generate_features, false, "2nd pass - generate intermediate features");
DEFINE_bool(generate_geometry, false, "3rd pass - split and simplify geometry and triangles for features");
DEFINE_bool(generate_index, false, "4rd pass - generate index");
DEFINE_bool(generate_grid, false, "Generate grid for given bucketing_level");
DEFINE_bool(calc_statistics, false, "Calculate feature statistics for specified mwm bucket files");
DEFINE_bool(use_light_nodes, false,
            "If true, use temporary vector of nodes, instead of huge temp file");
DEFINE_string(data_path, "", "Working directory, 'path_to_exe/../../data' if empty.");
DEFINE_string(output, "", "Prefix of filenames of outputted .dat and .idx files.");
DEFINE_string(intermediate_data_path, "", "Path to store nodes, ways, relations.");
DEFINE_int32(bucketing_level, -1, "If positive, level of cell ids for bucketing.");
DEFINE_int32(generate_world_scale, -1, "If specified, features for zoomlevels [0..this_value] "
             "which are enabled in classificator will be MOVED to the separate world file");
DEFINE_bool(split_by_polygons, false, "Use kml shape files to split planet by regions and countries");
DEFINE_int32(simplify_countries_level, -1, "If positive, simplifies country polygons. Recommended values [10..15]");
DEFINE_bool(merge_coastlines, false, "If defined, tries to merge coastlines when renerating World file");

string AddSlashIfNeeded(string const & str)
{
  string result(str);
  size_t const size = result.size();
  if (size)
  {
    if (result.find_last_of('\\') == size - 1)
      result[size - 1] = '/';
    else
      if (result.find_last_of('/') != size - 1)
        result.push_back('/');
  }
  return result;
}

int main(int argc, char ** argv)
{
  google::SetUsageMessage(
      "Takes OSM XML data from stdin and creates data and index files in several passes.");

  google::ParseCommandLineFlags(&argc, &argv, true);

  string const path =
      FLAGS_data_path.empty() ? GetPlatform().WritableDir() : AddSlashIfNeeded(FLAGS_data_path);

  if (FLAGS_version)
  {
    cout << "Tool version: " << VERSION_STRING << endl;
    cout << "Built on: " << VERSION_DATE_STRING << endl;
  }

  // Make a classificator
  if (FLAGS_generate_classif)
  {
    classificator::GenerateAndWrite(path);
  }

  if (FLAGS_generate_grid)
  {
    grid::GenerateGridToStdout(FLAGS_bucketing_level);
  }

  // Generating intermediate files
  if (FLAGS_preprocess_xml)
  {
    LOG(LINFO, ("Generating intermediate data ...."));
    if (!data::GenerateToFile(FLAGS_intermediate_data_path, FLAGS_use_light_nodes))
      return -1;
  }

  feature::GenerateInfo genInfo;
  genInfo.tmpDir = FLAGS_intermediate_data_path;

  // load classificator only if necessary
  if (FLAGS_generate_features || FLAGS_generate_geometry ||
      FLAGS_generate_index || FLAGS_calc_statistics)
  {
    classificator::Read(path + "drawing_rules.bin",
                        path + "classificator.txt",
                        path + "visibility.txt");
    classificator::PrepareForFeatureGeneration();
  }

  // Generate dat file
  if (FLAGS_generate_features)
  {
    LOG(LINFO, ("Generating final data ..."));

    if (FLAGS_output.empty() || FLAGS_split_by_polygons)  // do not break data path for polygons
      genInfo.datFilePrefix = path;
    else
      genInfo.datFilePrefix = path + FLAGS_output + (FLAGS_bucketing_level > 0 ? "-" : "");
    genInfo.datFileSuffix = DATA_FILE_EXTENSION;

    // split data by countries polygons
    genInfo.splitByPolygons = FLAGS_split_by_polygons;
    genInfo.simplifyCountriesLevel = FLAGS_simplify_countries_level;

    genInfo.cellBucketingLevel = FLAGS_bucketing_level;
    genInfo.maxScaleForWorldFeatures = FLAGS_generate_world_scale;
    genInfo.mergeCoastlines = FLAGS_merge_coastlines;

    if (!feature::GenerateFeatures(genInfo, FLAGS_use_light_nodes))
      return -1;

    for (size_t i = 0; i < genInfo.bucketNames.size(); ++i)
      genInfo.bucketNames[i] = genInfo.datFilePrefix + genInfo.bucketNames[i] + genInfo.datFileSuffix;
    if (FLAGS_generate_world_scale >= 0)
      genInfo.bucketNames.push_back(genInfo.datFilePrefix + WORLD_FILE_NAME + genInfo.datFileSuffix);
  }
  else
  {
    genInfo.bucketNames.push_back(path + FLAGS_output + DATA_FILE_EXTENSION);
  }

  // Enumerate over all dat files that were created.
  for (size_t i = 0; i < genInfo.bucketNames.size(); ++i)
  {
    string const & datFile = genInfo.bucketNames[i];

    if (FLAGS_generate_geometry)
    {
      LOG(LINFO, ("Generating result features for ", datFile));
      if (!feature::GenerateFinalFeatures(datFile, FLAGS_sort_features))
      {
        // If error - move to next bucket without index generation
        continue;
      }
    }

    if (FLAGS_generate_index)
    {
      LOG(LINFO, ("Generating index for ", datFile));
      if (!indexer::BuildIndexFromDatFile(datFile, FLAGS_intermediate_data_path + FLAGS_output))
      {
        LOG(LCRITICAL, ("Error generating index."));
      }
    }

    if (FLAGS_calc_statistics)
    {
      LOG(LINFO, ("Calculating statistics for ", datFile));

      stats::FileContainerStatistic(datFile);

      stats::MapInfo info;
      stats::CalcStatistic(datFile, info);
      stats::PrintStatistic(info);
    }
  }

  // Create http update list for countries and corresponding files
  if (FLAGS_generate_update)
  {
    LOG(LINFO, ("Creating maps.update file..."));
    update::GenerateFilesList(path);
  }

  return 0;
}
<|endoftext|>


<commit_before>#include "mainwindow.h"
#include "ui_mainwindow.h"

#define TIME_TRAY_BALLOON 5000
#define PROJECT "Tsunami++"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    p_session_thread = new QThread();
    sessionManager = new tsuManager();
    sessionManager->moveToThread(p_session_thread);

    settingsPage = new settingswindow(this);
    searchPage = new searchwindow(this);
    statusLabel = new QLabel(this);
    statisticsPage = new statisticswindow(this);
    downloadPage = new downloadwindow(this);

    initializeScreen();
    readSettings();
    loadLanguage(language);

    statusBar()->addPermanentWidget(statusLabel, 0);
    statusBar()->showMessage("Welcome!");

    // add from SessionManager goes to downloadPage to add tsuCard
    connect(sessionManager, SIGNAL(addFromSessionManager(const tsuEvents::tsuEvent &)), downloadPage, SLOT(addFromSession(const tsuEvents::tsuEvent &)));//, Qt::QueuedConnection);

    // update from sessionManager goes to downloadPage to manage tsuCard values
    connect(sessionManager, SIGNAL(updateFromSessionManager(const QVector<tsuEvents::tsuEvent> &)), downloadPage, SLOT(updateFromSession(const QVector<tsuEvents::tsuEvent> &)));//, Qt::DirectConnection);

    // deleted torrent from sessionManager goes to downloadPage to remove it from list
    connect(sessionManager, SIGNAL(torrentDeleted(std::string)), downloadPage, SLOT(torrentDeletedFromSession(std::string)));//, Qt::QueuedConnection);

    // requested cancel from downloadPage (emitted from a tsucard) goes to sessionManager to remove torrent from libtorrent
    connect(downloadPage, SIGNAL(sendRequestedCancelToSession(std::string,bool)), sessionManager, SLOT(getCancelRequest(std::string,bool)));//, Qt::QueuedConnection);

    // requested pause from downloadPage (emitted from a tsucard) goes to sessionManager to pause torrent
    connect(downloadPage, SIGNAL(sendRequestedPauseToSession(std::string)), sessionManager, SLOT(getPauseRequest(std::string)));//, Qt::QueuedConnection);

    // requested resume from downloadPage (emitted from a tsucard) goes to sessionManager to resume torrent
    connect(downloadPage, SIGNAL(sendRequestedResumeToSession(std::string)), sessionManager, SLOT(getResumeRequest(std::string)));//, Qt::QueuedConnection);

    // update from downloadPage to statusbar text
    connect(downloadPage, SIGNAL(sendUpdateToStatusBar(const QString &)), this, SLOT(updateStatusBar(const QString &)));//, Qt::QueuedConnection);

    // update from downloadPage to statistics page
    connect(downloadPage, SIGNAL(sendStatisticsUpdate(const QPair<int,int> &)), statisticsPage, SLOT(updateStats(const QPair<int,int> &)));//, Qt::QueuedConnection);

    // popup message from downloadPage
    connect(downloadPage, SIGNAL(sendPopupInfo(QString)), this, SLOT(popupInfo(QString)));//, Qt::QueuedConnection);

    // update from downloadPage to gauge
    connect(downloadPage, SIGNAL(sendUpdateGauge(double)), this, SLOT(updateGauge(double)));//, Qt::QueuedConnection);

    connect(p_session_thread, SIGNAL(started()), sessionManager, SLOT(startManager()));
    connect(this, SIGNAL(stopSessionManager()), sessionManager, SLOT(stopManager()), Qt::BlockingQueuedConnection);
    connect(sessionManager, SIGNAL(finished()), p_session_thread, SLOT(quit()));
    connect(sessionManager, SIGNAL(finished()), sessionManager, SLOT(deleteLater()));
//    connect(p_session_thread, SIGNAL(finished()), p_session_thread, SLOT(deleteLater()));

    p_session_thread->start();
}

MainWindow::~MainWindow()
{
    qDebug("starting destroy");
//    p_session_thread->wait();
//    qDebug("session thread waited");
    p_session_thread->deleteLater();
    qDebug("session thread executed deleteLater");
    delete ui;
    qDebug("ui deleted");
}

void MainWindow::updateStatusBar(const QString &msg)
{
    statusLabel->setText(msg);
}

void MainWindow::updateGauge(const double &value)
{
    p_scaleGauge->setValue(value);
}

void MainWindow::initializeScreen() {
    setWindowIcon(QIcon(":/images/logo_tsunami_tiny.ico"));
    setWindowTitle(PROJECT " " VERSION);
//    setWindowFlags(Qt::FramelessWindowHint);
    createTrayIcon();

    QFontDatabase::addApplicationFont(":/font/BEBAS___.TTF");

    connect(ui->btnSettings, SIGNAL(released()), this, SLOT(btnMenuClick()));
    connect(ui->btnUser, SIGNAL(released()), this, SLOT(btnMenuClick()));
    connect(ui->btnSearch, SIGNAL(released()), this, SLOT(btnMenuClick()));
    connect(ui->btnDownload, SIGNAL(released()), this, SLOT(btnMenuClick()));
    connect(ui->btnArchive, SIGNAL(released()), this, SLOT(btnMenuClick()));
    connect(ui->btnStreaming, SIGNAL(released()), this, SLOT(btnMenuClick()));
    connect(ui->btnStatistics, SIGNAL(released()), this, SLOT(btnMenuClick()));
    connect(ui->btnChat, SIGNAL(released()), this, SLOT(btnMenuClick()));

    connect(ui->btnAdd, SIGNAL(released()), this, SLOT(btnAddClick()));

    ui->btnSettings->show();
    ui->btnUser->show();
    ui->btnSearch->show();
    ui->btnDownload->show();
    ui->btnArchive->show();
    ui->btnStreaming->show();
    ui->btnStatistics->show();

    ui->btnSettings_on->hide();
    ui->btnUser_on->hide();
    ui->btnSearch_on->hide();
    ui->btnDownload_on->hide();
    ui->btnArchive_on->hide();
    ui->btnStreaming_on->hide();
    ui->btnStatistics_on->hide();

    settingsPage->hide();
    searchPage->hide();
    downloadPage->hide();
    statisticsPage->hide();

    ui->content->addWidget(settingsPage);
    ui->content->addWidget(searchPage);
    ui->content->addWidget(statisticsPage);
    ui->content->addWidget(downloadPage);

    p_scaleGauge = new QScale(this);
    p_scaleGauge->setInvertedAppearance(true);
    ui->contentGauge->addWidget(p_scaleGauge);

}

void MainWindow::readSettings()
{
    QSettings settings(settingsPage->settingsFileName, QSettings::IniFormat);

    settings.beginGroup("MainWindow");
    resize(settings.value("size", QSize(840, 670)).toSize());
    move(settings.value("pos", QPoint(200, 200)).toPoint());
    if ( settings.value("fullScreen", false).toBool() ) setWindowState(Qt::WindowFullScreen);
    settings.endGroup();
    language = settings.value("Language").toString();
}

void MainWindow::writeSettings()
{
    QSettings settings(settingsPage->settingsFileName, QSettings::IniFormat);
    settings.beginGroup("MainWindow");
    settings.setValue("size", size());
    settings.setValue("pos", pos());
    settings.setValue("fullScreen", isFullScreen());
    settings.endGroup();
}

void MainWindow::updateTsunami()
{
    QProcess process;
    QString dir = QCoreApplication::applicationDirPath() + "/../";
    //qDebug() << dir + "Update.exe";
    process.start(dir+"/"+"Update.exe --checkForUpdate=tsunami.adunanza.net/releases/Releases/");

    process.waitForFinished();
    if(process.error() != QProcess::UnknownError)
    {
        qDebug() << "Error checking for updates";
        return;
    }

    QProcess::startDetached(dir+"Update.exe --update=tsunami.adunanza.net/releases/Releases/");

}

void MainWindow::loadLanguage(QString l)
{
    if(l == "Italian")
    {
        bool load = t.load(":/languages/italian.qm");
        qDebug() << "Load: " << load;
    }
    if(l != "English")
    {
        bool response = QCoreApplication::installTranslator(&t);
        qDebug() << "Response: " << response;
    }
}

void MainWindow::createTrayIcon()
{
    // Tray icon
    m_systrayIcon = new QSystemTrayIcon(QIcon(":/images/logo_tsunami_tiny.ico"), this);

    //m_systrayIcon->setContextMenu(trayIconMenu());
    connect(m_systrayIcon, SIGNAL(messageClicked()), this, SLOT(balloonClicked()));
    // End of Icon Menu
    connect(m_systrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(toggleVisibility(QSystemTrayIcon::ActivationReason)));
    m_systrayIcon->setToolTip(PROJECT " " VERSION);
    m_systrayIcon->show();
//    m_systrayIcon->showMessage(PROJECT, "Welcome to the future!", QSystemTrayIcon::Information, TIME_TRAY_BALLOON);
    popupInfo("Welcome to the future!");
    qDebug("started");
}

void MainWindow::toggleVisibility(QSystemTrayIcon::ActivationReason e)
{
    qDebug("entered toggleVisibility");
    if ((e == QSystemTrayIcon::Trigger) || (e == QSystemTrayIcon::DoubleClick)) {
        if (isHidden()) {
            /*if (m_uiLocked) {
                // Ask for UI lock password
                if (!unlockUI())
                    return;
            }*/
            // Make sure the window is not minimized
            setWindowState(windowState() & (~Qt::WindowMinimized | Qt::WindowActive));
            // Then show it
            show();
            raise();
            activateWindow();
        }
        else {
            hide();
        }
    }
}

void MainWindow::balloonClicked()
{
    if (isHidden()) {
        /*if (m_uiLocked) {
            // Ask for UI lock password
            if (!unlockUI())
                return;
        }*/
        show();
        if (isMinimized())
            showNormal();
    }

    raise();
    activateWindow();
}

void MainWindow::btnMenuClick() {
    QString btn = sender()->objectName();

    ui->btnSettings->setHidden(btn == ui->btnSettings->objectName());
    ui->btnUser->setHidden(btn == ui->btnUser->objectName());
    ui->btnSearch->setHidden(btn == ui->btnSearch->objectName());
    ui->btnDownload->setHidden(btn == ui->btnDownload->objectName());
    ui->btnArchive->setHidden(btn == ui->btnArchive->objectName());
    ui->btnStreaming->setHidden(btn == ui->btnStreaming->objectName());
    ui->btnStatistics->setHidden(btn == ui->btnStatistics->objectName());

    ui->btnSettings_on->setHidden(btn != ui->btnSettings->objectName());
    ui->btnUser_on->setHidden(btn != ui->btnUser->objectName());
    ui->btnSearch_on->setHidden(btn != ui->btnSearch->objectName());
    ui->btnDownload_on->setHidden(btn != ui->btnDownload->objectName());
    ui->btnArchive_on->setHidden(btn != ui->btnArchive->objectName());
    ui->btnStreaming_on->setHidden(btn != ui->btnStreaming->objectName());
    ui->btnStatistics_on->setHidden(btn != ui->btnStatistics->objectName());

    settingsPage->setHidden(btn != ui->btnSettings->objectName());
    searchPage->setHidden(btn != ui->btnSearch->objectName());
    statisticsPage->setHidden(btn != ui->btnStatistics->objectName());
    downloadPage->setHidden(btn != ui->btnDownload->objectName());

    if (btn == ui->btnChat->objectName()) {
        QString link = "https://discordapp.com/invite/0pfzTOXuEjt9ifvF";
        QDesktopServices::openUrl(QUrl(link));
    }
}

void MainWindow::btnAddClick()
{
    QFileDialog fd(this, tr("Select torrent"), settingsPage->getLastBrowsedDir(), tr("Torrents (*.torrent)"));
    QStringList fileNames = fd.getOpenFileNames();
    if (fileNames.isEmpty()) return;
    settingsPage->setLastBrowsedDir(QFileInfo(fileNames.first()).absolutePath());
    sessionManager->addItems(std::move(fileNames), settingsPage->getDownloadPath());
    ui->btnDownload->released(); // switch to downloadpage
}

void MainWindow::popupInfo(const QString &msg)
{
    m_systrayIcon->showMessage(PROJECT, msg, QSystemTrayIcon::Information, TIME_TRAY_BALLOON);
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    qDebug("closing");
    statusLabel->setText("Saving resume data. Please wait.");
    writeSettings();
    updateTsunami();
    emit stopSessionManager();
    event->accept();
}

void MainWindow::changeEvent(QEvent *e)
{
    if(e->type() == QEvent::LanguageChange)
    {
        qDebug() << "Intercepted LanguageChange event by MainWindow";
        ui->retranslateUi(this);
    }

    QMainWindow::changeEvent(e);
}
<commit_msg>AutoUpdate FixBug<commit_after>#include "mainwindow.h"
#include "ui_mainwindow.h"

#define TIME_TRAY_BALLOON 5000
#define PROJECT "Tsunami++"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    p_session_thread = new QThread();
    sessionManager = new tsuManager();
    sessionManager->moveToThread(p_session_thread);

    settingsPage = new settingswindow(this);
    searchPage = new searchwindow(this);
    statusLabel = new QLabel(this);
    statisticsPage = new statisticswindow(this);
    downloadPage = new downloadwindow(this);

    initializeScreen();
    readSettings();
    loadLanguage(language);

    statusBar()->addPermanentWidget(statusLabel, 0);
    statusBar()->showMessage("Welcome!");

    // add from SessionManager goes to downloadPage to add tsuCard
    connect(sessionManager, SIGNAL(addFromSessionManager(const tsuEvents::tsuEvent &)), downloadPage, SLOT(addFromSession(const tsuEvents::tsuEvent &)));//, Qt::QueuedConnection);

    // update from sessionManager goes to downloadPage to manage tsuCard values
    connect(sessionManager, SIGNAL(updateFromSessionManager(const QVector<tsuEvents::tsuEvent> &)), downloadPage, SLOT(updateFromSession(const QVector<tsuEvents::tsuEvent> &)));//, Qt::DirectConnection);

    // deleted torrent from sessionManager goes to downloadPage to remove it from list
    connect(sessionManager, SIGNAL(torrentDeleted(std::string)), downloadPage, SLOT(torrentDeletedFromSession(std::string)));//, Qt::QueuedConnection);

    // requested cancel from downloadPage (emitted from a tsucard) goes to sessionManager to remove torrent from libtorrent
    connect(downloadPage, SIGNAL(sendRequestedCancelToSession(std::string,bool)), sessionManager, SLOT(getCancelRequest(std::string,bool)));//, Qt::QueuedConnection);

    // requested pause from downloadPage (emitted from a tsucard) goes to sessionManager to pause torrent
    connect(downloadPage, SIGNAL(sendRequestedPauseToSession(std::string)), sessionManager, SLOT(getPauseRequest(std::string)));//, Qt::QueuedConnection);

    // requested resume from downloadPage (emitted from a tsucard) goes to sessionManager to resume torrent
    connect(downloadPage, SIGNAL(sendRequestedResumeToSession(std::string)), sessionManager, SLOT(getResumeRequest(std::string)));//, Qt::QueuedConnection);

    // update from downloadPage to statusbar text
    connect(downloadPage, SIGNAL(sendUpdateToStatusBar(const QString &)), this, SLOT(updateStatusBar(const QString &)));//, Qt::QueuedConnection);

    // update from downloadPage to statistics page
    connect(downloadPage, SIGNAL(sendStatisticsUpdate(const QPair<int,int> &)), statisticsPage, SLOT(updateStats(const QPair<int,int> &)));//, Qt::QueuedConnection);

    // popup message from downloadPage
    connect(downloadPage, SIGNAL(sendPopupInfo(QString)), this, SLOT(popupInfo(QString)));//, Qt::QueuedConnection);

    // update from downloadPage to gauge
    connect(downloadPage, SIGNAL(sendUpdateGauge(double)), this, SLOT(updateGauge(double)));//, Qt::QueuedConnection);

    connect(p_session_thread, SIGNAL(started()), sessionManager, SLOT(startManager()));
    connect(this, SIGNAL(stopSessionManager()), sessionManager, SLOT(stopManager()), Qt::BlockingQueuedConnection);
    connect(sessionManager, SIGNAL(finished()), p_session_thread, SLOT(quit()));
    connect(sessionManager, SIGNAL(finished()), sessionManager, SLOT(deleteLater()));
//    connect(p_session_thread, SIGNAL(finished()), p_session_thread, SLOT(deleteLater()));

    p_session_thread->start();
}

MainWindow::~MainWindow()
{
    qDebug("starting destroy");
//    p_session_thread->wait();
//    qDebug("session thread waited");
    p_session_thread->deleteLater();
    qDebug("session thread executed deleteLater");
    delete ui;
    qDebug("ui deleted");
}

void MainWindow::updateStatusBar(const QString &msg)
{
    statusLabel->setText(msg);
}

void MainWindow::updateGauge(const double &value)
{
    p_scaleGauge->setValue(value);
}

void MainWindow::initializeScreen() {
    setWindowIcon(QIcon(":/images/logo_tsunami_tiny.ico"));
    setWindowTitle(PROJECT " " VERSION);
//    setWindowFlags(Qt::FramelessWindowHint);
    createTrayIcon();

    QFontDatabase::addApplicationFont(":/font/BEBAS___.TTF");

    connect(ui->btnSettings, SIGNAL(released()), this, SLOT(btnMenuClick()));
    connect(ui->btnUser, SIGNAL(released()), this, SLOT(btnMenuClick()));
    connect(ui->btnSearch, SIGNAL(released()), this, SLOT(btnMenuClick()));
    connect(ui->btnDownload, SIGNAL(released()), this, SLOT(btnMenuClick()));
    connect(ui->btnArchive, SIGNAL(released()), this, SLOT(btnMenuClick()));
    connect(ui->btnStreaming, SIGNAL(released()), this, SLOT(btnMenuClick()));
    connect(ui->btnStatistics, SIGNAL(released()), this, SLOT(btnMenuClick()));
    connect(ui->btnChat, SIGNAL(released()), this, SLOT(btnMenuClick()));

    connect(ui->btnAdd, SIGNAL(released()), this, SLOT(btnAddClick()));

    ui->btnSettings->show();
    ui->btnUser->show();
    ui->btnSearch->show();
    ui->btnDownload->show();
    ui->btnArchive->show();
    ui->btnStreaming->show();
    ui->btnStatistics->show();

    ui->btnSettings_on->hide();
    ui->btnUser_on->hide();
    ui->btnSearch_on->hide();
    ui->btnDownload_on->hide();
    ui->btnArchive_on->hide();
    ui->btnStreaming_on->hide();
    ui->btnStatistics_on->hide();

    settingsPage->hide();
    searchPage->hide();
    downloadPage->hide();
    statisticsPage->hide();

    ui->content->addWidget(settingsPage);
    ui->content->addWidget(searchPage);
    ui->content->addWidget(statisticsPage);
    ui->content->addWidget(downloadPage);

    p_scaleGauge = new QScale(this);
    p_scaleGauge->setInvertedAppearance(true);
    ui->contentGauge->addWidget(p_scaleGauge);

}

void MainWindow::readSettings()
{
    QSettings settings(settingsPage->settingsFileName, QSettings::IniFormat);

    settings.beginGroup("MainWindow");
    resize(settings.value("size", QSize(840, 670)).toSize());
    move(settings.value("pos", QPoint(200, 200)).toPoint());
    if ( settings.value("fullScreen", false).toBool() ) setWindowState(Qt::WindowFullScreen);
    settings.endGroup();
    language = settings.value("Language").toString();
}

void MainWindow::writeSettings()
{
    QSettings settings(settingsPage->settingsFileName, QSettings::IniFormat);
    settings.beginGroup("MainWindow");
    settings.setValue("size", size());
    settings.setValue("pos", pos());
    settings.setValue("fullScreen", isFullScreen());
    settings.endGroup();
}

void MainWindow::updateTsunami()
{
    QProcess process;
    QString dir = QCoreApplication::applicationDirPath() + "/../";
    process.start(dir+"/"+"Update.exe --checkForUpdate=https://tsunami.adunanza.net/releases/Releases/");

    process.waitForFinished();
    if(process.error() != QProcess::UnknownError)
    {
        qDebug() << "Error checking for updates";
        return;
    }

    QProcess::startDetached(dir+"Update.exe --update=https://tsunami.adunanza.net/releases/Releases/");

}

void MainWindow::loadLanguage(QString l)
{
    if(l == "Italian")
    {
        bool load = t.load(":/languages/italian.qm");
        qDebug() << "Load: " << load;
    }
    if(l != "English")
    {
        bool response = QCoreApplication::installTranslator(&t);
        qDebug() << "Response: " << response;
    }
}

void MainWindow::createTrayIcon()
{
    // Tray icon
    m_systrayIcon = new QSystemTrayIcon(QIcon(":/images/logo_tsunami_tiny.ico"), this);

    //m_systrayIcon->setContextMenu(trayIconMenu());
    connect(m_systrayIcon, SIGNAL(messageClicked()), this, SLOT(balloonClicked()));
    // End of Icon Menu
    connect(m_systrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(toggleVisibility(QSystemTrayIcon::ActivationReason)));
    m_systrayIcon->setToolTip(PROJECT " " VERSION);
    m_systrayIcon->show();
//    m_systrayIcon->showMessage(PROJECT, "Welcome to the future!", QSystemTrayIcon::Information, TIME_TRAY_BALLOON);
    popupInfo("Welcome to the future!");
    qDebug("started");
}

void MainWindow::toggleVisibility(QSystemTrayIcon::ActivationReason e)
{
    qDebug("entered toggleVisibility");
    if ((e == QSystemTrayIcon::Trigger) || (e == QSystemTrayIcon::DoubleClick)) {
        if (isHidden()) {
            /*if (m_uiLocked) {
                // Ask for UI lock password
                if (!unlockUI())
                    return;
            }*/
            // Make sure the window is not minimized
            setWindowState(windowState() & (~Qt::WindowMinimized | Qt::WindowActive));
            // Then show it
            show();
            raise();
            activateWindow();
        }
        else {
            hide();
        }
    }
}

void MainWindow::balloonClicked()
{
    if (isHidden()) {
        /*if (m_uiLocked) {
            // Ask for UI lock password
            if (!unlockUI())
                return;
        }*/
        show();
        if (isMinimized())
            showNormal();
    }

    raise();
    activateWindow();
}

void MainWindow::btnMenuClick() {
    QString btn = sender()->objectName();

    ui->btnSettings->setHidden(btn == ui->btnSettings->objectName());
    ui->btnUser->setHidden(btn == ui->btnUser->objectName());
    ui->btnSearch->setHidden(btn == ui->btnSearch->objectName());
    ui->btnDownload->setHidden(btn == ui->btnDownload->objectName());
    ui->btnArchive->setHidden(btn == ui->btnArchive->objectName());
    ui->btnStreaming->setHidden(btn == ui->btnStreaming->objectName());
    ui->btnStatistics->setHidden(btn == ui->btnStatistics->objectName());

    ui->btnSettings_on->setHidden(btn != ui->btnSettings->objectName());
    ui->btnUser_on->setHidden(btn != ui->btnUser->objectName());
    ui->btnSearch_on->setHidden(btn != ui->btnSearch->objectName());
    ui->btnDownload_on->setHidden(btn != ui->btnDownload->objectName());
    ui->btnArchive_on->setHidden(btn != ui->btnArchive->objectName());
    ui->btnStreaming_on->setHidden(btn != ui->btnStreaming->objectName());
    ui->btnStatistics_on->setHidden(btn != ui->btnStatistics->objectName());

    settingsPage->setHidden(btn != ui->btnSettings->objectName());
    searchPage->setHidden(btn != ui->btnSearch->objectName());
    statisticsPage->setHidden(btn != ui->btnStatistics->objectName());
    downloadPage->setHidden(btn != ui->btnDownload->objectName());

    if (btn == ui->btnChat->objectName()) {
        QString link = "https://discordapp.com/invite/0pfzTOXuEjt9ifvF";
        QDesktopServices::openUrl(QUrl(link));
    }
}

void MainWindow::btnAddClick()
{
    QFileDialog fd(this, tr("Select torrent"), settingsPage->getLastBrowsedDir(), tr("Torrents (*.torrent)"));
    QStringList fileNames = fd.getOpenFileNames();
    if (fileNames.isEmpty()) return;
    settingsPage->setLastBrowsedDir(QFileInfo(fileNames.first()).absolutePath());
    sessionManager->addItems(std::move(fileNames), settingsPage->getDownloadPath());
    ui->btnDownload->released(); // switch to downloadpage
}

void MainWindow::popupInfo(const QString &msg)
{
    m_systrayIcon->showMessage(PROJECT, msg, QSystemTrayIcon::Information, TIME_TRAY_BALLOON);
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    qDebug("closing");
    statusLabel->setText("Saving resume data. Please wait.");
    writeSettings();
    updateTsunami();
    emit stopSessionManager();
    event->accept();
}

void MainWindow::changeEvent(QEvent *e)
{
    if(e->type() == QEvent::LanguageChange)
    {
        qDebug() << "Intercepted LanguageChange event by MainWindow";
        ui->retranslateUi(this);
    }

    QMainWindow::changeEvent(e);
}
<|endoftext|>


<commit_before>/**
 * @file LLNearbyChatHandler.cpp
 * @brief Nearby chat notification managment
 *
 * $LicenseInfo:firstyear=2009&license=viewergpl$
 *
 * Copyright (c) 2009, Linden Research, Inc.
 *
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 *
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at
 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 *
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 *
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "llnearbychathandler.h"

#include "llbottomtray.h"
#include "llchatitemscontainerctrl.h"
#include "llnearbychat.h"
#include "llrecentpeople.h"

#include "llviewercontrol.h"

#include "llfloaterreg.h"//for LLFloaterReg::getTypedInstance
#include "llviewerwindow.h"//for screen channel position

//add LLNearbyChatHandler to LLNotificationsUI namespace
using namespace LLNotificationsUI;

//-----------------------------------------------------------------------------------------------
//LLNearbyChatScreenChannel
//-----------------------------------------------------------------------------------------------
LLToastPanelBase* createToastPanel()
{
	LLNearbyChatToastPanel* item = LLNearbyChatToastPanel::createInstance();
	return item;
}

class LLNearbyChatScreenChannel: public LLScreenChannelBase
{
public:
	LLNearbyChatScreenChannel(const LLUUID& id):LLScreenChannelBase(id) { mStopProcessing = false;};

	void addNotification	(LLSD& notification);
	void arrangeToasts		();
	void showToastsBottom	();

	typedef boost::function<LLToastPanelBase* (void )> create_toast_panel_callback_t;
	void setCreatePanelCallback(create_toast_panel_callback_t value) { m_create_toast_panel_callback_t = value;}

	void onToastDestroyed	(LLToast* toast);
	void onToastFade		(LLToast* toast);

	void reshape			(S32 width, S32 height, BOOL called_from_parent);

	void redrawToasts()
	{
		arrangeToasts();
	}

	// hide all toasts from screen, but not remove them from a channel
	virtual void		hideToastsFromScreen()
	{
	};
	// removes all toasts from a channel
	virtual void		removeToastsFromChannel()
	{
		for(std::vector<LLToast*>::iterator it = m_active_toasts.begin(); it != m_active_toasts.end(); ++it)
		{
			addToToastPool((*it));
		}
		m_active_toasts.clear();
	};

	virtual void deleteAllChildren()
	{
		m_toast_pool.clear();
		m_active_toasts.clear();
		LLScreenChannelBase::deleteAllChildren();
	}

protected:
	void	addToToastPool(LLToast* toast)
	{
		toast->setVisible(FALSE);
		toast->stopTimer();
		toast->setIsHidden(true);
		m_toast_pool.push_back(toast);
	}

	void	createOverflowToast(S32 bottom, F32 timer);

	create_toast_panel_callback_t m_create_toast_panel_callback_t;

	bool	createPoolToast();

	std::vector<LLToast*> m_active_toasts;
	std::list<LLToast*> m_toast_pool;

	bool	mStopProcessing;
};

void	LLNearbyChatScreenChannel::createOverflowToast(S32 bottom, F32 timer)
{
	//we don't need overflow toast in nearby chat
}

void LLNearbyChatScreenChannel::onToastDestroyed(LLToast* toast)
{
	mStopProcessing = true;
}

void LLNearbyChatScreenChannel::onToastFade(LLToast* toast)
{
	//fade mean we put toast to toast pool
	if(!toast)
		return;

	std::vector<LLToast*>::iterator pos = std::find(m_active_toasts.begin(),m_active_toasts.end(),toast);
	if(pos!=m_active_toasts.end())
		m_active_toasts.erase(pos);

	addToToastPool(toast);

	arrangeToasts();
}

bool	LLNearbyChatScreenChannel::createPoolToast()
{
	LLToastPanelBase* panel= m_create_toast_panel_callback_t();
	if(!panel)
		return false;

	LLToast::Params p;
	p.panel = panel;
	p.lifetime_secs = gSavedSettings.getS32("NearbyToastLifeTime");
	p.fading_time_secs = gSavedSettings.getS32("NearbyToastFadingTime");

	LLToast* toast = new LLToast(p);

	toast->setOnFadeCallback(boost::bind(&LLNearbyChatScreenChannel::onToastFade, this, _1));
	toast->setOnToastDestroyedCallback(boost::bind(&LLNearbyChatScreenChannel::onToastDestroyed, this, _1));

	m_toast_pool.push_back(toast);
	return true;
}

void LLNearbyChatScreenChannel::addNotification(LLSD& notification)
{
	//look in pool. if there is any message
	if(mStopProcessing)
		return;

	/*
    find last toast and check ID
	*/

	if(m_active_toasts.size())
	{
		LLUUID fromID = notification["from_id"].asUUID();		// agent id or object id
		std::string from = notification["from"].asString();
		LLToast* toast = m_active_toasts[0];
		LLNearbyChatToastPanel* panel = dynamic_cast<LLNearbyChatToastPanel*>(toast->getPanel());

		if(panel && panel->messageID() == fromID && panel->getFromName() == from && panel->canAddText())
		{
			panel->addMessage(notification);
			toast->reshapeToPanel();
			toast->resetTimer();

			arrangeToasts();
			return;
		}
	}

	if(m_toast_pool.empty())
	{
		//"pool" is empty - create one more panel
		if(!createPoolToast())//created toast will go to pool. so next call will find it
			return;
		addNotification(notification);
		return;
	}

	int chat_type = notification["chat_type"].asInteger();

	if( ((EChatType)chat_type == CHAT_TYPE_DEBUG_MSG))
	{
		if(gSavedSettings.getBOOL("ShowScriptErrors") == FALSE)
			return;
		if(gSavedSettings.getS32("ShowScriptErrorsLocation")== 1)
			return;
	}

	//take 1st element from pool, (re)initialize it, put it in active toasts

	LLToast* toast = m_toast_pool.back();

	m_toast_pool.pop_back();

	LLToastPanelBase* panel = dynamic_cast<LLToastPanelBase*>(toast->getPanel());
	if(!panel)
		return;
	panel->init(notification);

	toast->reshapeToPanel();
	toast->resetTimer();

	m_active_toasts.push_back(toast);

	arrangeToasts();
}

void LLNearbyChatScreenChannel::arrangeToasts()
{
	if(m_active_toasts.size() == 0 || isHovering())
		return;

	hideToastsFromScreen();

	showToastsBottom();
}

int sort_toasts_predicate(LLToast* first,LLToast* second)
{
	F32 v1 = first->getTimer()->getEventTimer().getElapsedTimeF32();
	F32 v2 = second->getTimer()->getEventTimer().getElapsedTimeF32();
	return v1 < v2;
}

void LLNearbyChatScreenChannel::showToastsBottom()
{
	if(mStopProcessing)
		return;

	LLRect	toast_rect;
	S32		bottom = getRect().mBottom;
	S32		margin = gSavedSettings.getS32("ToastGap");

	//sort active toasts
	std::sort(m_active_toasts.begin(),m_active_toasts.end(),sort_toasts_predicate);

	//calc max visible item and hide other toasts.

	for(std::vector<LLToast*>::iterator it = m_active_toasts.begin(); it != m_active_toasts.end(); ++it)
	{
		S32 toast_top = bottom + (*it)->getRect().getHeight() + margin;

		if(toast_top > gFloaterView->getRect().getHeight())
		{
			while(it!=m_active_toasts.end())
			{
				addToToastPool((*it));
				it=m_active_toasts.erase(it);
			}
			break;
		}
		LLToast* toast = (*it);

		toast_rect = toast->getRect();
		toast_rect.setLeftTopAndSize(getRect().mLeft , bottom + toast_rect.getHeight(), toast_rect.getWidth() ,toast_rect.getHeight());

		toast->setRect(toast_rect);
		bottom += toast_rect.getHeight() + margin;
	}

	// use reverse order to provide correct z-order and avoid toast blinking

	for(std::vector<LLToast*>::reverse_iterator it = m_active_toasts.rbegin(); it != m_active_toasts.rend(); ++it)
	{
		LLToast* toast = (*it);
		toast->setIsHidden(false);
		toast->setVisible(TRUE);

	}
}

void LLNearbyChatScreenChannel::reshape			(S32 width, S32 height, BOOL called_from_parent)
{
	LLScreenChannelBase::reshape(width, height, called_from_parent);
	arrangeToasts();
}

//-----------------------------------------------------------------------------------------------
//LLNearbyChatHandler
//-----------------------------------------------------------------------------------------------
LLNearbyChatHandler::LLNearbyChatHandler(e_notification_type type, const LLSD& id)
{
	mType = type;

	// Getting a Channel for our notifications
	LLNearbyChatScreenChannel* channel = new LLNearbyChatScreenChannel(LLUUID(gSavedSettings.getString("NearByChatChannelUUID")));

	LLNearbyChatScreenChannel::create_toast_panel_callback_t callback = createToastPanel;

	channel->setCreatePanelCallback(callback);

	mChannel = LLChannelManager::getInstance()->addChannel(channel);
}

LLNearbyChatHandler::~LLNearbyChatHandler()
{
}

void LLNearbyChatHandler::initChannel()
{
	LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD());
	LLView* chat_box = LLBottomTray::getInstance()->getChildView("chat_box");
	S32 channel_right_bound = nearby_chat->getRect().mRight;
	mChannel->init(chat_box->getRect().mLeft, channel_right_bound);
}

void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args)
{
	if(chat_msg.mMuted == TRUE)
		return;
	if(chat_msg.mSourceType == CHAT_SOURCE_AGENT && chat_msg.mFromID.notNull())
         LLRecentPeople::instance().add(chat_msg.mFromID);

	if(chat_msg.mText.empty())
		return;//don't process empty messages

	LLChat& tmp_chat = const_cast<LLChat&>(chat_msg);

	LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD());
	{
		//sometimes its usefull to have no name at all...
		//if(tmp_chat.mFromName.empty() && tmp_chat.mFromID!= LLUUID::null)
		//	tmp_chat.mFromName = tmp_chat.mFromID.asString();
	}
	nearby_chat->addMessage(chat_msg, true, args);
	if( nearby_chat->getVisible()
		|| ( chat_msg.mSourceType == CHAT_SOURCE_AGENT
			&& gSavedSettings.getBOOL("UseChatBubbles") ) )
		return;//no need in toast if chat is visible or if bubble chat is enabled

	// Handle irc styled messages for toast panel
	if (tmp_chat.mChatStyle == CHAT_STYLE_IRC)
	{
		if(!tmp_chat.mFromName.empty())
			tmp_chat.mText = tmp_chat.mFromName + tmp_chat.mText.substr(3);
		else
			tmp_chat.mText = tmp_chat.mText.substr(3);
	}

	// arrange a channel on a screen
	if(!mChannel->getVisible())
	{
		initChannel();
	}

	/*
	//comment all this due to EXT-4432
	..may clean up after some time...

	//only messages from AGENTS
	if(CHAT_SOURCE_OBJECT == chat_msg.mSourceType)
	{
		if(chat_msg.mChatType == CHAT_TYPE_DEBUG_MSG)
			return;//ok for now we don't skip messeges from object, so skip only debug messages
	}
	*/

	LLUUID id;
	id.generate();

	LLNearbyChatScreenChannel* channel = dynamic_cast<LLNearbyChatScreenChannel*>(mChannel);

	if(channel)
	{
		LLSD notification;
		notification["id"] = id;
		notification["message"] = chat_msg.mText;
		notification["from"] = chat_msg.mFromName;
		notification["from_id"] = chat_msg.mFromID;
		notification["time"] = chat_msg.mTime;
		notification["source"] = (S32)chat_msg.mSourceType;
		notification["chat_type"] = (S32)chat_msg.mChatType;
		notification["chat_style"] = (S32)chat_msg.mChatStyle;

		std::string r_color_name = "White";
		F32 r_color_alpha = 1.0f;
		LLViewerChat::getChatColor( chat_msg, r_color_name, r_color_alpha);

		notification["text_color"] = r_color_name;
		notification["color_alpha"] = r_color_alpha;
		notification["font_size"] = (S32)LLViewerChat::getChatFontSize() ;
		channel->addNotification(notification);
	}

}

void LLNearbyChatHandler::onDeleteToast(LLToast* toast)
{
}

<commit_msg>EXT-7534 FIX add toast wrapping pannel padding<commit_after>/**
 * @file LLNearbyChatHandler.cpp
 * @brief Nearby chat notification managment
 *
 * $LicenseInfo:firstyear=2009&license=viewergpl$
 *
 * Copyright (c) 2009, Linden Research, Inc.
 *
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 *
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at
 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 *
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 *
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "llnearbychathandler.h"

#include "llbottomtray.h"
#include "llchatitemscontainerctrl.h"
#include "llnearbychat.h"
#include "llrecentpeople.h"

#include "llviewercontrol.h"

#include "llfloaterreg.h"//for LLFloaterReg::getTypedInstance
#include "llviewerwindow.h"//for screen channel position

//add LLNearbyChatHandler to LLNotificationsUI namespace
using namespace LLNotificationsUI;

//-----------------------------------------------------------------------------------------------
//LLNearbyChatScreenChannel
//-----------------------------------------------------------------------------------------------
LLToastPanelBase* createToastPanel()
{
	LLNearbyChatToastPanel* item = LLNearbyChatToastPanel::createInstance();
	return item;
}

class LLNearbyChatScreenChannel: public LLScreenChannelBase
{
public:
	LLNearbyChatScreenChannel(const LLUUID& id):LLScreenChannelBase(id) { mStopProcessing = false;};

	void addNotification	(LLSD& notification);
	void arrangeToasts		();
	void showToastsBottom	();

	typedef boost::function<LLToastPanelBase* (void )> create_toast_panel_callback_t;
	void setCreatePanelCallback(create_toast_panel_callback_t value) { m_create_toast_panel_callback_t = value;}

	void onToastDestroyed	(LLToast* toast);
	void onToastFade		(LLToast* toast);

	void reshape			(S32 width, S32 height, BOOL called_from_parent);

	void redrawToasts()
	{
		arrangeToasts();
	}

	// hide all toasts from screen, but not remove them from a channel
	virtual void		hideToastsFromScreen()
	{
	};
	// removes all toasts from a channel
	virtual void		removeToastsFromChannel()
	{
		for(std::vector<LLToast*>::iterator it = m_active_toasts.begin(); it != m_active_toasts.end(); ++it)
		{
			addToToastPool((*it));
		}
		m_active_toasts.clear();
	};

	virtual void deleteAllChildren()
	{
		m_toast_pool.clear();
		m_active_toasts.clear();
		LLScreenChannelBase::deleteAllChildren();
	}

protected:
	void	addToToastPool(LLToast* toast)
	{
		toast->setVisible(FALSE);
		toast->stopTimer();
		toast->setIsHidden(true);
		m_toast_pool.push_back(toast);
	}

	void	createOverflowToast(S32 bottom, F32 timer);

	create_toast_panel_callback_t m_create_toast_panel_callback_t;

	bool	createPoolToast();

	std::vector<LLToast*> m_active_toasts;
	std::list<LLToast*> m_toast_pool;

	bool	mStopProcessing;
};

void	LLNearbyChatScreenChannel::createOverflowToast(S32 bottom, F32 timer)
{
	//we don't need overflow toast in nearby chat
}

void LLNearbyChatScreenChannel::onToastDestroyed(LLToast* toast)
{
	mStopProcessing = true;
}

void LLNearbyChatScreenChannel::onToastFade(LLToast* toast)
{
	//fade mean we put toast to toast pool
	if(!toast)
		return;

	std::vector<LLToast*>::iterator pos = std::find(m_active_toasts.begin(),m_active_toasts.end(),toast);
	if(pos!=m_active_toasts.end())
		m_active_toasts.erase(pos);

	addToToastPool(toast);

	arrangeToasts();
}

bool	LLNearbyChatScreenChannel::createPoolToast()
{
	LLToastPanelBase* panel= m_create_toast_panel_callback_t();
	if(!panel)
		return false;

	LLToast::Params p;
	p.panel = panel;
	p.lifetime_secs = gSavedSettings.getS32("NearbyToastLifeTime");
	p.fading_time_secs = gSavedSettings.getS32("NearbyToastFadingTime");

	LLToast* toast = new LLToast(p);

	toast->setOnFadeCallback(boost::bind(&LLNearbyChatScreenChannel::onToastFade, this, _1));
	toast->setOnToastDestroyedCallback(boost::bind(&LLNearbyChatScreenChannel::onToastDestroyed, this, _1));

	m_toast_pool.push_back(toast);
	return true;
}

void LLNearbyChatScreenChannel::addNotification(LLSD& notification)
{
	//look in pool. if there is any message
	if(mStopProcessing)
		return;

	/*
    find last toast and check ID
	*/

	if(m_active_toasts.size())
	{
		LLUUID fromID = notification["from_id"].asUUID();		// agent id or object id
		std::string from = notification["from"].asString();
		LLToast* toast = m_active_toasts[0];
		LLNearbyChatToastPanel* panel = dynamic_cast<LLNearbyChatToastPanel*>(toast->getPanel());

		if(panel && panel->messageID() == fromID && panel->getFromName() == from && panel->canAddText())
		{
			panel->addMessage(notification);
			toast->reshapeToPanel();
			toast->resetTimer();

			arrangeToasts();
			return;
		}
	}

	if(m_toast_pool.empty())
	{
		//"pool" is empty - create one more panel
		if(!createPoolToast())//created toast will go to pool. so next call will find it
			return;
		addNotification(notification);
		return;
	}

	int chat_type = notification["chat_type"].asInteger();

	if( ((EChatType)chat_type == CHAT_TYPE_DEBUG_MSG))
	{
		if(gSavedSettings.getBOOL("ShowScriptErrors") == FALSE)
			return;
		if(gSavedSettings.getS32("ShowScriptErrorsLocation")== 1)
			return;
	}

	//take 1st element from pool, (re)initialize it, put it in active toasts

	LLToast* toast = m_toast_pool.back();

	m_toast_pool.pop_back();

	LLToastPanelBase* panel = dynamic_cast<LLToastPanelBase*>(toast->getPanel());
	if(!panel)
		return;
	panel->init(notification);

	toast->reshapeToPanel();
	toast->resetTimer();

	m_active_toasts.push_back(toast);

	arrangeToasts();
}

void LLNearbyChatScreenChannel::arrangeToasts()
{
	if(m_active_toasts.size() == 0 || isHovering())
		return;

	hideToastsFromScreen();

	showToastsBottom();
}

int sort_toasts_predicate(LLToast* first,LLToast* second)
{
	F32 v1 = first->getTimer()->getEventTimer().getElapsedTimeF32();
	F32 v2 = second->getTimer()->getEventTimer().getElapsedTimeF32();
	return v1 < v2;
}

void LLNearbyChatScreenChannel::showToastsBottom()
{
	if(mStopProcessing)
		return;

	LLRect	toast_rect;
	S32		bottom = getRect().mBottom;
	S32		margin = gSavedSettings.getS32("ToastGap");

	//sort active toasts
	std::sort(m_active_toasts.begin(),m_active_toasts.end(),sort_toasts_predicate);

	//calc max visible item and hide other toasts.

	for(std::vector<LLToast*>::iterator it = m_active_toasts.begin(); it != m_active_toasts.end(); ++it)
	{
		S32 toast_top = bottom + (*it)->getRect().getHeight() + margin;

		if(toast_top > gFloaterView->getRect().getHeight())
		{
			while(it!=m_active_toasts.end())
			{
				addToToastPool((*it));
				it=m_active_toasts.erase(it);
			}
			break;
		}
		LLToast* toast = (*it);

		toast_rect = toast->getRect();
		toast_rect.setLeftTopAndSize(getRect().mLeft , bottom + toast_rect.getHeight(), toast_rect.getWidth() ,toast_rect.getHeight());

		toast->setRect(toast_rect);
		bottom += toast_rect.getHeight() - toast->getTopPad() + margin;
	}

	// use reverse order to provide correct z-order and avoid toast blinking

	for(std::vector<LLToast*>::reverse_iterator it = m_active_toasts.rbegin(); it != m_active_toasts.rend(); ++it)
	{
		LLToast* toast = (*it);
		toast->setIsHidden(false);
		toast->setVisible(TRUE);

	}
}

void LLNearbyChatScreenChannel::reshape			(S32 width, S32 height, BOOL called_from_parent)
{
	LLScreenChannelBase::reshape(width, height, called_from_parent);
	arrangeToasts();
}

//-----------------------------------------------------------------------------------------------
//LLNearbyChatHandler
//-----------------------------------------------------------------------------------------------
LLNearbyChatHandler::LLNearbyChatHandler(e_notification_type type, const LLSD& id)
{
	mType = type;

	// Getting a Channel for our notifications
	LLNearbyChatScreenChannel* channel = new LLNearbyChatScreenChannel(LLUUID(gSavedSettings.getString("NearByChatChannelUUID")));

	LLNearbyChatScreenChannel::create_toast_panel_callback_t callback = createToastPanel;

	channel->setCreatePanelCallback(callback);

	mChannel = LLChannelManager::getInstance()->addChannel(channel);
}

LLNearbyChatHandler::~LLNearbyChatHandler()
{
}

void LLNearbyChatHandler::initChannel()
{
	LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD());
	LLView* chat_box = LLBottomTray::getInstance()->getChildView("chat_box");
	S32 channel_right_bound = nearby_chat->getRect().mRight;
	mChannel->init(chat_box->getRect().mLeft, channel_right_bound);
}

void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args)
{
	if(chat_msg.mMuted == TRUE)
		return;
	if(chat_msg.mSourceType == CHAT_SOURCE_AGENT && chat_msg.mFromID.notNull())
         LLRecentPeople::instance().add(chat_msg.mFromID);

	if(chat_msg.mText.empty())
		return;//don't process empty messages

	LLChat& tmp_chat = const_cast<LLChat&>(chat_msg);

	LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD());
	{
		//sometimes its usefull to have no name at all...
		//if(tmp_chat.mFromName.empty() && tmp_chat.mFromID!= LLUUID::null)
		//	tmp_chat.mFromName = tmp_chat.mFromID.asString();
	}
	nearby_chat->addMessage(chat_msg, true, args);
	if( nearby_chat->getVisible()
		|| ( chat_msg.mSourceType == CHAT_SOURCE_AGENT
			&& gSavedSettings.getBOOL("UseChatBubbles") ) )
		return;//no need in toast if chat is visible or if bubble chat is enabled

	// Handle irc styled messages for toast panel
	if (tmp_chat.mChatStyle == CHAT_STYLE_IRC)
	{
		if(!tmp_chat.mFromName.empty())
			tmp_chat.mText = tmp_chat.mFromName + tmp_chat.mText.substr(3);
		else
			tmp_chat.mText = tmp_chat.mText.substr(3);
	}

	// arrange a channel on a screen
	if(!mChannel->getVisible())
	{
		initChannel();
	}

	/*
	//comment all this due to EXT-4432
	..may clean up after some time...

	//only messages from AGENTS
	if(CHAT_SOURCE_OBJECT == chat_msg.mSourceType)
	{
		if(chat_msg.mChatType == CHAT_TYPE_DEBUG_MSG)
			return;//ok for now we don't skip messeges from object, so skip only debug messages
	}
	*/

	LLUUID id;
	id.generate();

	LLNearbyChatScreenChannel* channel = dynamic_cast<LLNearbyChatScreenChannel*>(mChannel);

	if(channel)
	{
		LLSD notification;
		notification["id"] = id;
		notification["message"] = chat_msg.mText;
		notification["from"] = chat_msg.mFromName;
		notification["from_id"] = chat_msg.mFromID;
		notification["time"] = chat_msg.mTime;
		notification["source"] = (S32)chat_msg.mSourceType;
		notification["chat_type"] = (S32)chat_msg.mChatType;
		notification["chat_style"] = (S32)chat_msg.mChatStyle;

		std::string r_color_name = "White";
		F32 r_color_alpha = 1.0f;
		LLViewerChat::getChatColor( chat_msg, r_color_name, r_color_alpha);

		notification["text_color"] = r_color_name;
		notification["color_alpha"] = r_color_alpha;
		notification["font_size"] = (S32)LLViewerChat::getChatFontSize() ;
		channel->addNotification(notification);
	}

}

void LLNearbyChatHandler::onDeleteToast(LLToast* toast)
{
}

<|endoftext|>


<commit_before>#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QObject>
#include <QtWidgets>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    mainWindowIcon(":/Resources/icons/mainWindowIcon.jpg"),
    isPlaying(false),
    prevButtonIcon(":/Resources/icons/Button-Prev-icon.png"),
    playButtonPlayIcon(":/Resources/icons/Button-Play-icon.png"),
    playButtonPauseIcon(":/Resources/icons/Button-Pause-icon.png"),
    nextButtonIcon(":/Resources/icons/Button-Next-icon.png"),
    _player(0),
    _playlist(this)
{
    ui->setupUi(this);
    setWindowIcon(mainWindowIcon);
    setWindowTitle("Music Player");

    setFixedWidth(5*72);
    setFixedHeight(3*72);

    /****************SETTING UP MENUS*********************/
    QWidget *topFiller = new QWidget;
    topFiller->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

#ifdef Q_OS_SYMBIAN
    infoLabel = new QLabel(tr("Choose a menu option"));
#else
    infoLabel = new QLabel(tr("Choose a menu option, or right-click to "
                              "invoke a context menu"));
#endif
    infoLabel->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
    infoLabel->setAlignment(Qt::AlignCenter);

    QWidget *bottomFiller = new QWidget;
    bottomFiller->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    QVBoxLayout *layout = new QVBoxLayout;
    layout->setMargin(5);
    layout->addWidget(topFiller);
    layout->addWidget(infoLabel);
    layout->addWidget(bottomFiller);

    createActions();
    createMenus();

    /************SETTING UP STATUS BAR********************/
#ifndef Q_OS_SYMBIAN
    QString message = tr("A context menu is available by right-clicking");
    statusBar()->showMessage(message);
#endif

    /*****************SETTING UP BUTTONS******************/
    const int mediaButtonYCoordinate =
            (
                (height() + layout->geometry().height())-
                ((width()/5) + statusBar()->geometry().height() - 8)
            );
    /*************SETTING UP PREV BUTTON******************/
    connect(&prevButton, SIGNAL(clicked()), this, SLOT(prevButtonIsPressed()));
    prevButton.setParent(this);
    prevButton.setGeometry
            (
                0,
                mediaButtonYCoordinate,
                width()/5,
                width()/5
            );
    prevButton.setIcon(prevButtonIcon);
    prevButton.setIconSize(QSize(prevButton.height(),prevButton.height()));
    prevButton.show();

    /*************SETTING UP PLAY BUTTON******************/
    connect(&playButton, SIGNAL(clicked()), this, SLOT(playButtonIsPressed()));
    playButton.setParent(this);
    playButton.setGeometry
            (
                prevButton.width()*2,
                mediaButtonYCoordinate,
                width()/5,
                width()/5
            );
    playButton.setIcon(playButtonPlayIcon);
    playButton.setIconSize(QSize(playButton.height(),playButton.height()));
    playButton.show();

    /*************SETTING UP NEXT BUTTON******************/
    connect(&nextButton, SIGNAL(clicked()), this, SLOT(nextButtonIsPressed()));
    nextButton.setParent(this);
    nextButton.setGeometry
            (
                playButton.width()*4,
                mediaButtonYCoordinate,
                width()/5,
                width()/5
            );
    nextButton.setIcon(nextButtonIcon);
    nextButton.setIconSize(QSize(nextButton.height(),nextButton.height()));
    nextButton.show();

    /*************SETTING UP VOLUME SLIDER******************/

    volumeLabel = new QLabel;
    volumeLabel->setText(tr("Volume:"));
    volumeLabel->setParent(this);
    volumeSlider = new QSlider(Qt::Horizontal);
    volumeSlider->setParent(this);
    volumeSlider->setMinimum(0);
    volumeSlider->setMaximum(100);
    volumeSlider->setSingleStep(10);
    volumeSlider->setGeometry
            (
                nextButton.geometry().x(),
                mediaButtonYCoordinate-20,
                playButton.width(),
                20
            );
    volumeLabel->setGeometry
            (
                volumeSlider->geometry().x()-60,
                volumeSlider->geometry().y(),
                60,
                volumeSlider->height()
            );
    volumeLabel->show();
    volumeSlider->show();

    /******************SOUND CODE******************/
    _player = new QMediaPlayer;
    _player->setMedia(QUrl::fromLocalFile("/home/dustin/CS/MusicPlayer/cs372-FinalProject/test.mp3"));
    _player->setVolume(100);

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::contextMenuEvent(QContextMenuEvent *event)
{
    QMenu menu(this);
    menu.addAction(playAct);
    menu.addAction(nextSongAct);
    menu.addAction(previousSongAct);
    menu.exec(event->globalPos());
}

void MainWindow::play()
{
    playButtonIsPressed();
}

void MainWindow::nextSong()
{
    nextButtonIsPressed();
}

void MainWindow::previousSong()
{
    prevButtonIsPressed();
}

void MainWindow::open()
{
   QFileDialog openFileDialog(this);
   openFileDialog.setNameFilter(tr("Audio (*.mp3 *.mp4 *.wav *.flac *.ogg)"));
   openFileDialog.setViewMode(QFileDialog::List);
   openFileDialog.setFileMode(QFileDialog::ExistingFiles);

   QStringList fileNames;
   if(openFileDialog.exec())
       fileNames = openFileDialog.selectedFiles();

   QList<QMediaContent> playListFiles;

   for(QStringList::iterator file = fileNames.begin(); file < fileNames.end(); file++)
       playListFiles.append(QMediaContent(QUrl::fromLocalFile(*file)));

   _playlist.clear();
   _playlist.addMedia(playListFiles);
   _player->stop();
   _player->setPlaylist(&_playlist);
   _player->setPosition(1);
}

void MainWindow::about()
{
    infoLabel->setText(tr("Invoked Help|About"));
    QMessageBox::about(this, tr("About Menu"),
            tr("Hit Play to Play Mooxzikz. "
               "Open to Open More Moozikz."));
//TODO: docoomentimgz
}

void MainWindow::aboutQt()
{
    infoLabel->setText(tr("Invoked Help|About Qt"));
}

void MainWindow::createActions()
{
    openAct = new QAction(tr("&Open..."), this);
    openAct->setStatusTip(tr("Open an existing file"));
    connect(openAct, SIGNAL(triggered()), this, SLOT(open()));

    exitAct = new QAction(tr("E&xit"), this);
    exitAct->setStatusTip(tr("Exit the application"));
    connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));

    playAct = new QAction(tr("&Play/Pause"), this);
    playAct->setStatusTip(tr("Play a song"));
    connect(playAct, SIGNAL(triggered()), this, SLOT(play()));

    nextSongAct = new QAction(tr("&Next Song"), this);
    nextSongAct->setStatusTip(tr("Switches to the Next Song"));
    connect(nextSongAct, SIGNAL(triggered()), this, SLOT(nextSong()));

    previousSongAct = new QAction(tr("&Previous Song"), this);
    previousSongAct->setStatusTip(tr("Switches to the Previous Song"));
    connect(previousSongAct, SIGNAL(triggered()), this, SLOT(previousSong()));

    aboutAct = new QAction(tr("&About"), this);
    aboutAct->setStatusTip(tr("Show the application's About box"));
    connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));

    aboutQtAct = new QAction(tr("About &Qt"), this);
    aboutQtAct->setStatusTip(tr("Show the Qt library's About box"));
    connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
    connect(aboutQtAct, SIGNAL(triggered()), this, SLOT(aboutQt()));
}

void MainWindow::createMenus()
{
    fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(openAct);
    fileMenu->addSeparator();
    fileMenu->addAction(exitAct);

    playMenu = menuBar()->addMenu(tr("&Play"));
    playMenu->addSeparator();
    playMenu->addAction(playAct);
    playMenu->addAction(nextSongAct);
    playMenu->addAction(previousSongAct);

    helpMenu = menuBar()->addMenu(tr("&Help"));
    helpMenu->addAction(aboutAct);
    helpMenu->addAction(aboutQtAct);
}

<commit_msg>Took out hard path so no more changing<commit_after>#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QObject>
#include <QtWidgets>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    mainWindowIcon(":/Resources/icons/mainWindowIcon.jpg"),
    isPlaying(false),
    prevButtonIcon(":/Resources/icons/Button-Prev-icon.png"),
    playButtonPlayIcon(":/Resources/icons/Button-Play-icon.png"),
    playButtonPauseIcon(":/Resources/icons/Button-Pause-icon.png"),
    nextButtonIcon(":/Resources/icons/Button-Next-icon.png"),
    _player(0),
    _playlist(this)
{
    ui->setupUi(this);
    setWindowIcon(mainWindowIcon);
    setWindowTitle("Music Player");

    setFixedWidth(5*72);
    setFixedHeight(3*72);

    /****************SETTING UP MENUS*********************/
    QWidget *topFiller = new QWidget;
    topFiller->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

#ifdef Q_OS_SYMBIAN
    infoLabel = new QLabel(tr("Choose a menu option"));
#else
    infoLabel = new QLabel(tr("Choose a menu option, or right-click to "
                              "invoke a context menu"));
#endif
    infoLabel->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
    infoLabel->setAlignment(Qt::AlignCenter);

    QWidget *bottomFiller = new QWidget;
    bottomFiller->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    QVBoxLayout *layout = new QVBoxLayout;
    layout->setMargin(5);
    layout->addWidget(topFiller);
    layout->addWidget(infoLabel);
    layout->addWidget(bottomFiller);

    createActions();
    createMenus();

    /************SETTING UP STATUS BAR********************/
#ifndef Q_OS_SYMBIAN
    QString message = tr("A context menu is available by right-clicking");
    statusBar()->showMessage(message);
#endif

    /*****************SETTING UP BUTTONS******************/
    const int mediaButtonYCoordinate =
            (
                (height() + layout->geometry().height())-
                ((width()/5) + statusBar()->geometry().height() - 8)
            );
    /*************SETTING UP PREV BUTTON******************/
    connect(&prevButton, SIGNAL(clicked()), this, SLOT(prevButtonIsPressed()));
    prevButton.setParent(this);
    prevButton.setGeometry
            (
                0,
                mediaButtonYCoordinate,
                width()/5,
                width()/5
            );
    prevButton.setIcon(prevButtonIcon);
    prevButton.setIconSize(QSize(prevButton.height(),prevButton.height()));
    prevButton.show();

    /*************SETTING UP PLAY BUTTON******************/
    connect(&playButton, SIGNAL(clicked()), this, SLOT(playButtonIsPressed()));
    playButton.setParent(this);
    playButton.setGeometry
            (
                prevButton.width()*2,
                mediaButtonYCoordinate,
                width()/5,
                width()/5
            );
    playButton.setIcon(playButtonPlayIcon);
    playButton.setIconSize(QSize(playButton.height(),playButton.height()));
    playButton.show();

    /*************SETTING UP NEXT BUTTON******************/
    connect(&nextButton, SIGNAL(clicked()), this, SLOT(nextButtonIsPressed()));
    nextButton.setParent(this);
    nextButton.setGeometry
            (
                playButton.width()*4,
                mediaButtonYCoordinate,
                width()/5,
                width()/5
            );
    nextButton.setIcon(nextButtonIcon);
    nextButton.setIconSize(QSize(nextButton.height(),nextButton.height()));
    nextButton.show();

    /*************SETTING UP VOLUME SLIDER******************/

    volumeLabel = new QLabel;
    volumeLabel->setText(tr("Volume:"));
    volumeLabel->setParent(this);
    volumeSlider = new QSlider(Qt::Horizontal);
    volumeSlider->setParent(this);
    volumeSlider->setMinimum(0);
    volumeSlider->setMaximum(100);
    volumeSlider->setSingleStep(10);
    volumeSlider->setGeometry
            (
                nextButton.geometry().x(),
                mediaButtonYCoordinate-20,
                playButton.width(),
                20
            );
    volumeLabel->setGeometry
            (
                volumeSlider->geometry().x()-60,
                volumeSlider->geometry().y(),
                60,
                volumeSlider->height()
            );
    volumeLabel->show();
    volumeSlider->show();

    /******************SOUND CODE******************/
    _player = new QMediaPlayer;
   // _player->setMedia(QUrl::fromLocalFile());
    _player->setVolume(100);

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::contextMenuEvent(QContextMenuEvent *event)
{
    QMenu menu(this);
    menu.addAction(playAct);
    menu.addAction(nextSongAct);
    menu.addAction(previousSongAct);
    menu.exec(event->globalPos());
}

void MainWindow::play()
{
    playButtonIsPressed();
}

void MainWindow::nextSong()
{
    nextButtonIsPressed();
}

void MainWindow::previousSong()
{
    prevButtonIsPressed();
}

void MainWindow::open()
{
   QFileDialog openFileDialog(this);
   openFileDialog.setNameFilter(tr("Audio (*.mp3 *.mp4 *.wav *.flac *.ogg)"));
   openFileDialog.setViewMode(QFileDialog::List);
   openFileDialog.setFileMode(QFileDialog::ExistingFiles);

   QStringList fileNames;
   if(openFileDialog.exec())
       fileNames = openFileDialog.selectedFiles();

   QList<QMediaContent> playListFiles;

   for(QStringList::iterator file = fileNames.begin(); file < fileNames.end(); file++)
       playListFiles.append(QMediaContent(QUrl::fromLocalFile(*file)));

   _playlist.clear();
   _playlist.addMedia(playListFiles);
   _player->stop();
   _player->setPlaylist(&_playlist);
   _player->setPosition(1);
}

void MainWindow::about()
{
    infoLabel->setText(tr("Invoked Help|About"));
    QMessageBox::about(this, tr("About Menu"),
            tr("Hit Play to Play Mooxzikz. "
               "Open to Open More Moozikz."));
//TODO: docoomentimgz
}

void MainWindow::aboutQt()
{
    infoLabel->setText(tr("Invoked Help|About Qt"));
}

void MainWindow::createActions()
{
    openAct = new QAction(tr("&Open..."), this);
    openAct->setStatusTip(tr("Open an existing file"));
    connect(openAct, SIGNAL(triggered()), this, SLOT(open()));

    exitAct = new QAction(tr("E&xit"), this);
    exitAct->setStatusTip(tr("Exit the application"));
    connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));

    playAct = new QAction(tr("&Play/Pause"), this);
    playAct->setStatusTip(tr("Play a song"));
    connect(playAct, SIGNAL(triggered()), this, SLOT(play()));

    nextSongAct = new QAction(tr("&Next Song"), this);
    nextSongAct->setStatusTip(tr("Switches to the Next Song"));
    connect(nextSongAct, SIGNAL(triggered()), this, SLOT(nextSong()));

    previousSongAct = new QAction(tr("&Previous Song"), this);
    previousSongAct->setStatusTip(tr("Switches to the Previous Song"));
    connect(previousSongAct, SIGNAL(triggered()), this, SLOT(previousSong()));

    aboutAct = new QAction(tr("&About"), this);
    aboutAct->setStatusTip(tr("Show the application's About box"));
    connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));

    aboutQtAct = new QAction(tr("About &Qt"), this);
    aboutQtAct->setStatusTip(tr("Show the Qt library's About box"));
    connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
    connect(aboutQtAct, SIGNAL(triggered()), this, SLOT(aboutQt()));
}

void MainWindow::createMenus()
{
    fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(openAct);
    fileMenu->addSeparator();
    fileMenu->addAction(exitAct);

    playMenu = menuBar()->addMenu(tr("&Play"));
    playMenu->addSeparator();
    playMenu->addAction(playAct);
    playMenu->addAction(nextSongAct);
    playMenu->addAction(previousSongAct);

    helpMenu = menuBar()->addMenu(tr("&Help"));
    helpMenu->addAction(aboutAct);
    helpMenu->addAction(aboutQtAct);
}

<|endoftext|>


<commit_before>#include <iterator>
#include <stdexcept>
#include <string>
#include <vector>
#include <QByteArray>
#include <QDebug>
#include <QFile>
#include <QFileDialog>
#include <QRegExp>
#include <QSettings>
#include <QString>
#include <QStringList>
#include <QTableWidgetItem>
#include <QTextStream>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkCookie>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest>
#include <QUrl>
#include <QVariant>
#include "mainwindow.hpp"
#include "sfcsv/sfcsv.h"
#include "ui_mainwindow.h"

static QString parseImdbId(const QString& text) {
    static const QRegExp imdbIdRx("ur([0-9]{7,8})");

    if(imdbIdRx.indexIn(text) == -1) {
        return {};
    }

    return imdbIdRx.cap(1);
}

static QString parseListId(const QString& text) {
    static const QRegExp listIdRx("ls([0-9]{9})");

    if(listIdRx.indexIn(text) == -1) {
        return {};
    }

    return listIdRx.cap(1);
}

static QStringList parseCsv(const QString& in) {
    QStringList result;
    std::vector<std::string> parsed;
    const std::string line = in.toStdString();
    sfcsv::parse_line(line, std::back_inserter(parsed), ',');
    for(auto&& res : parsed) {
        result.append(QString::fromStdString(res));
    }

    return result;
}

static QList<QNetworkCookie> parseCookies(const QString& cookies) {
    QList<QNetworkCookie> result;

    const QStringList pairs = cookies.split("; ");
    if(pairs.size() == 1) {
        return {};
    }

    for(const QString& pair : pairs) {
        const QStringList kv = pair.split("=");
        if(kv.size() == 1) {
            return {};
        }

        QByteArray key, value;
        key.append(kv.at(0));
        value.append(kv.at(1));

        const QNetworkCookie cookie(key, value);
        result.append(cookie);
    }

    return result;
}

static QStringList parseFile(const QString& in) {
    QStringList results;
    QFile inFile(in);
    if(!inFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
        throw std::runtime_error("Unable to open file");
    }

    QTextStream stream(&inFile);
    stream.setCodec("UTF-8");
    while(!stream.atEnd()) {
        const QString line = stream.readLine().remove("\n");
        results << line;
    }

    return results;
}

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    netManager(new QNetworkAccessManager),
    config("IMDbDownloaderConfig.ini", QSettings::IniFormat)
{
    ui->setupUi(this);

    connect(netManager.get(),   SIGNAL(finished(QNetworkReply *)),
            this,               SLOT(networkReplyFinished(QNetworkReply*)));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_actionOpen_triggered()
{
    const QString openedFile = QFileDialog::getOpenFileName(this, tr("Open..."),
                                                            config.value("last_csv").toString());
    if(openedFile.isEmpty()) {
        return;
    }

    config.setValue("last_csv", openedFile);

    const QStringList lines = parseFile(openedFile);
    const QString header = lines.first();
    const QStringList headerParsed = parseCsv(header);

    ui->plainTextLog->clear();
    ui->tableCsv->clear();
    ui->tableCsv->setColumnCount(headerParsed.size() + 1);
    ui->tableCsv->setHorizontalHeaderLabels(QStringList() << "List Name" << "URL" << "Status");
    ui->tableCsv->setRowCount(lines.size());

    for(int row = 0; row < lines.size(); ++row) {
        const QStringList columns = parseCsv(lines.at(row));
        const QString username = columns.at(0);
        const QString url = columns.at(1);

        ui->tableCsv->setItem(row, 0, new QTableWidgetItem(username));
        ui->tableCsv->setItem(row, 1, new QTableWidgetItem(url));
        ui->tableCsv->setItem(row, 2, new QTableWidgetItem("Waiting"));

        const QString urlId = parseUrlId(url);
        QString requestUrl;
        if(ui->radioRatings->isChecked()) {
            // IMDb ratings
            requestUrl = QString("http://www.imdb.com/list/export?list_id=ratings&author_id=ur%1").arg(urlId);
        }
        else {
            // IMDb lists
            requestUrl = QString("http://www.imdb.com/list/export?list_id=ls%1&author_id=ur27588704").arg(urlId);
        }

        if(!requestUrl.isEmpty()) {
            requests.append(QNetworkRequest(requestUrl));
        }

        qDebug() << "Added" << username << url << requestUrl;

    }

    ui->plainTextLog->appendPlainText(tr("Enqueued %1 URLs").arg(requests.size()));
}

void MainWindow::networkReplyFinished(QNetworkReply *reply)
{
    // Remove highlight from current
    const int row = findItemRow(parseUrlId(reply->url().toDisplayString()));

    if(reply->error()) {
        setRowColor(row, QColor(Qt::red));

        setRowStatus(row, tr("Failed. Retrying..."));

        // Enqueue the request
        requests.append(QNetworkRequest(reply->url()));

        // Start another request
        nextRequest();
        return;
    }

    setRowStatus(row, tr("Saved"));
    setRowColor(row, QColor(Qt::green));

    const QString url = reply->url().toDisplayString();
    const QString data = reply->readAll();

    // Find who this imdb id belongs to
    const QString imdbId = parseUrlId(url);
    if(row != -1) {
        const QString username = ui->tableCsv->item(row, 0)->text().trimmed();
        QFile out(QString("%1/%2.csv").arg(config.value("save_to").toString()).arg(username));
        out.open(QIODevice::WriteOnly | QIODevice::Text);

        QTextStream stream(&out);
        stream.setCodec("UTF-8");
        stream << data;
    }

    reply->deleteLater();

    // Start another request
    nextRequest();
}

void MainWindow::on_buttonDownload_clicked()
{
    const QString savePath = QFileDialog::getExistingDirectory(this, tr("Save to..."),
                                                               config.value("save_to").toString());
    if(savePath.isEmpty()) {
        return;
    }

    config.setValue("save_to", savePath);

    for(int i = 0, last = ui->spinBoxSimReqs->value(); i < last; ++i) {
        nextRequest();
    }
}

void MainWindow::on_buttonLoadCookies_clicked()
{
    const QString openedFile =
            QFileDialog::getOpenFileName(this, tr("Cookies"),
                                         config.value("last_cookies").toString());
    if(openedFile.isEmpty()) {
        return;
    }

    config.setValue("last_cookies", openedFile);

    QFile in(openedFile);
    if(!in.open(QIODevice::ReadOnly | QIODevice::Text)) {
        ui->plainTextLog->appendPlainText(tr("Failed to open cookies file. Insufficient permissions?"));
        return;
    }

    const QString cookies = in.readAll();
    netCookies = parseCookies(cookies);
    if(netCookies.empty()) {
        ui->plainTextLog->appendPlainText(tr("Invalid cookie format"));

        return;
    }

    ui->plainTextLog->appendPlainText(tr("Loaded cookies."));
}

void MainWindow::nextRequest()
{
    if(requests.empty()) {
        return;
    }

    QVariant cookieVar;
    cookieVar.setValue(netCookies);

    // Makes sure files are only overwritten if explicitly specified
    // or to request files that do not exist
    while(!requests.empty()) {
        QNetworkRequest req = requests.takeFirst();
        req.setHeader(QNetworkRequest::CookieHeader, cookieVar);

        const QUrl url = req.url();
        const int row = findItemRow(parseUrlId(url.toDisplayString()));

        const QString username = ui->tableCsv->item(row, 0)->text();
        const QString savePath = QString("%1/%2.csv").arg(config.value("save_to").toString()).arg(username);
        if(ui->checkBoxOverwrite->isChecked() || !QFile::exists(savePath)) {
            // Highlight current
            setRowColor(row, QColor(Qt::yellow));
            setRowStatus(row, tr("Downloading"));

            netManager->get(req);

            break;
        }
        else {
            setRowStatus(row, tr("Skipped"));
        }
    }
}

int MainWindow::findItemRow(const QString& imdbId) const
{
    int foundRow = -1;
    const auto users = ui->tableCsv->rowCount();
    for(int row = 0; row < users; ++row) {
        auto current = ui->tableCsv->item(row, 1);
        const QString imdbUrl = current->text();

        const QString userImdbId = parseUrlId(imdbUrl);
        if(imdbId == userImdbId) {
            foundRow = ui->tableCsv->row(current);
            break;
        }
    }

    return foundRow;
}

QString MainWindow::parseUrlId(const QString& url) const
{
    QString id;
    if(ui->radioRatings->isChecked()) {
        id = parseImdbId(url);
    }
    else {
        id = parseListId(url);
    }

    return id;
}

void MainWindow::setRowStatus(const int row, const QString& status)
{
    ui->tableCsv->item(row, 2)->setText(status);
}

void MainWindow::setRowColor(const int row, const QColor& color)
{
    const QBrush brush(color);
    for(int column = 0, last = ui->tableCsv->columnCount(); column < last; ++column) {
        ui->tableCsv->item(row, column)->setBackground(brush);
    }
}
<commit_msg>Newlines (minor refactoring)<commit_after>#include <iterator>
#include <stdexcept>
#include <string>
#include <vector>
#include <QByteArray>
#include <QDebug>
#include <QFile>
#include <QFileDialog>
#include <QRegExp>
#include <QSettings>
#include <QString>
#include <QStringList>
#include <QTableWidgetItem>
#include <QTextStream>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkCookie>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest>
#include <QUrl>
#include <QVariant>
#include "mainwindow.hpp"
#include "sfcsv/sfcsv.h"
#include "ui_mainwindow.h"

static QString parseImdbId(const QString& text) {
    static const QRegExp imdbIdRx("ur([0-9]{7,8})");

    if(imdbIdRx.indexIn(text) == -1) {
        return {};
    }

    return imdbIdRx.cap(1);
}

static QString parseListId(const QString& text) {
    static const QRegExp listIdRx("ls([0-9]{9})");

    if(listIdRx.indexIn(text) == -1) {
        return {};
    }

    return listIdRx.cap(1);
}

static QStringList parseCsv(const QString& in) {
    QStringList result;

    std::vector<std::string> parsed;
    const std::string line = in.toStdString();
    sfcsv::parse_line(line, std::back_inserter(parsed), ',');
    for(auto&& res : parsed) {
        result.append(QString::fromStdString(res));
    }

    return result;
}

static QList<QNetworkCookie> parseCookies(const QString& cookies) {
    QList<QNetworkCookie> result;

    const QStringList pairs = cookies.split("; ");
    if(pairs.size() == 1) {
        return {};
    }

    for(const QString& pair : pairs) {
        const QStringList kv = pair.split("=");
        if(kv.size() == 1) {
            return {};
        }

        QByteArray key, value;
        key.append(kv.at(0));
        value.append(kv.at(1));

        const QNetworkCookie cookie(key, value);
        result.append(cookie);
    }

    return result;
}

static QStringList parseFile(const QString& in) {
    QStringList results;

    QFile inFile(in);
    if(!inFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
        throw std::runtime_error("Unable to open file");
    }

    QTextStream stream(&inFile);
    stream.setCodec("UTF-8");
    while(!stream.atEnd()) {
        const QString line = stream.readLine().remove("\n");
        results << line;
    }

    return results;
}

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    netManager(new QNetworkAccessManager),
    config("IMDbDownloaderConfig.ini", QSettings::IniFormat)
{
    ui->setupUi(this);

    connect(netManager.get(),   SIGNAL(finished(QNetworkReply *)),
            this,               SLOT(networkReplyFinished(QNetworkReply*)));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_actionOpen_triggered()
{
    const QString openedFile = QFileDialog::getOpenFileName(this, tr("Open..."),
                                                            config.value("last_csv").toString());
    if(openedFile.isEmpty()) {
        return;
    }

    config.setValue("last_csv", openedFile);

    const QStringList lines = parseFile(openedFile);
    const QString header = lines.first();
    const QStringList headerParsed = parseCsv(header);

    ui->plainTextLog->clear();
    ui->tableCsv->clear();
    ui->tableCsv->setColumnCount(headerParsed.size() + 1);
    ui->tableCsv->setHorizontalHeaderLabels(QStringList() << "List Name" << "URL" << "Status");
    ui->tableCsv->setRowCount(lines.size());

    for(int row = 0; row < lines.size(); ++row) {
        const QStringList columns = parseCsv(lines.at(row));
        const QString username = columns.at(0);
        const QString url = columns.at(1);

        ui->tableCsv->setItem(row, 0, new QTableWidgetItem(username));
        ui->tableCsv->setItem(row, 1, new QTableWidgetItem(url));
        ui->tableCsv->setItem(row, 2, new QTableWidgetItem("Waiting"));

        const QString urlId = parseUrlId(url);
        QString requestUrl;
        if(ui->radioRatings->isChecked()) {
            // IMDb ratings
            requestUrl = QString("http://www.imdb.com/list/export?list_id=ratings&author_id=ur%1").arg(urlId);
        }
        else {
            // IMDb lists
            requestUrl = QString("http://www.imdb.com/list/export?list_id=ls%1&author_id=ur27588704").arg(urlId);
        }

        if(!requestUrl.isEmpty()) {
            requests.append(QNetworkRequest(requestUrl));
        }

        qDebug() << "Added" << username << url << requestUrl;

    }

    ui->plainTextLog->appendPlainText(tr("Enqueued %1 URLs").arg(requests.size()));
}

void MainWindow::networkReplyFinished(QNetworkReply *reply)
{
    // Remove highlight from current
    const int row = findItemRow(parseUrlId(reply->url().toDisplayString()));

    if(reply->error()) {
        setRowColor(row, QColor(Qt::red));

        setRowStatus(row, tr("Failed. Retrying..."));

        // Enqueue the request
        requests.append(QNetworkRequest(reply->url()));

        // Start another request
        nextRequest();
        return;
    }

    setRowStatus(row, tr("Saved"));
    setRowColor(row, QColor(Qt::green));

    const QString url = reply->url().toDisplayString();
    const QString data = reply->readAll();

    // Find who this imdb id belongs to
    const QString imdbId = parseUrlId(url);
    if(row != -1) {
        const QString username = ui->tableCsv->item(row, 0)->text().trimmed();
        QFile out(QString("%1/%2.csv").arg(config.value("save_to").toString()).arg(username));
        out.open(QIODevice::WriteOnly | QIODevice::Text);

        QTextStream stream(&out);
        stream.setCodec("UTF-8");
        stream << data;
    }

    reply->deleteLater();

    // Start another request
    nextRequest();
}

void MainWindow::on_buttonDownload_clicked()
{
    const QString savePath = QFileDialog::getExistingDirectory(this, tr("Save to..."),
                                                               config.value("save_to").toString());
    if(savePath.isEmpty()) {
        return;
    }

    config.setValue("save_to", savePath);

    for(int i = 0, last = ui->spinBoxSimReqs->value(); i < last; ++i) {
        nextRequest();
    }
}

void MainWindow::on_buttonLoadCookies_clicked()
{
    const QString openedFile =
            QFileDialog::getOpenFileName(this, tr("Cookies"),
                                         config.value("last_cookies").toString());
    if(openedFile.isEmpty()) {
        return;
    }

    config.setValue("last_cookies", openedFile);

    QFile in(openedFile);
    if(!in.open(QIODevice::ReadOnly | QIODevice::Text)) {
        ui->plainTextLog->appendPlainText(tr("Failed to open cookies file. Insufficient permissions?"));
        return;
    }

    const QString cookies = in.readAll();
    netCookies = parseCookies(cookies);
    if(netCookies.empty()) {
        ui->plainTextLog->appendPlainText(tr("Invalid cookie format"));

        return;
    }

    ui->plainTextLog->appendPlainText(tr("Loaded cookies."));
}

void MainWindow::nextRequest()
{
    if(requests.empty()) {
        return;
    }

    QVariant cookieVar;
    cookieVar.setValue(netCookies);

    // Makes sure files are only overwritten if explicitly specified
    // or to request files that do not exist
    while(!requests.empty()) {
        QNetworkRequest req = requests.takeFirst();
        req.setHeader(QNetworkRequest::CookieHeader, cookieVar);

        const QUrl url = req.url();
        const int row = findItemRow(parseUrlId(url.toDisplayString()));

        const QString username = ui->tableCsv->item(row, 0)->text();
        const QString savePath = QString("%1/%2.csv").arg(config.value("save_to").toString()).arg(username);
        if(ui->checkBoxOverwrite->isChecked() || !QFile::exists(savePath)) {
            // Highlight current
            setRowColor(row, QColor(Qt::yellow));
            setRowStatus(row, tr("Downloading"));

            netManager->get(req);

            break;
        }
        else {
            setRowStatus(row, tr("Skipped"));
        }
    }
}

int MainWindow::findItemRow(const QString& imdbId) const
{
    int foundRow = -1;
    const auto users = ui->tableCsv->rowCount();
    for(int row = 0; row < users; ++row) {
        auto current = ui->tableCsv->item(row, 1);
        const QString imdbUrl = current->text();

        const QString userImdbId = parseUrlId(imdbUrl);
        if(imdbId == userImdbId) {
            foundRow = ui->tableCsv->row(current);
            break;
        }
    }

    return foundRow;
}

QString MainWindow::parseUrlId(const QString& url) const
{
    QString id;
    if(ui->radioRatings->isChecked()) {
        id = parseImdbId(url);
    }
    else {
        id = parseListId(url);
    }

    return id;
}

void MainWindow::setRowStatus(const int row, const QString& status)
{
    ui->tableCsv->item(row, 2)->setText(status);
}

void MainWindow::setRowColor(const int row, const QColor& color)
{
    const QBrush brush(color);
    for(int column = 0, last = ui->tableCsv->columnCount(); column < last; ++column) {
        ui->tableCsv->item(row, column)->setBackground(brush);
    }
}
<|endoftext|>