cantor.cpp 26.8 KB
Newer Older
1
/*
Alexander Rieder's avatar
Alexander Rieder committed
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    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.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA  02110-1301, USA.

    ---
    Copyright (C) 2009 Alexander Rieder <alexanderrieder@gmail.com>
19
 */
Alexander Rieder's avatar
Alexander Rieder committed
20
#include "cantor.h"
21

22
#include <KActionCollection>
23
24
#include <KConfigDialog>
#include <KConfigGroup>
25
#include <KConfig>
26
#include <KMessageBox>
27
#include <KShortcutsDialog>
28
29
#include <KStandardAction>
#include <KNS3/DownloadDialog>
30
#include <KParts/ReadWritePart>
31
#include <KRecentFilesAction>
32

33
#include <QApplication>
34
#include <QCloseEvent>
35
36
#include <QDebug>
#include <QDockWidget>
37
#include <QDir>
38
#include <QFileDialog>
39
#include <QPushButton>
40
#include <QRegularExpression>
41
#include <QGraphicsView>
42
43

#include "lib/backend.h"
44
45
#include "lib/panelpluginhandler.h"
#include "lib/panelplugin.h"
46
#include "lib/worksheetaccess.h"
47
48
49

#include "settings.h"
#include "ui_settings.h"
50
#include "backendchoosedialog.h"
51

