toplevel.cpp 14 KB
Newer Older
1
2
/* This file is part of the KDE project
   Copyright (C) 2000 David Faure <faure@kde.org>
3
   Copyright (C) 2002-2003 Alexander Kellett <lypanov@kde.org>
4
5
6
7
8
9
10
11

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
   License version 2 as published by the Free Software Foundation.

   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
12
   General Public License for more details.
13
14
15

   You should have received a copy of the GNU General Public License
   along with this program; see the file COPYING.  If not, write to
Dirk Mueller's avatar
Dirk Mueller committed
16
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Dirk Mueller's avatar
Dirk Mueller committed
17
   Boston, MA 02110-1301, USA.
18
19
*/

20
21
#include "toplevel.h"

22
23
#include "bookmarkmodel.h"

24
#include "bookmarkinfo.h"
25
26
27
#include "actionsimpl.h"
#include "dcop.h"
#include "exporters.h"
28
#include "settings.h"
29
#include "commands.h"
30
#include "kebsearchline.h"
31
#include "bookmarklistview.h"
32

33
#include <stdlib.h>
34

Dirk Mueller's avatar
Dirk Mueller committed
35
36
37
38
#include <QtGui/QClipboard>
#include <QtGui/QSplitter>
#include <QtGui/QLayout>
#include <QtGui/QLabel>
39

Aaron J. Seigo's avatar
Aaron J. Seigo committed
40
41
42
#include <kaction.h>
#include <kactioncollection.h>
#include <ktoggleaction.h>
43
#include <kapplication.h>
Aaron J. Seigo's avatar
Aaron J. Seigo committed
44
45
46
47
48
49
50
51
#include <kbookmark.h>
#include <kbookmarkmanager.h>
#include <kdebug.h>
#include <kedittoolbar.h>
#include <kfiledialog.h>
#include <klineedit.h>
#include <klocale.h>
#include <kmessagebox.h>
Aaron J. Seigo's avatar
Aaron J. Seigo committed
52
#include <kstandardaction.h>
53

54
#include <assert.h>
Dirk Mueller's avatar
Dirk Mueller committed
55
#include <QtCore/QBool>
56
57


Alexander Kellett's avatar
Alexander Kellett committed
58

59
60
CmdHistory* CmdHistory::s_self = 0;

61
CmdHistory::CmdHistory(KActionCollection *collection)
62
    : m_commandHistory(collection) {
David Faure's avatar
David Faure committed
63
64
    connect(&m_commandHistory, SIGNAL( commandExecuted(K3Command *) ),
            SLOT( slotCommandExecuted(K3Command *) ));
65
    assert(!s_self);
66
    s_self = this; // this is hacky
67
68
69
}

CmdHistory* CmdHistory::self() {
70
    assert(s_self);
71
    return s_self;
72
73
}

David Faure's avatar
David Faure committed
74
void CmdHistory::slotCommandExecuted(K3Command *k) {
75
    KEBApp::self()->notifyCommandExecuted();
76

77
78
79
80
81
82
    IKEBCommand * cmd = dynamic_cast<IKEBCommand *>(k);
    Q_ASSERT(cmd);

    KBookmark bk = CurrentMgr::bookmarkAt(cmd->affectedBookmarks());
    Q_ASSERT(bk.isGroup());
    CurrentMgr::self()->notifyManagers(bk.toGroup());
83
84
}

85
void CmdHistory::notifyDocSaved() {
86
    m_commandHistory.documentSaved();
87
88
}

David Faure's avatar
David Faure committed
89
void CmdHistory::didCommand(K3Command *cmd) {
90
91
92
    if (!cmd)
        return;
    m_commandHistory.addCommand(cmd, false);
93
    CmdHistory::slotCommandExecuted(cmd);
94
95
}

David Faure's avatar
David Faure committed
96
void CmdHistory::addCommand(K3Command *cmd) {
97
98
99
    if (!cmd)
        return;
    m_commandHistory.addCommand(cmd);
100
101
}

David Faure's avatar
David Faure committed
102
void CmdHistory::addInFlightCommand(K3Command *cmd)
103
104
105
106
107
108
{
    if(!cmd)
        return;
    m_commandHistory.addCommand(cmd, false);
}

109
void CmdHistory::clearHistory() {
110
    m_commandHistory.clear();
111
112
}

113
114
/* -------------------------- */

115
116
CurrentMgr *CurrentMgr::s_mgr = 0;

