dashboard.cpp 12.6 KB
Newer Older
Daniel Laidig's avatar
Daniel Laidig committed
1
/***************************************************************************
Inge Wallin's avatar
Inge Wallin committed
2
    Copyright 2014 Inge Wallin <inge@lysator.liu.se>
Daniel Laidig's avatar
Daniel Laidig committed
3 4 5 6 7 8 9 10 11 12 13
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

Yuri Chornoivan's avatar
Yuri Chornoivan committed
14 15
#include "dashboard.h"

16
#include <QTimer>
17 18
#include <QAction>
#include <QMessageBox>
Amarvir Singh's avatar
Amarvir Singh committed
19
#include <QDebug>
Inge Wallin's avatar
Inge Wallin committed
20
#include <QStandardItemModel>
Amarvir Singh's avatar
Amarvir Singh committed
21

22
//#include <KMimeType>
23
#include <KActionCollection>
24

25
#include "../utils.h"
26
#include "buttondelegate.h"
27
#include "parleymainwindow.h"
28
#include "parleydocument.h"
29 30
#include "practice/themedbackgroundrenderer.h"
#include "practice/imagewidget.h"
Amarvir Singh's avatar
Amarvir Singh committed
31 32
#include "statistics/statisticsmainwindow.h"
#include "statistics/statisticsmodel.h"
33

34
#include "collection.h"
Inge Wallin's avatar
Inge Wallin committed
35
#include "collectionwidget.h"
36
#include "gradereferencewidget.h"
Amarvir Singh's avatar
Amarvir Singh committed
37

38

39
// ================================================================
40
//                         class Dashboard
41 42


Inge Wallin's avatar
Inge Wallin committed
43
int ROWSIZE = 4;      // Number of collection widgets (+ 1 initial spacerItem) per row
44

45
Dashboard::Dashboard(ParleyMainWindow *parent)
46 47
    : KXmlGuiWindow(parent)
    , m_mainWindow(parent)
Daniel Laidig's avatar
Daniel Laidig committed
48
{
49
    // KXmlGui
50 51
    setXMLFile(QStringLiteral("dashboardui.rc"));
    setObjectName(QStringLiteral("Dashboard"));
52

53
    m_widget = new Practice::ImageWidget(this);
54

55 56 57 58
    m_widget->setScalingEnabled(false, false);
    m_widget->setKeepAspectRatio(Qt::IgnoreAspectRatio);
    m_widget->setFadingEnabled(false);

59 60
    m_ui = new Ui::Dashboard();
    m_ui->setupUi(m_widget);
61
    setCentralWidget(m_widget);
Amarvir Singh's avatar
Amarvir Singh committed
62

63
    QFont font = m_ui->recentLabel->font();
64
    font.setBold(true);
65 66
    m_ui->recentLabel->setFont(font);
    font = m_ui->completedLabel->font();
Amarvir Singh's avatar
Amarvir Singh committed
67
    font.setBold(true);
68
    m_ui->completedLabel->setFont(font);
69

70 71 72
    m_ui->newButton->setIcon(QIcon::fromTheme(QStringLiteral("document-new")));
    m_ui->openButton->setIcon(QIcon::fromTheme(QStringLiteral("document-open")));
    m_ui->ghnsButton->setIcon(QIcon::fromTheme(QStringLiteral("get-hot-new-stuff")));
73

Amarvir Singh's avatar
Amarvir Singh committed
74
    GradeReferenceWidget *gradeReferenceWidget = new GradeReferenceWidget();
Inge Wallin's avatar
Inge Wallin committed
75
    gradeReferenceWidget->setMinimumSize(m_widget->width(), 50);
76
    m_ui->gridLayout->addWidget(gradeReferenceWidget, 1, 0, 1, ROWSIZE, Qt::AlignCenter);
77

Amarvir Singh's avatar
Amarvir Singh committed
78 79 80
    m_subGridLayout = new QGridLayout();
    m_subGridLayout->setHorizontalSpacing(50);
    m_subGridLayout->setVerticalSpacing(30);
81 82
    m_ui->gridLayout_2->addLayout(m_subGridLayout, 2, 0, 1, 1);

Inge Wallin's avatar
Inge Wallin committed
83

Amarvir Singh's avatar
Amarvir Singh committed
84 85 86
    m_completedGridLayout = new QGridLayout();
    m_completedGridLayout->setHorizontalSpacing(50);
    m_completedGridLayout->setVerticalSpacing(30);
87
    m_ui->gridLayout_2->addLayout(m_completedGridLayout, 6, 0, 1, 1);
88

89
    populateMap();
Amarvir Singh's avatar
Amarvir Singh committed
90
    populateGrid();
91

92
    // Signals from the main buttons.
93
    ParleyDocument* doc = m_mainWindow->parleyDocument();
94 95 96
    connect(m_ui->newButton,  &QAbstractButton::clicked, m_mainWindow, &ParleyMainWindow::slotFileNew);
    connect(m_ui->openButton, &QAbstractButton::clicked, doc, &ParleyDocument::slotFileOpen);
    connect(m_ui->ghnsButton, &QAbstractButton::clicked, doc, &ParleyDocument::slotGHNS);
97

98
    KConfigGroup cfg(KSharedConfig::openConfig(QStringLiteral("parleyrc")), objectName());
99 100
    applyMainWindowSettings(cfg);

101
    m_themedBackgroundRenderer = new Practice::ThemedBackgroundRenderer(this, QStringLiteral("startpagethemecache.bin"));
102

103
    // Set theme and prepare for future theme changes.
104
    connect(Prefs::self(), &KCoreConfigSkeleton::configChanged, this, &Dashboard::setTheme);
105 106
    setTheme();

Laurent Montel's avatar
Laurent Montel committed
107 108
    connect(m_themedBackgroundRenderer, &Practice::ThemedBackgroundRenderer::backgroundChanged,
            this,                       &Dashboard::backgroundChanged);
109
    connect(m_widget, &Practice::ImageWidget::sizeChanged, this, &Dashboard::updateBackground);
Amarvir Singh's avatar
Amarvir Singh committed
110

111
    QAction *updateAction = new QAction(this);
112 113
    updateAction->connect(updateAction, &QAction::triggered, this, &Dashboard::updateWidgets);
    actionCollection()->addAction(QStringLiteral("update_dashboard"), updateAction);
Laurent Montel's avatar
Laurent Montel committed
114
    actionCollection()->setDefaultShortcut(updateAction, QKeySequence(Qt::Key_F5));
115 116
}

117
Dashboard::~Dashboard()
118
{
119
    KConfigGroup cfg(KSharedConfig::openConfig(QStringLiteral("parleyrc")), objectName());
120
    saveMainWindowSettings(cfg);
121 122
}

Inge Wallin's avatar
Inge Wallin committed
123

124
void Dashboard::clearGrid()
125
{
Inge Wallin's avatar
Inge Wallin committed
126
   remove(m_subGridLayout,
127 128
          m_subGridLayout->rowCount() - 1, m_subGridLayout->columnCount() - 1,
          true);
Inge Wallin's avatar
Inge Wallin committed
129
   remove(m_completedGridLayout,
130 131
          m_completedGridLayout->rowCount() - 1, m_completedGridLayout->columnCount() - 1,
          true);
132 133 134 135 136 137 138 139
}

/**
 * Helper function. Removes all layout items within the given @a layout
 * which either span the given @a row or @a column. If @a deleteWidgets
 * is true, all concerned child widgets become not only removed from the
 * layout, but also deleted.
 */