52
CantorShell::CantorShell() : KParts::MainWindow(), m_part(nullptr)
53
54
{
    // set the shell's ui resource file
55
    setXMLFile(QLatin1String("cantor_shell.rc"));
56
57
58
59

    // then, setup our actions
    setupActions();

60
    createGUI(nullptr);
61

Filipe Saraiva's avatar
Filipe Saraiva committed
62
    m_tabWidget=new QTabWidget(this);
63
    m_tabWidget->setTabsClosable(true);
64
65
    m_tabWidget->setMovable(true);
    m_tabWidget->setDocumentMode(true);
66
67
68
    setCentralWidget(m_tabWidget);

    connect(m_tabWidget, SIGNAL(currentChanged(int)), this, SLOT(activateWorksheet(int)));
69
    connect(m_tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
70
71
72
73
74

    // apply the saved mainwindow settings, if any, and ask the mainwindow
    // to automatically save settings if changed: window size, toolbar
    // position, icon size, etc.
    setAutoSaveSettings();
75
76

    setDockOptions(QMainWindow::AnimatedDocks|QMainWindow::AllowTabbedDocks|QMainWindow::VerticalTabs);
77
78

    updateNewSubmenu();
79
80
}

81
82
83
84
CantorShell::~CantorShell()
{
    if (m_recentProjectsAction)
        m_recentProjectsAction->saveEntries(KSharedConfig::openConfig()->group(QLatin1String("Recent Files")));
85
86
87
88
89
90
91
92
93
94
95

    if (!m_newBackendActions.isEmpty())
    {
        unplugActionList(QLatin1String("new_worksheet_with_backend_list"));
        qDeleteAll(m_newBackendActions);
        m_newBackendActions.clear();
    }

    unplugActionList(QLatin1String("view_show_panel_list"));
    qDeleteAll(m_panels);
    m_panels.clear();
96
97
}

98
void CantorShell::load(const QUrl &url)
99
{
100
101
102
103
104
105
106
107
108
    // If the url already opened, then don't open the url in another tab, but
    // just activate the already existed tab
    for (int i = 0; i < m_parts.size(); i++)
    {
        KParts::ReadOnlyPart* part = m_parts[i];
        if (part && part->url() == url)
        {
            if (m_tabWidget->currentIndex() != i)
                activateWorksheet(i);
109
110
            else
                KMessageBox::information(this, i18n("The file %1 is already opened.", QFileInfo(url.toLocalFile()).fileName()), i18n("Open file"));
111
112
113
114
            return;
        }
    }

Alexander Rieder's avatar
Alexander Rieder committed
115
    if (!m_part||!m_part->url().isEmpty() || m_part->isModified() )
116
    {
117
        addWorksheet(QString());
118
119
        m_tabWidget->setCurrentIndex(m_parts.size()-1);
    }
120
121
    if (!m_part->openUrl( url ))
        closeTab(m_tabWidget->currentIndex());
122
123
    if (m_recentProjectsAction)
        m_recentProjectsAction->addUrl(url);
124
125

    updateWindowTitle(m_part->url().fileName());
126
127
}

Alexander Rieder's avatar
Alexander Rieder committed
128
void CantorShell::setupActions()
129
{
130
    QAction* openNew = KStandardAction::openNew(this, SLOT(fileNew()), actionCollection());
131
    openNew->setPriority(QAction::LowPriority);
132
    QAction* open = KStandardAction::open(this, SLOT(fileOpen()), actionCollection());
133
    open->setPriority(QAction::LowPriority);
134
135
136
    m_recentProjectsAction = KStandardAction::openRecent(this, &CantorShell::load, actionCollection());
    m_recentProjectsAction->setPriority(QAction::LowPriority);
    m_recentProjectsAction->loadEntries(KSharedConfig::openConfig()->group(QLatin1String("Recent Files")));
137

138
139
    KStandardAction::close (this,  SLOT(closeTab()),  actionCollection());

140
141
142
143
144
    KStandardAction::quit(qApp, SLOT(closeAllWindows()), actionCollection());

    createStandardStatusBarAction();
    //setStandardToolBarMenuEnabled(true);

145
146
    KStandardAction::keyBindings(this, SLOT(optionsConfigureKeys()), actionCollection());
    KStandardAction::configureToolbars(this, SLOT(configureToolbars()), actionCollection());
147
148

    KStandardAction::preferences(this, SLOT(showSettings()), actionCollection());
149

150
151
152
    QAction * downloadExamples = new QAction(i18n("Download Example Worksheets"), actionCollection());
    downloadExamples->setIcon(QIcon::fromTheme(QLatin1String("get-hot-new-stuff")));
    actionCollection()->addAction(QLatin1String("file_example_download"),  downloadExamples);
153
    connect(downloadExamples, SIGNAL(triggered()), this,  SLOT(downloadExamples()));
154

155
156
157
    QAction * openExample =new QAction(i18n("&Open Example"), actionCollection());
    openExample->setIcon(QIcon::fromTheme(QLatin1String("document-open")));
    actionCollection()->addAction(QLatin1String("file_example_open"), openExample);
158
    connect(openExample, SIGNAL(triggered()), this, SLOT(openExample()));
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182

    QAction* toPreviousTab = new QAction(i18n("Go to previous worksheet"), actionCollection());
    actionCollection()->addAction(QLatin1String("go_to_previous_tab"), toPreviousTab);
    actionCollection()->setDefaultShortcut(toPreviousTab, Qt::CTRL+Qt::Key_PageDown);
    connect(toPreviousTab, &QAction::triggered, toPreviousTab, [this](){
        const int index = m_tabWidget->currentIndex()-1;
        if (index >= 0)
            m_tabWidget->setCurrentIndex(index);
        else
            m_tabWidget->setCurrentIndex(m_tabWidget->count()-1);
    });
    addAction(toPreviousTab);

    QAction* toNextTab = new QAction(i18n("Go to next worksheet"), actionCollection());
    actionCollection()->addAction(QLatin1String("go_to_next_tab"), toNextTab);
    actionCollection()->setDefaultShortcut(toNextTab, Qt::CTRL+Qt::Key_PageUp);
    connect(toNextTab, &QAction::triggered, toNextTab, [this](){
        const int index = m_tabWidget->currentIndex()+1;
        if (index < m_tabWidget->count())
            m_tabWidget->setCurrentIndex(index);
        else
            m_tabWidget->setCurrentIndex(0);
    });
    addAction(toNextTab);
183
184
}

Alexander Rieder's avatar
Alexander Rieder committed
185
void CantorShell::saveProperties(KConfigGroup & /*config*/)
186
187
188
189
190
191
{
    // the 'config' object points to the session managed
    // config file.  anything you write here will be available
    // later when this app is restored
}

Alexander Rieder's avatar
Alexander Rieder committed
192
void CantorShell::readProperties(const KConfigGroup & /*config*/)
193
194
195
196
197
198
199
{
    // the 'config' object points to the session managed
    // config file.  this function is automatically called whenever
    // the app is being restored.  read in here whatever you wrote
    // in 'saveProperties'
}

200
201
202
203
204
/*!
 * called when one of the "new backend" action or the "New" action are called
 * adds a new worksheet with the backend assossiated with the called action
 * or opens the "Choose Backend" dialog, respectively.
 */
Alexander Rieder's avatar
Alexander Rieder committed
205
void CantorShell::fileNew()
206
{
207
208
209
    QAction* a = static_cast<QAction*>(sender());
    const QString& backendName = a->data().toString();
    if (!backendName.isEmpty())
210
    {
211
212
        addWorksheet(backendName);
        return;
213
    }
214
215

    //"New" action was called -> open the "Choose Backend" dialog.
216
    addWorksheet();
217
218
}

Alexander Rieder's avatar
Alexander Rieder committed
219
void CantorShell::optionsConfigureKeys()
220
{
221
222
    KShortcutsDialog dlg( KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsDisallowed, this );
    dlg.addCollection( actionCollection(), i18n("Cantor") );
223
224
    if (m_part)
        dlg.addCollection( m_part->actionCollection(), i18n("Cantor") );
225
    dlg.configure( true );
226
227
}

Alexander Rieder's avatar
Alexander Rieder committed
228
void CantorShell::fileOpen()
229
230
231
232
{
    // this slot is called whenever the File->Open menu is selected,
    // the Open shortcut is pressed (usually CTRL+O) or the Open toolbar
    // button is clicked
Filipe Saraiva's avatar
Filipe Saraiva committed
233
234
    static const QString& filter = i18n("All supported files (*.cws *ipynb);;Cantor Worksheet (*.cws);;Jupyter Notebook (*.ipynb)");
    QUrl url = QFileDialog::getOpenFileUrl(this, i18n("Open file"), QUrl(), filter, &m_previousFilter);
235
236
237

    if (url.isEmpty() == false)
    {
238
        // About this function, the style guide
239
240
241
242
243
244
245
246
247
248
        // says that it should open a new window if the document is _not_
        // in its initial state.  This is what we do here..
        /*if ( m_part->url().isEmpty() && ! m_part->isModified() )
        {
            // we open the file in this window...
            load( url );
        }
        else
        {
            // we open the file in a new window...
Alexander Rieder's avatar
Alexander Rieder committed
249
            CantorShell* newWin = new CantorShell;
250
251
252
253
254
255
256
            newWin->load( url );
            newWin->show();
            }*/
        load( url );
    }
}

Alexander Rieder's avatar
Alexander Rieder committed
257
void CantorShell::addWorksheet()
258
{
259
260
261
262
263
264
265
266
267
268
269
    bool hasBackend = false;
    for (auto* b : Cantor::Backend::availableBackends())
    {
        if(b->isEnabled())
        {
            hasBackend = true;
            break;
        }
    }

    if(hasBackend) //There is no point in asking for the backend, if no one is available
270
    {
271
272
        QString backend = Settings::self()->defaultBackend();
        if (backend.isEmpty())
273
        {
274
275
276
277
            QPointer<BackendChooseDialog> dlg=new BackendChooseDialog(this);
            if(dlg->exec())
            {
                backend = dlg->backendName();
278
                addWorksheet(backend);
279
280
281
            }

            delete dlg;
282
        }
283
284
285
286
        else
        {
            addWorksheet(backend);
        }
287

288
289
    }else
    {
290
        QTextBrowser *browser=new QTextBrowser(this);
291
        QString backendList=QLatin1String("<ul>");
Andrew Coles's avatar
Andrew Coles committed
292
        int backendListSize = 0;
293
294
        foreach(Cantor::Backend* b, Cantor::Backend::availableBackends())
        {
Yuri Chornoivan's avatar
Yuri Chornoivan committed
295
            if(!b->requirementsFullfilled()) //It's disabled because of missing dependencies, not because of some other reason(like eg. nullbackend)
Andrew Coles's avatar
Andrew Coles committed
296
            {
297
                backendList+=QString::fromLatin1("<li>%1: <a href=\"%2\">%2</a></li>").arg(b->name(), b->url());
Andrew Coles's avatar
Andrew Coles committed
298
299
                ++backendListSize;
            }
300
        }
Andrew Coles's avatar
Andrew Coles committed
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
        browser->setHtml(i18np("<h1>No Backend Found</h1>\n"             \
                               "<div>You could try:\n"                   \
                               "  <ul>"                                  \
                               "    <li>Changing the settings in the config dialog;</li>" \
                               "    <li>Installing packages for the following program:</li>" \
                               "     %2 "                                \
                               "  </ul> "                                 \
                               "</div> "
                              , "<h1>No Backend Found</h1>\n"             \
                               "<div>You could try:\n"                   \
                               "  <ul>"                                  \
                               "    <li>Changing the settings in the config dialog;</li>" \
                               "    <li>Installing packages for one of the following programs:</li>" \
                               "     %2 "                                \
                               "  </ul> "                                 \
                               "</div> "
                              , backendListSize, backendList
                              ));
319

320
        browser->setObjectName(QLatin1String("ErrorMessage"));
321
322
        m_tabWidget->addTab(browser, i18n("Error"));
    }
323
324
}

Alexander Rieder's avatar
Alexander Rieder committed
325
void CantorShell::addWorksheet(const QString& backendName)
326
327
328
329
330
331
{
    static int sessionCount=1;

    // this routine will find and load our Part.  it finds the Part by
    // name which is a bad idea usually.. but it's alright in this
    // case since our Part is made for this Shell
332
333
    KPluginLoader loader(QLatin1String("cantorpart"));
    KPluginFactory* factory = loader.factory();
334
335
    if (factory)
    {
336
        Cantor::Backend* backend = nullptr;
337
        if (!backendName.isEmpty())
338
        {
339
            backend = Cantor::Backend::getBackend(backendName);
340
            if (!backend)
341
            {
342
343
                KMessageBox::error(this, i18n("Backend %1 is not installed", backendName), i18n("Cantor"));
                return;
344
            }
345
            else
346
            {
347
348
349
350
351
                if (!backend->isEnabled())
                {
                    KMessageBox::error(this, i18n("%1 backend installed, but inactive. Please check installation and Cantor settings", backendName), i18n("Cantor"));
                    return;
                }
352
            }
353
        }
354
355
356
357
358
359
360

        // now that the Part is loaded, we cast it to a Part to get our hands on it
        KParts::ReadWritePart* part = factory->create<KParts::ReadWritePart>(m_tabWidget, QVariantList()<<backendName);
        if (part)
        {
            connect(part, SIGNAL(setCaption(QString,QIcon)), this, SLOT(setTabCaption(QString,QIcon)));
            connect(part, SIGNAL(worksheetSave(QUrl)), this, SLOT(onWorksheetSave(QUrl)));
361
            connect(part, SIGNAL(requestOpenWorksheet(QUrl)), this, SLOT(load(QUrl)));
362
            m_parts.append(part);
363
364
365
366
367
368
369
            if (backend) // If backend empty (loading worksheet from file), then we connect to signal and wait
                m_parts2Backends[part] = backend->id();
            else
            {
                m_parts2Backends[part] = QString();
                connect(part, SIGNAL(setBackendName(QString)), this, SLOT(updateBackendForPart(setBackendName)));
            }
370
371
372
373
374
            int tab = m_tabWidget->addTab(part->widget(), i18n("Session %1", sessionCount++));
            m_tabWidget->setCurrentIndex(tab);
            // Setting focus on worksheet view, because Qt clear focus of added widget inside addTab
            // This fix https://bugs.kde.org/show_bug.cgi?id=395976
            part->widget()->findChild<QGraphicsView*>()->setFocus();
375
376
377

            // Force run updateCaption for getting proper backend icon
            QMetaObject::invokeMethod(part, "updateCaption");
378
        }
379
        else
380
381
382
        {
            qDebug()<<"error creating part ";
        }
383
384
385
386
387
    }
    else
    {
        // if we couldn't find our Part, we exit since the Shell by
        // itself can't do anything useful
388
        KMessageBox::error(this, i18n("Failed to find the Cantor Part with error %1", loader.errorString()));
389
390
391
392
393
394
395
396
        qApp->quit();
        // we return here, cause qApp->quit() only means "exit the
        // next time we enter the event loop...
        return;
    }

}

Alexander Rieder's avatar
Alexander Rieder committed
397
void CantorShell::activateWorksheet(int index)
398
{
399
    QObject* pluginHandler=m_part->findChild<QObject*>(QLatin1String("PanelPluginHandler"));
400
401
402
403
404
405
406
407
408
409
410
411
412
413
    if (pluginHandler)
        disconnect(pluginHandler,SIGNAL(pluginsChanged()), this, SLOT(updatePanel()));

    // Save part state before change worksheet
    if (m_part)
    {
        QStringList visiblePanelNames;
        foreach (QDockWidget* doc, m_panels)
        {
            if (doc->widget() && doc->widget()->isVisible())
                visiblePanelNames << doc->objectName();
        }
        m_pluginsVisibility[m_part] = visiblePanelNames;
    }
414

415
    m_part=findPart(m_tabWidget->widget(index));
416
    if(m_part)
417
    {
418
        createGUI(m_part);
419

420
        updateWindowTitle(m_part->url().fileName());
421
        QObject* pluginHandler=m_part->findChild<QObject*>(QLatin1String("PanelPluginHandler"));
422
423
424
        connect(pluginHandler, SIGNAL(pluginsChanged()), this, SLOT(updatePanel()));
        updatePanel();
    }
425
    else
426
        qDebug()<<"selected part doesn't exist";
427
428

    m_tabWidget->setCurrentIndex(index);
429
430
}

431
void CantorShell::setTabCaption(const QString& caption, const QIcon& icon)
432
433
{
    KParts::ReadWritePart* part=dynamic_cast<KParts::ReadWritePart*>(sender());
434
435
    if (part)
    {
436
437
        if (!caption.isEmpty())
            m_tabWidget->setTabText(m_tabWidget->indexOf(part->widget()), caption);
438
439
        m_tabWidget->setTabIcon(m_tabWidget->indexOf(part->widget()), icon);
    }
440
441
}

442
443
444
445
446
447
void CantorShell::updateWindowTitle(const QString& fileName)
{
    QFileInfo info(fileName);
    setWindowTitle(info.baseName());
}

448
void CantorShell::closeTab(int index)
449
{
450
    if (index != -1)
451
    {
452
453
454
455
456
457
458
459
460
461
462
463
        QWidget* widget = m_tabWidget->widget(index);
        if (widget)
        {
            KParts::ReadWritePart* part= findPart(widget);
            if (part && !reallyCloseThisPart(part))
                return;
        }
    }
    else
    {
        if (!reallyClose(false))
            return;
464
    }
465
466
467

    QWidget* widget = nullptr;
    if (index >= 0)
468
    {
469
470
471
472
473
474
475
476
477
478
479
        widget = m_tabWidget->widget(index);
    }
    else if (m_part)
    {
        widget = m_part->widget();
    }

    if (!widget)
    {
        qWarning() << "Could not find widget by tab index" << index;
        return;
480
    }
481

482

483
484
    m_tabWidget->removeTab(index);

485
    if(widget->objectName()==QLatin1String("ErrorMessage"))
486
487
488
489
490
491
492
    {
        widget->deleteLater();
    }else
    {
        KParts::ReadWritePart* part= findPart(widget);
        if(part)
        {
493
494
            saveDockPanelsState(part);

495
            m_parts.removeAll(part);
496
            m_pluginsVisibility.remove(part);
497
            m_parts2Backends.remove(part);
498
            delete part;
499
500
        }
    }
501
502
503

    if (m_tabWidget->count() == 0)
        setCaption(QString());
504
    updatePanel();
505
506
}

507
508
509
bool CantorShell::reallyClose(bool checkAllParts) {
    if(checkAllParts && m_parts.count() > 1) {
        bool modified = false;
510
        foreach( KParts::ReadWritePart* const part, m_parts)
511
512
513
514
515
516
517
518
        {
            if(part->isModified()) {
                modified = true;
                break;
            }
        }
        if(!modified) return true;
        int want_save = KMessageBox::warningYesNo( this,
519
            i18n("Multiple unsaved Worksheets are opened. Do you want to close them?"),
520
521
522
523
524
525
526
527
            i18n("Close Cantor"));
        switch (want_save) {
            case KMessageBox::Yes:
                return true;
            case KMessageBox::No:
                return false;
        }
    }
528
529
530
531
532
533
534

    return reallyCloseThisPart(m_part);
}

bool CantorShell::reallyCloseThisPart(KParts::ReadWritePart* part)
{
     if (part && part->isModified() ) {
535
536
537
538
539
        int want_save = KMessageBox::warningYesNoCancel( this,
            i18n("The current project has been modified. Do you want to save it?"),
            i18n("Save Project"));
        switch (want_save) {
            case KMessageBox::Yes:
540
541
                part->save();
                if(part->waitSaveComplete()) {
542
543
                    return true;
                } else {
544
                    part->setModified(true);
545
546
547
548
549
550
551
552
553
554
555
                    return false;
                }
            case KMessageBox::Cancel:
                return false;
            case KMessageBox::No:
                return true;
        }
    }
    return true;
}

556

557
558
559
560
void CantorShell::closeEvent(QCloseEvent* event) {
    if(!reallyClose()) {
        event->ignore();
    } else {
561
562
563
        for (KParts::ReadWritePart* part : m_parts)
            saveDockPanelsState(part);

564
565
566
567
        KParts::MainWindow::closeEvent(event);
    }
}

Alexander Rieder's avatar
Alexander Rieder committed
568
void CantorShell::showSettings()
569
{
570
    KConfigDialog *dialog = new KConfigDialog(this,  QLatin1String("settings"), Settings::self());
571
572
573
    QWidget *generalSettings = new QWidget;
    Ui::SettingsBase base;
    base.setupUi(generalSettings);
Alexander Rieder's avatar
Alexander Rieder committed
574
    base.kcfg_DefaultBackend->addItems(Cantor::Backend::listAvailableBackends());
575

576
    dialog->addPage(generalSettings, i18n("General"), QLatin1String("preferences-other"));
Alexander Rieder's avatar
Alexander Rieder committed
577
    foreach(Cantor::Backend* backend, Cantor::Backend::availableBackends())
578
579
580
581
582
583
584
    {
        if (backend->config()) //It has something to configure, so add it to the dialog
            dialog->addPage(backend->settingsWidget(dialog), backend->config(), backend->name(),  backend->icon());
    }

    dialog->show();
}
585

Alexander Rieder's avatar
Alexander Rieder committed
586
void CantorShell::downloadExamples()
587
{
588
589
590
    KNS3::DownloadDialog dialog;
    dialog.exec();
    foreach (const KNS3::Entry& e,  dialog.changedEntries())
591
    {
592
        qDebug() << "Changed Entry: " << e.name();
593
594
    }
}
595

Alexander Rieder's avatar
Alexander Rieder committed
596
void CantorShell::openExample()
597
{
598
    QString dir = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1String("/examples");
599
    if (dir.isEmpty()) return;
600
    QDir().mkpath(dir);
601
602

    QStringList files=QDir(dir).entryList(QDir::Files);
603
    QPointer<QDialog> dlg=new QDialog(this);
604
    QListWidget* list=new QListWidget(dlg);
605
606
607
    foreach(const QString& file, files)
    {
        QString name=file;
608
        name.remove(QRegularExpression(QStringLiteral("-.*\\.hotstuff-access$")));
609
610
611
        list->addItem(name);
    }

612
613
614
615
616
617
618
619
620
621
622
623
624
    QVBoxLayout *mainLayout = new QVBoxLayout;
    dlg->setLayout(mainLayout);
    mainLayout->addWidget(list);

    QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);

    mainLayout->addWidget(buttonBox);

    buttonBox->button(QDialogButtonBox::Ok)->setIcon(QApplication::style()->standardIcon(QStyle::SP_DialogOkButton));
    buttonBox->button(QDialogButtonBox::Cancel)->setIcon(QApplication::style()->standardIcon(QStyle::SP_DialogCancelButton));

    connect(buttonBox, SIGNAL(accepted()), dlg, SLOT(accept()) );
    connect(buttonBox, SIGNAL(rejected()), dlg, SLOT(reject()) );
625

626
    if (dlg->exec()==QDialog::Accepted&&list->currentRow()>=0)
627
628
    {
        const QString& selectedFile=files[list->currentRow()];
629
        QUrl url = QUrl::fromLocalFile(QDir(dir).absoluteFilePath(selectedFile));
630

631
        qDebug()<<"loading file "<<url;
632
        load(url);
633
    }
634
635

    delete dlg;
636
}
637
638
639
640
641
642
643
644