117
118
119
120
121
KBookmarkGroup CurrentMgr::root()
{
    return mgr()->root();
}

122
KBookmark CurrentMgr::bookmarkAt(const QString &a)
123
{
124
    return self()->mgr()->findByAddress(a);
125
126
127
128
129
}

bool CurrentMgr::managerSave() { return mgr()->save(); }
void CurrentMgr::saveAs(const QString &fileName) { mgr()->saveAs(fileName); }
void CurrentMgr::setUpdate(bool update) { mgr()->setUpdate(update); }
130
QString CurrentMgr::path() const { return mgr()->path(); }
131

132
void CurrentMgr::createManager(const QString &filename, const QString &dbusObjectName) {
133
    if (m_mgr) {
Laurent Montel's avatar
Laurent Montel committed
134
        kDebug()<<"ERROR calling createManager twice"<<endl;
135
136
137
        disconnect(m_mgr, 0, 0, 0);
        // still todo - delete old m_mgr
    }
138

139
    kDebug()<<"DBus Object name: "<<dbusObjectName<<endl;
140
    m_mgr = KBookmarkManager::managerForFile(filename, dbusObjectName);
141

142
143
    connect(m_mgr, SIGNAL( changed(const QString &, const QString &) ),
            SLOT( slotBookmarksChanged(const QString &, const QString &) ));
144
145
}

146
147
148
149
150
void CurrentMgr::slotBookmarksChanged(const QString &, const QString &) {
    if(ignorenext > 0) //We ignore the first changed signal after every change we did
    {
        --ignorenext;
        return;
151
    }
152
153
154

    CmdHistory::self()->clearHistory();
    KEBApp::self()->updateActions();
155
156
}

Robert Knight's avatar
Robert Knight committed
157
void CurrentMgr::notifyManagers(const KBookmarkGroup& grp)
158
159
{
    ++ignorenext;
160
161
162
    mgr()->emitChanged(grp);
}

163
void CurrentMgr::notifyManagers() {
164
    notifyManagers( root() );
165
166
}

167
168
void CurrentMgr::reloadConfig() {
    mgr()->emitConfigChanged();
169
170
}

171
172
173
174
175
176
QString CurrentMgr::makeTimeStr(const QString & in)
{
    int secs;
    bool ok;
    secs = in.toInt(&ok);
    if (!ok)
Laurent Montel's avatar
Laurent Montel committed
177
        return QString();
178
179
180
181
182
183
184
185
    return makeTimeStr(secs);
}

QString CurrentMgr::makeTimeStr(int b)
{
    QDateTime dt;
    dt.setTime_t(b);
    return (dt.daysTo(QDateTime::currentDateTime()) > 31)
186
187
        ? KGlobal::locale()->formatDate(dt.date(), KLocale::LongDate)
        : KGlobal::locale()->formatDateTime(dt, KLocale::LongDate);
188
189
}

190
/* -------------------------- */
Dirk Mueller's avatar
Dirk Mueller committed
191
#include <QtDBus/QDBusConnection>
Alexander Kellett's avatar
Alexander Kellett committed
192
KEBApp *KEBApp::s_topLevel = 0;
193

194
KEBApp::KEBApp(
195
    const QString &bookmarksFile, bool readonly,
196
197
    const QString &address, bool browser, const QString &caption,
    const QString &dbusObjectName
198
) : KXmlGuiWindow(), m_dcopIface(0), m_bookmarksFilename(bookmarksFile),
199
    m_caption(caption),
Laurent Montel's avatar
Laurent Montel committed
200
    m_dbusObjectName(dbusObjectName), m_readOnly(readonly),m_browser(browser)