140
void Dashboard::remove(QGridLayout *layout, int row, int column, bool deleteWidgets)
141
{
142 143 144 145
    // We avoid usage of QGridLayout::itemAtPosition() here to improve performance.
    for (int i = layout->count() - 1; i >= 0; i--) {
        int r, c, rs, cs;
        layout->getItemPosition(i, &r, &c, &rs, &cs);
146
        if ((r + rs - 1 <= row) || (c + cs - 1 <= column)) {
147 148 149 150 151 152 153 154 155 156 157 158 159
            // This layout item is subject to deletion.
            QLayoutItem *item = layout->takeAt(i);
            if (deleteWidgets) {
                deleteChildWidgets(item);
            }
            delete item;
        }
    }
}

/**
 * Helper function. Deletes all child widgets of the given layout @a item.
 */
160
void Dashboard::deleteChildWidgets(QLayoutItem *item)
Inge Wallin's avatar
Inge Wallin committed
161
{
162 163 164 165 166 167 168 169 170
    if (item->layout()) {
        // Process all child items recursively.
        for (int i = 0; i < item->layout()->count(); i++) {
            deleteChildWidgets(item->layout()->itemAt(i));
        }
    }
    delete item->widget();
}

171
void Dashboard::populateMap()
172
{
173
    KConfig parleyConfig(QStringLiteral("parleyrc"));
174 175
    KConfigGroup recentFilesGroup(&parleyConfig, "Recent Files");
    for (int i = recentFilesGroup.keyList().count() / 2; i > 0 ; i--) {
176 177
        QString urlString = recentFilesGroup.readPathEntry("File" + QString::number(i), QString());
        QString nameString = recentFilesGroup.readEntry("Name" + QString::number(i), QString());
178
        m_recentFilesMap.insert(urlString, nameString);
179 180 181
    }
}