KParts::ReadWritePart* CantorShell::findPart(QWidget* widget)
{
    foreach( KParts::ReadWritePart* const part, m_parts)
    {
        if(part->widget()==widget)
            return part;
    }
645
    return nullptr;
646
}
647
648
649

void CantorShell::updatePanel()
{
Minh Ngo's avatar
Minh Ngo committed
650
    unplugActionList(QLatin1String("view_show_panel_list"));
651

652
653
654
655
    //remove all of the previous panels (but do not delete the widgets)
    foreach(QDockWidget* dock, m_panels)
    {
        QWidget* widget=dock->widget();
656
        if(widget!=nullptr)
657
658
659
660
661
662
663
664
        {
            widget->setParent(this);
            widget->hide();
        }
        dock->deleteLater();
    }
    m_panels.clear();

665
666
    QList<QAction*> panelActions;

667
    Cantor::PanelPluginHandler* handler=m_part->findChild<Cantor::PanelPluginHandler*>(QLatin1String("PanelPluginHandler"));
668
669
    if(!handler)
    {
670
        qDebug()<<"no PanelPluginHandle found for this part";
671
672
673
        return;
    }

674
    QDockWidget* last=nullptr;
675
676
677
678
679
680
681
682
683
684
685
686
    bool isNewWorksheet = !m_pluginsVisibility.contains(m_part);

    if (isNewWorksheet)
    {
        KConfigGroup panelStatusGroup(KSharedConfig::openConfig(), QLatin1String("PanelsStatus"));
        if (m_parts2Backends.contains(m_part) && panelStatusGroup.hasKey(m_parts2Backends[m_part]))
        {
            const QStringList& plugins = panelStatusGroup.readEntry(m_parts2Backends[m_part]).split(QLatin1Char('\n'));
            m_pluginsVisibility[m_part] = plugins;
            isNewWorksheet = false;
        }
    }
687
688
689
690

    QList<Cantor::PanelPlugin*> plugins=handler->plugins();
    foreach(Cantor::PanelPlugin* plugin, plugins)
    {
691
        if(plugin==nullptr)
692
        {
693
            qDebug()<<"somethings wrong";
694
695
696
            continue;
        }

697
        qDebug()<<"adding panel for "<<plugin->name();
698
699
700
701
702
703
704
        plugin->setParentWidget(this);

        QDockWidget* docker=new QDockWidget(plugin->name(), this);
        docker->setObjectName(plugin->name());
        docker->setWidget(plugin->widget());
        addDockWidget ( Qt::RightDockWidgetArea,  docker );

705
        // Set visibility for dock from saved info
706
707
708
        if (isNewWorksheet)
        {
            if (plugin->showOnStartup())
709
710
711
                docker->show();
            else
                docker->hide();
712
        }
713
        else
714
715
716
717
718
719
        {
            if (m_pluginsVisibility[m_part].contains(plugin->name()))
                docker->show();
            else
                docker->hide();
        }
720

721
        if(last!=nullptr)
722
723
724
            tabifyDockWidget(last, docker);
        last=docker;

725
        connect(plugin, &Cantor::PanelPlugin::visibilityRequested, this, &CantorShell::pluginVisibilityRequested);
726

727
        m_panels.append(docker);
728
729
730
731

        //Create the action to show/hide this panel
        panelActions<<docker->toggleViewAction();

732
    }
733

734
    plugActionList(QLatin1String("view_show_panel_list"), panelActions);
735

736
737
738
739
740
    updateNewSubmenu();
}