201
 {
Laurent Montel's avatar
Laurent Montel committed
202
    QDBusConnection::sessionBus().registerObject("/keditbookmarks", this, QDBusConnection::ExportScriptableSlots);
Daniel Teske's avatar
Daniel Teske committed
203
204
    Q_UNUSED(address);//FIXME sets the current item

205
    m_cmdHistory = new CmdHistory(actionCollection());
Alexander Kellett's avatar
Alexander Kellett committed
206

207
    s_topLevel = this;
208

209
    QSplitter *vsplitter = new QSplitter(this);
210

211
212
213
214
215
    createActions();
    if (m_browser)
        createGUI();
    else
        createGUI("keditbookmarks-genui.rc");
216

217
    m_dcopIface = new KBookmarkEditorIface();
Alexander Kellett's avatar
Alexander Kellett committed
218

219
    connect(qApp->clipboard(), SIGNAL( dataChanged() ),
220
                               SLOT( slotClipboardDataChanged() ));
Alexander Kellett's avatar
Alexander Kellett committed
221

222
    KGlobal::locale()->insertCatalog("libkonq");
223

224
225
    m_canPaste = false;

226
    CurrentMgr::self()->createManager(m_bookmarksFilename, m_dbusObjectName);
Alexander Kellett's avatar
Alexander Kellett committed
227

Daniel Teske's avatar
Daniel Teske committed
228
    mBookmarkListView = new BookmarkListView();
229
230
231
232
    mBookmarkListView->setModel( BookmarkModel::self() );
    mBookmarkListView->setSelectionMode(QAbstractItemView::ExtendedSelection);
    mBookmarkListView->loadColumnSetting();

Urs Wolfer's avatar
Urs Wolfer committed
233
    KViewSearchLineWidget *searchline = new KViewSearchLineWidget(mBookmarkListView);
Daniel Teske's avatar
Daniel Teske committed
234

Daniel Teske's avatar
Daniel Teske committed
235
    mBookmarkFolderView = new BookmarkFolderView(mBookmarkListView);
236

Urs Wolfer's avatar
Urs Wolfer committed
237
238
239
240
241
242
    QWidget *listLayoutWidget = new QWidget;

    QVBoxLayout *listLayout = new QVBoxLayout(listLayoutWidget);
    listLayout->addWidget(searchline);
    listLayout->addWidget(mBookmarkListView);

Daniel Teske's avatar
Daniel Teske committed
243
    m_bkinfo = new BookmarkInfoWidget(mBookmarkListView);
244
245

    vsplitter->setOrientation(Qt::Vertical);
Urs Wolfer's avatar
Urs Wolfer committed
246
    vsplitter->addWidget(listLayoutWidget);
Daniel Teske's avatar
Daniel Teske committed
247
    vsplitter->addWidget(m_bkinfo);
248

Daniel Teske's avatar
Daniel Teske committed
249
250
251
252
253
    QSplitter *hsplitter = new QSplitter(this);
    hsplitter->setOrientation(Qt::Horizontal);
    hsplitter->addWidget(mBookmarkFolderView);
    hsplitter->addWidget(vsplitter);
    //FIXME set sensible sizes for vsplitter and hsplitter
254

Daniel Teske's avatar
Daniel Teske committed
255
256
257
    setCentralWidget(hsplitter);

    expandAll();
258
259
260
261
262
263

    slotClipboardDataChanged();
    setAutoSaveSettings();

    connect(mBookmarkListView->selectionModel(), SIGNAL(selectionChanged(  const QItemSelection &, const QItemSelection & )),
            this, SLOT(selectionChanged()));
Daniel Teske's avatar
Daniel Teske committed
264

Daniel Teske's avatar
Daniel Teske committed
265
266
    setCancelFavIconUpdatesEnabled(false);
    setCancelTestsEnabled(false);
267
    updateActions();
268
269
}

Laurent Montel's avatar
Laurent Montel committed
270
271
272
273
274
QString KEBApp::bookmarkFilename()
{
   return m_bookmarksFilename;
}

275
void KEBApp::reset(const QString & caption, const QString & bookmarksFileName)
276
277
278
{
    m_caption = caption;
    m_bookmarksFilename = bookmarksFileName;
279
    CurrentMgr::self()->createManager(m_bookmarksFilename, m_dbusObjectName); //FIXME this is still a memory leak (iff called by slotLoad)
280
281
282
283
    BookmarkModel::self()->resetModel();
    expandAll();
    updateActions();
}
284

285
286
287
288
void KEBApp::collapseAll()
{
    collapseAllHelper( BookmarkModel::self()->index(0, 0, QModelIndex()));
}
289

290
291
292
293
294
295
296
297
298
299
void KEBApp::collapseAllHelper( QModelIndex index )
{
    mBookmarkListView->collapse(index);
    int rowCount = index.model()->rowCount(index);
    for(int i=0; i<rowCount; ++i)
        collapseAllHelper(index.child(i, 0));
}

void KEBApp::expandAll()
{
Daniel Teske's avatar
Daniel Teske committed
300
301
    expandAllHelper( mBookmarkListView, BookmarkModel::self()->index(0, 0, QModelIndex()));
    expandAllHelper( mBookmarkFolderView, BookmarkModel::self()->index(0, 0, QModelIndex()));
302
303
}