182
void Dashboard::populateGrid()
183 184
{
    int j = 0, k = 0, jc = 0, kc = 0;
185

186
    QMapIterator<QString, QString> it(m_recentFilesMap);
Inge Wallin's avatar
Inge Wallin committed
187 188
    while (it.hasNext()) {
        it.next();
189 190 191
        QString urlString   = it.key();
        QString titleString = it.value();

192 193
        QUrl  url(QUrl::fromLocalFile(urlString));
        Collection *collection = new Collection(&url, this);
Inge Wallin's avatar
Inge Wallin committed
194

195 196
        WordCount dueWords;
	int percentageCompleted = dueWords.percentageCompleted();
197

198
        m_urlArray[k] = url;
199
        if (percentageCompleted != 100) {
Inge Wallin's avatar
Inge Wallin committed
200
            if (j % ROWSIZE == 0) {
201
                m_subGridLayout->addItem(new QSpacerItem(50, 1), j / ROWSIZE, 0);
Amarvir Singh's avatar
Amarvir Singh committed
202 203 204 205
                j++;
            }
        }
        else {
Inge Wallin's avatar
Inge Wallin committed
206 207
            if (jc % ROWSIZE == 0) {
                m_completedGridLayout->addItem(new QSpacerItem(50,1), jc / ROWSIZE, 0);
Amarvir Singh's avatar
Amarvir Singh committed
208 209 210
                jc++;
            }
        }
Inge Wallin's avatar
Inge Wallin committed
211

212
        CollectionWidget* backWidget = new CollectionWidget(collection, &dueWords, this);
213
        m_collectionWidgets.append(backWidget);
214
        if (percentageCompleted != 100) {
Inge Wallin's avatar
Inge Wallin committed
215
                backWidget->setFixedSize(COLLWIDTH, COLLHEIGHT1);
216
                backWidget->setMinimumSize(COLLWIDTH, COLLHEIGHT1);
Inge Wallin's avatar
Inge Wallin committed
217
                m_subGridLayout->addWidget(backWidget, j / ROWSIZE, j % ROWSIZE);
Amarvir Singh's avatar
Amarvir Singh committed
218 219
        }
        else {
Inge Wallin's avatar
Inge Wallin committed
220
                backWidget->setFixedSize(COLLWIDTH, COLLHEIGHT2);
221
                backWidget->setMinimumSize(COLLWIDTH, COLLHEIGHT2);
Inge Wallin's avatar
Inge Wallin committed
222
                m_completedGridLayout->addWidget(backWidget, jc / ROWSIZE, jc % ROWSIZE);
Amarvir Singh's avatar
Amarvir Singh committed
223
        }
Inge Wallin's avatar
Inge Wallin committed
224

225 226 227 228
        connect(backWidget, &CollectionWidget::practiceButtonClicked,
                this, [=] {slotPracticeButtonClicked(urlString);});
        connect(backWidget, &CollectionWidget::removeButtonClicked,
                this, [=] {slotRemoveButtonClicked(urlString);});
Inge Wallin's avatar
Inge Wallin committed
229

230
        if (percentageCompleted != 100) {
Amarvir Singh's avatar
Amarvir Singh committed
231 232 233 234 235 236
            j++;
        }
        else {
            jc++;
            kc++;
        }
237

Amarvir Singh's avatar
Amarvir Singh committed
238
        k++;
239
    }
Inge Wallin's avatar
Inge Wallin committed
240

Inge Wallin's avatar
Inge Wallin committed
241
    m_count = k;
242
    m_completedGridLayout->addItem(new QSpacerItem(50, 1,
243 244 245
                                                   QSizePolicy::Expanding, QSizePolicy::Fixed),
                                   m_completedGridLayout->rowCount() - 1,
                                   m_completedGridLayout->columnCount());
Inge Wallin's avatar
Inge Wallin committed
246
    m_subGridLayout->addItem(new QSpacerItem(50,1,QSizePolicy::Expanding, QSizePolicy::Fixed),
247
                             m_subGridLayout->rowCount() - 1, m_subGridLayout->columnCount());
Inge Wallin's avatar
Inge Wallin committed
248
    if (k - kc) {
249
        m_ui->recentLabel->setText(i18n("Active Collections"));
250
    } else {
251
        m_ui->recentLabel->clear();
252
    }
Amarvir Singh's avatar
Amarvir Singh committed
253
    if (kc) {
254
        m_ui->completedLabel->setText(i18n("Completed Collections"));
Amarvir Singh's avatar
Amarvir Singh committed
255
    } else {
256
        m_ui->completedLabel->clear();
Amarvir Singh's avatar
Amarvir Singh committed
257 258 259
    }
}