void CantorShell::updateNewSubmenu()
{
741
    unplugActionList(QLatin1String("new_worksheet_with_backend_list"));
742
743
744
    qDeleteAll(m_newBackendActions);
    m_newBackendActions.clear();

745
746
747
748
    foreach (Cantor::Backend* backend, Cantor::Backend::availableBackends())
    {
        if (!backend->isEnabled())
            continue;
749
        QAction * action = new QAction(QIcon::fromTheme(backend->icon()), backend->name(), nullptr);
750
751
        action->setData(backend->name());
        connect(action, SIGNAL(triggered()), this, SLOT(fileNew()));
752
        m_newBackendActions << action;
753
    }
754
    plugActionList(QLatin1String("new_worksheet_with_backend_list"), m_newBackendActions);
755
}
756
757
758
759
760
761
762
763
764
765

Cantor::WorksheetAccessInterface* CantorShell::currentWorksheetAccessInterface()
{
    Cantor::WorksheetAccessInterface* wa=m_part->findChild<Cantor::WorksheetAccessInterface*>(Cantor::WorksheetAccessInterface::Name);

    if (!wa)
        qDebug()<<"failed to access worksheet access interface for current part";

    return wa;
}
766
767
768
769
770
771
772
773
774
775
776
777
778
779

void CantorShell::pluginVisibilityRequested()
{
    Cantor::PanelPlugin* plugin = static_cast<Cantor::PanelPlugin*>(sender());
    for (QDockWidget* docker: m_panels)
    {
        if (plugin->name() == docker->windowTitle())
        {
            if (docker->isHidden())
                docker->show();
            docker->raise();
        }
    }
}
780
781
782
783
784