Daniel Teske's avatar
Daniel Teske committed
304
void KEBApp::expandAllHelper(QTreeView * view, QModelIndex index)
305
{
Daniel Teske's avatar
Daniel Teske committed
306
    view->expand(index);
307
308
    int rowCount = index.model()->rowCount(index);
    for(int i=0; i<rowCount; ++i)
Daniel Teske's avatar
Daniel Teske committed
309
        expandAllHelper(view, index.child(i, 0));
310
311
312
313
314
}

void KEBApp::startEdit( Column c )
{
    const QModelIndexList & list = mBookmarkListView->selectionModel()->selectedIndexes();
Daniel Teske's avatar
Daniel Teske committed
315
316
317
318
319
    QModelIndexList::const_iterator it, end;
    end = list.constEnd();
    for(it = list.constBegin(); it != end; ++it)
        if( (*it).column() == int(c) && (BookmarkModel::self()->flags(*it) & Qt::ItemIsEditable) )
            return mBookmarkListView->edit( *it );
320
321
322
323
324
325
326
327
328
329
330
331
}

KBookmark KEBApp::firstSelected() const
{
    const QModelIndexList & list = mBookmarkListView->selectionModel()->selectedIndexes();
    QModelIndex index = *list.constBegin();
    return static_cast<TreeItem *>(index.internalPointer())->bookmark();
}

QString KEBApp::insertAddress() const
{
    KBookmark current = firstSelected();
332
    return (current.isGroup())
333
334
335
336
        ? (current.address() + "/0") //FIXME internal represantation used
        : KBookmark::nextAddress(current.address());
}

Robert Knight's avatar
Robert Knight committed
337
bool lessAddress(const QString& first, const QString& second)
338
{
Robert Knight's avatar
Robert Knight committed
339
340
341
    QString a = first;
    QString b = second;

342
343
344
345
346
347
348
349
350
    if(a == b)
         return false;

    QString error("ERROR");
    if(a == error)
        return false;
    if(b == error)
        return true;

Thorsten Roeder's avatar
Thorsten Roeder committed
351
352
    a += '/';
    b += '/';
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367

    uint aLast = 0;
    uint bLast = 0;
    uint aEnd = a.length();
    uint bEnd = b.length();
    // Each iteration checks one "/"-delimeted part of the address
    // "" is treated correctly
    while(true)
    {
        // Invariant: a[0 ... aLast] == b[0 ... bLast]
        if(aLast + 1 == aEnd) //The last position was the last slash
            return true; // That means a is shorter than b
        if(bLast +1 == bEnd)
            return false;

368
369
        uint aNext = a.indexOf("/", aLast + 1);
        uint bNext = b.indexOf("/", bLast + 1);
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391

        bool okay;
        uint aNum = a.mid(aLast + 1, aNext - aLast - 1).toUInt(&okay);
        if(!okay)
            return false;
        uint bNum = b.mid(bLast + 1, bNext - bLast - 1).toUInt(&okay);
        if(!okay)
            return true;

        if(aNum != bNum)
            return aNum < bNum;

        aLast = aNext;
        bLast = bNext;
    }
}

bool lessBookmark(const KBookmark & first, const KBookmark & second) //FIXME Using internal represantation
{
    return lessAddress(first.address(), second.address());
}

392
KBookmark::List KEBApp::selectedBookmarks() const
393
{
394
    KBookmark::List bookmarks;
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
    const QModelIndexList & list = mBookmarkListView->selectionModel()->selectedIndexes();
    QModelIndexList::const_iterator it, end;
    end = list.constEnd();
    for( it = list.constBegin(); it != end; ++it)
    {
        if((*it).column() != 0)
            continue;
        KBookmark bk = static_cast<TreeItem *>((*it).internalPointer())->bookmark();;
        if(bk.address() != CurrentMgr::self()->root().address())
            bookmarks.push_back( bk );
    }
    qSort(bookmarks.begin(), bookmarks.end(), lessBookmark);
    return bookmarks;
}

410
KBookmark::List KEBApp::selectedBookmarksExpanded() const
411
{
412
413
414
    KBookmark::List bookmarks = selectedBookmarks();
    KBookmark::List result;
    KBookmark::List::const_iterator it, end;
415
416
417
418
419
420
421
422
    end = bookmarks.constEnd();
    for(it = bookmarks.constBegin(); it != end; ++it)
    {
        selectedBookmarksExpandedHelper( *it, result );
    }
    return result;
}