Laurent Montel's avatar
Laurent Montel committed
260
void Dashboard::statisticsHandler(const QUrl &url)
Inge Wallin's avatar
Inge Wallin committed
261 262 263 264
{
#if 1
    Q_UNUSED(url);
#else
Amarvir Singh's avatar
Amarvir Singh committed
265 266 267
    if (!m_mainWindow->parleyDocument()->open(url)) {
        return;
    }
Inge Wallin's avatar
Inge Wallin committed
268 269 270 271

    // Find due words. TODO find a better way.
    m_mainWindow->m_sessionManager.setDocument(m_mainWindow->parleyDocument()->document());

Amarvir Singh's avatar
Amarvir Singh committed
272 273
    qDebug()<<"Session Manager, allEntryCount="<<m_mainWindow->m_sessionManager.allDueEntryCount();
    statisticsWidget->setDocument(m_mainWindow->parleyDocument()->document());
Inge Wallin's avatar
Inge Wallin committed
274 275

    // Find the percentage completion, to categorize as active or completed collection.
Amarvir Singh's avatar
Amarvir Singh committed
276
    QModelIndex index = statisticsWidget->statisticsModel()->index(0, 2, QModelIndex());
Inge Wallin's avatar
Inge Wallin committed
277 278
    qDebug() << "Percentage:" << index.data(StatisticsModel::TotalPercent).toInt();
#endif
Daniel Laidig's avatar
Daniel Laidig committed
279 280
}

281
void Dashboard::slotOpenUrl(const QUrl& url)
282
{
283
    if (!m_mainWindow->parleyDocument()->open(url)) {
284 285
        return;
    }
286
    m_mainWindow->showEditor();
287 288
}

289
void Dashboard::slotPracticeButtonClicked(const QString& urlString)
290
{
291
    //qDebug() << urlString;
292
    QUrl url( QUrl::fromLocalFile(urlString) );
293
    m_openUrl = url;
294
    QTimer::singleShot(0, this, &Dashboard::slotDoubleClickOpen);
295 296
}

297
void Dashboard::slotRemoveButtonClicked(const QString& urlString)
298
{
299
    qDebug() << urlString;
300

301
    QMessageBox::StandardButton reply;
Inge Wallin's avatar
Inge Wallin committed
302
    reply = QMessageBox::question(this, i18n("Remove"),
303 304
                                  i18n("Are you sure you want to remove this collection?"),
                                  QMessageBox::Yes | QMessageBox::No);
305
    if (reply == QMessageBox::Yes) {
306
        m_recentFilesMap.remove(urlString);
307
        m_mainWindow->removeRecentFile(QUrl::fromLocalFile(urlString ));
308 309 310 311 312
        clearGrid();
        populateGrid();
    }
}

313
void Dashboard::slotDoubleClickOpen()
314
{
315
    slotPracticeUrl(m_openUrl);
316 317
}

318
void Dashboard::slotPracticeUrl(const QUrl & url)
319
{
320
    if (!m_mainWindow->parleyDocument()->open(url)) {
321 322
        return;
    }
323 324 325 326

    // This used to go to the practice configuration but both I and
    //some users wanted to go directly to the practice so I'm testing
    //out this for a while.
327
    m_mainWindow->showPracticeConfiguration();
328
    //m_mainWindow->showPractice();
329 330
}

331
void Dashboard::backgroundChanged(const QPixmap &pixmap)
332 333 334 335
{
    m_widget->setPixmap(pixmap);
}

336
void Dashboard::setTheme()
337
{
338 339 340 341
    m_themedBackgroundRenderer->setTheme(Prefs::theme());
    updateFontColors();
    updateBackground();
    m_widget->setContentsMargins(m_themedBackgroundRenderer->contentMargins());
342 343
}

344 345 346
void Dashboard::updateWidgets()
{
    foreach (CollectionWidget *cw, m_collectionWidgets) {
347
        cw->updateDue();
348 349
    }
}
350
void Dashboard::updateFontColors()
351 352
{
    QPalette p(QApplication::palette());
353
    QColor c = m_themedBackgroundRenderer->fontColor(QStringLiteral("Start"), p.color(QPalette::Active, QPalette::WindowText));
354 355 356
    p.setColor(QPalette::Base, Qt::transparent);
    p.setColor(QPalette::Text, c);
    p.setColor(QPalette::WindowText, c);
357
    m_widget->setPalette(p);
358 359
}

360
void Dashboard::updateBackground()
361
{
362
    m_themedBackgroundRenderer->clearRects();
363
    m_themedBackgroundRenderer->addRect(QStringLiteral("startbackground"), QRect(QPoint(), m_widget->size()));
364 365 366 367 368
    QPixmap pixmap = m_themedBackgroundRenderer->getScaledBackground();
    if (!pixmap.isNull()) {
        m_widget->setPixmap(pixmap);
    }
    m_themedBackgroundRenderer->updateBackground();
369
}