void CantorShell::onWorksheetSave(const QUrl& url)
{
    if (m_recentProjectsAction)
        m_recentProjectsAction->addUrl(url);
785
786

    updateWindowTitle(m_part->url().fileName());
787
}
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809

void CantorShell::saveDockPanelsState(KParts::ReadWritePart* part)
{
    if (m_parts2Backends.contains(part))
    {

        QStringList visiblePanelNames;
        if (part == m_part)
        {
            foreach (QDockWidget* doc, m_panels)
            {
                if (doc->widget() && doc->widget()->isVisible())
                    visiblePanelNames << doc->objectName();
            }
        }
        else if (m_pluginsVisibility.contains(part))
            visiblePanelNames = m_pluginsVisibility[part];

        KConfigGroup panelStatusGroup(KSharedConfig::openConfig(), QLatin1String("PanelsStatus"));
        panelStatusGroup.writeEntry(m_parts2Backends[part], visiblePanelNames.join(QLatin1Char('\n')));
    }
}
810
811
812
813
814
815
816

void CantorShell::updateBackendForPart(const QString& backend)
{
    KParts::ReadWritePart* part=dynamic_cast<KParts::ReadWritePart*>(sender());
    if (part && m_parts2Backends.contains(part) && m_parts2Backends[part].isEmpty())
        m_parts2Backends[part] = backend;
}