Robert Knight's avatar
Robert Knight committed
423
void KEBApp::selectedBookmarksExpandedHelper(const KBookmark& bk, KBookmark::List & bookmarks) const
424
425
426
427
428
429
430
431
432
433
434
435
{
    bookmarks.push_back( bk );
    if(bk.isGroup())
    {
        KBookmarkGroup parent = bk.toGroup();
        KBookmark child = parent.first();
        while(child.hasParent())
        {
            selectedBookmarksExpandedHelper(child, bookmarks);
            child = parent.next(child);
        }
    }
Daniel Teske's avatar
Daniel Teske committed
436
437
}

Stephen Leaf's avatar
Stephen Leaf committed
438
void KEBApp::updateStatus(const QString &url)
Daniel Teske's avatar
Daniel Teske committed
439
440
441
{
    if(m_bkinfo->bookmark().url() == url)
        m_bkinfo->updateStatus();
442
443
}

Alexander Kellett's avatar
Alexander Kellett committed
444
KEBApp::~KEBApp() {
445
    s_topLevel = 0;
Daniel Teske's avatar
Daniel Teske committed
446
    delete m_cmdHistory;
447
    delete m_dcopIface;
Alexander Kellett's avatar
Alexander Kellett committed
448
    delete ActionsImpl::self();
449
450
    delete mBookmarkListView;
    delete BookmarkModel::self();
451
452
}

453
KToggleAction* KEBApp::getToggleAction(const char *action) const {
454
    return static_cast<KToggleAction*>(actionCollection()->action(action));
455
456
}

Alexander Kellett's avatar
Alexander Kellett committed
457
void KEBApp::resetActions() {
458
459
    stateChanged("disablestuff");
    stateChanged("normal");
Alexander Kellett's avatar
Alexander Kellett committed
460

461
462
    if (!m_readOnly)
        stateChanged("notreadonly");
463
}
Alexander Kellett's avatar
Alexander Kellett committed
464

465
466
467
468
469
void  KEBApp::selectionChanged()
{
    updateActions();
}

Alexander Kellett's avatar
Alexander Kellett committed
470
void KEBApp::updateActions() {
Daniel Teske's avatar
Daniel Teske committed
471
    // FIXME if nothing is selected in the item view, the folder in the group view
472
    // is selected.
Daniel Teske's avatar
Daniel Teske committed
473
    // Change setActionsEnabled() and firstSelected() to match that
474
    resetActions();
475
    setActionsEnabled(mBookmarkListView->getSelectionAbilities());
476
477
}

Alexander Kellett's avatar
Alexander Kellett committed
478
void KEBApp::slotClipboardDataChanged() {
Laurent Montel's avatar
Laurent Montel committed
479
    // kDebug() << "KEBApp::slotClipboardDataChanged" << endl;
480
    if (!m_readOnly) {
Daniel Teske's avatar
Daniel Teske committed
481
482
        m_canPaste = KBookmark::List::canDecode(
                        QApplication::clipboard()->mimeData());
Daniel Teske's avatar
Daniel Teske committed
483
        updateActions();
484
    }
485
486
}

Alexander Kellett's avatar
Alexander Kellett committed
487
/* -------------------------- */
488

489
void KEBApp::notifyCommandExecuted() {
Laurent Montel's avatar
Laurent Montel committed
490
    // kDebug() << "KEBApp::notifyCommandExecuted()" << endl;
491
    updateActions();
492
493
}

494
/* -------------------------- */
495

Alexander Kellett's avatar
Alexander Kellett committed
496
void KEBApp::slotConfigureToolbars() {
497
    saveMainWindowSettings(KConfigGroup( KGlobal::config(), "MainWindow") );
Aaron J. Seigo's avatar
Aaron J. Seigo committed
498
    KEditToolBar dlg(actionCollection());
499
    connect(&dlg, SIGNAL( newToolbarConfig() ),
500
501
                  SLOT( slotNewToolbarConfig() ));
    dlg.exec();
502
503
}

Alexander Kellett's avatar
Alexander Kellett committed
504
void KEBApp::slotNewToolbarConfig() {
505
506
    // called when OK or Apply is clicked
    createGUI();
507
    applyMainWindowSettings(KConfigGroup(KGlobal::config(), "MainWindow") );
508
509
}

Alexander Kellett's avatar
Alexander Kellett committed
510
/* -------------------------- */
Alexander Kellett's avatar
Alexander Kellett committed
511

512
#include "toplevel.moc"
513