diff --git a/CHANGELOG b/CHANGELOG index fec16ba..c2445dc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,187 +1,194 @@ +--December 9,2009-- +- Refactored the Sidebar in order to inherit from QTableWidget, now it can + be placed both in vertical and horizontal position; btw it need some + polishing yet =) +- Fixed font rendering, now it doesn't cut the ending of the string +- Updated older and obsolete includes + --December 6,2009-- - Documentation widget now saves its current page on exit and restores it the next time PlasMate starts. --December 5, 2009-- - Rewritten the TimeLine widget in order to allow the user to place it both in vertical and horizontal position. --November 30,2009-- - Selecting the editor tab now loads the previous active editor (if exists) instead of showing the 'select a file' QWidget. --November 29,2009-- - The state of central widgets (editor, publisher, documentation etc) are no longer reloaded, but are remembered and restored as the user switches between them. --November 28,2009-- - Added simple documentation widget. --November 23,2009-- - Reverted 'Recent project list' to showing plasmoid names and fixed so it works. Import plasmoids now works. --November 21,2009-- - Added preliminary support for importing plasmoids. 'Recent project list' now shows project folder names instead of plasmoid names to avoid confusion. --November 15,2009-- - Added a simple, draft publisher widget. Exporting and installing plasmoids work, but online publishing doesn't for now. --November 14,2009-- - New files can now be added to the project by clicking 'New' in the editor tree, and existing files can be deleted by doing a right-click > Delete. --November 13,2009-- - Editor tree now dynamically reflects changes in the directory --October 27,2009-- - Restored previewer dockwidget (while retaining previewer tab for now). Previewer refresh button now asks the mainwindow to save any unsaved data so that the preview is up to date. Also added a 'Refresh Previewer' menubar item with a keyboard shortcut (Ctrl-F5 for now) that does the same. --October 26,2009-- - Editor contents are now automagically saved on swapping files/tabs and on exit. --October 19,2009-- - Metadata editor now loads properly (but still unable to save). Previewer is now in a tab of its own. --October 18,2009-- - Selecting metadata now brings up the metadata editor GUI - but it doesn't really work. --October 1,2009-- - Experimental separation of editor tree-widget into a QDockWidget. Still UGLY and BUGGY. --September 26,2009-- - Package metadata file is now visible and editable in the editor. --September 25, 2009-- - Fixed more editor issues : all tree widget entries are now correctly named and properly mapped to their respective files. --September 23, 2009-- - Fixed clicking certain files in the editor component tree widget causing plasmate to crash. Issues remaining for editor: - File entries are not properly named in editor's project structure tree. - metadata.desktop is not currently editable (or visible). --September 20, 2009-- - Editor component now makes a (buggy) attempt to load clicked project files with an editor kpart. Also fixed a bug causing editor kpart to not load the first time the editor component is loaded. --September 19, 2009-- - Fixed previewer refresh code: Refreshing now properly reflects changes since previous refresh. Also fixed issue with refreshed plasmoid being smaller than original. --September 12, 2009-- - Loading a project now also attempts to load a preview in previewer --August 29, 2009-- - Modified the newSavePoint() method to prevent a crash when the user want to store his first SavePoint, but then it discard the "new SavePoint" dialog. --August 22, 2009-- - Added titles to the previewer tool menus. --August 14, 2009-- - Updated the TimeLine test class, now it shows a simple widget with the TimeLine and a button used to create new SavePoints. - Removed useless header from timeline* sources. --August 13, 2009-- - Commented the remaining headers under /savesystem, removed unused files and the /vng dir. --August 12, 2009-- - Added to BranchDialog class a simple regexp validator, in order to avoid use of non-standard characters when the user types a new branch name. - Starting writing apidox documentation, removin useless methods and fixing style. --August 10, 2009-- - Fixed StartPage issue: opening/creating a project, when an other one is already open, now works. - TimeLine didn't reload properly when changing from an existing project to an other. Fixed. --August 9, 2009-- - Moved "New SavePoint" buttom from timeline to workflow dock widget. Changed workflow signals connection in order to restore the previous tab after setting a SavePoint. - Added bool GitRunner::hasNewChangesToCommit(), so New SavePoint dialog is triggered only if there are uncommitted changes. - Moved "On Section: " button on the top of TimeLine dock for usability reason, because if there are lots of SavePoints, the user has to scroll down each time he want to perfom an action Section-related. - Fixed plasma-containment-studiopreviewer.desktop file; now it doesn't interacts with "Desktop Settings" -> "Desktop Activity" entries. - Some fixes and coding style fix. --August 3, 2009-- - When creating a new project, metadata.desktop file is filled with the required fields - Added setAuthor and setEmail to GitRunner class, so now TimeLine can set that fields - Review createNewProject code. - Fixed some krazy warnings. --July 30, 2009-- - New Project page displays now two fields, Author and Email, defaulted to and @none.org. These values are inserted in the header contained int the main script file. --July 29, 2009-- - Fixed saving/reloading layout ( still need some fixing with previewer dimensions btw ) - Now templates are installed under $KDEDIR/share/apps/plasmate/templates - When creating a new project, PlasMate makes a copy of the corresponding template in the working directory, modify its file name and the main class to match the project name. --July 26, 2009-- - Added radio button to select the scripting language, connected KLineEdit::returnPressed() signal, saved docks position so the next time PlasMate is loaded, it reloads docks previous position ( need more fixing btw ). - Added templated folder, with simple sources for plasmoid and data engines. --July 25, 2009-- - The loading of a text editor at the Publish tab was unnecessary. Removed. - Cancel button added to new project screen. --July 21, 2009-- - Fixed the issue with the KRestrictedLine form; now it accepts correctly all names composed by characters a-z,A-Z,0-9, and "_", "." --July 19, 2009-- - Added merge capabilities to TimeLine class. --July 17, 2009-- - TimeLine now is able to create/delete branches, move to a selected commit ( creating also a new branch to preserve other commits ), restore the current state to whatever commit ( deleting all the commits performed after it, in the same branch ), init itself and save commits. --July 14, 2009-- - Now the TimeLine sets-up a menu for each item, available by right-clicking on it: implemented the switch branch feature. --July 12, 2009-- - Fixed a strange behaviour with GitRunner class which causes the app to continue runnig, even if the app is closed. Extended TimeLine class; now it shows in the main window the current branches and its related commits, and more infos are provided when moving the mouse over the icons. --July 7, 2009-- - Fixed DvcsJob behaviour when are performed sequential calls, like in the unit test. Added the following action in the GitRunner class: remove, status, log, reset, newBranch, switchBranch, branches. --July 5, 2009-- - Splitted the Sidebar class, coded the following git action: init, add, commit, isValidDirectory and clone ( only with local repo, for now ). Wrote a simple test case, and start integrating it in the timeline class. --June 1, 2009-- -Appropriate kpart shown when an item is selected from the tree in the Edit tab. --June 24, 2009-- -Simple 'Pick wallpaper plugin' functionality added to previewer diff --git a/CMakeLists.txt b/CMakeLists.txt index e358a92..9b535ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,51 +1,50 @@ project(PlasMate) find_package(KDE4) include(KDE4Defaults) set (PlasMate_SRC editors/editpage.cpp editors/metadata/metadataeditor.cpp main.cpp sidebaritem.cpp sidebardelegate.cpp - sidebarlistwidget.cpp - sidebarprivatestorage.cpp + sidebartablewidget.cpp sidebar.cpp savesystem/dvcsjob.cpp savesystem/gitrunner.cpp savesystem/branchdialog.cpp savesystem/commitdialog.cpp savesystem/timelineitem.cpp savesystem/tabledelegate.cpp savesystem/tablewidget.cpp savesystem/timeline.cpp mainwindow.cpp startpage.cpp packagemodel.cpp previewer/previewer.cpp publisher/publisher.cpp docbrowser/docbrowser.cpp ) kde4_add_ui_files (PlasMate_SRC mainwindow.ui startpage.ui editors/metadata/metadata.ui ) include_directories(${KDE4_INCLUDES}) add_subdirectory( editors ) add_subdirectory( previewer ) add_subdirectory( savesystem ) add_subdirectory( templates ) add_subdirectory( publisher ) add_subdirectory( docbrowser ) #add_subdirectory( savesystem ) kde4_add_executable(plasmate ${PlasMate_SRC}) target_link_libraries(plasmate ${KDE4_KDEUI_LIBS} ${KDE4_KTEXTEDITOR_LIBS} ${KDE4_KPARTS_LIBS} ${KDE4_KIO_LIBRARY} ${KDE4_PLASMA_LIBS}) install(TARGETS plasmate ${INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES plasmateui.rc DESTINATION ${DATA_INSTALL_DIR}/plasmate) diff --git a/mainwindow.cpp b/mainwindow.cpp index 28a18d1..d850ba4 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -1,521 +1,518 @@ /* Copyright (c) 2009 Riccardo Iaconelli 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "editors/editpage.h" #include "editors/metadata/metadataeditor.h" #include "savesystem/timeline.h" #include "mainwindow.h" #include "packagemodel.h" #include "sidebar.h" #include "startpage.h" #include "ui_mainwindow.h" #include "previewer/previewer.h" #include "publisher/publisher.h" #include "docbrowser/docbrowser.h" MainWindow::CentralContainer::CentralContainer(QWidget* parent) : QWidget(parent), m_curWidget(0), m_curMode(Preserve) { m_layout = new QVBoxLayout(); setLayout(m_layout); } void MainWindow::CentralContainer::switchTo(QWidget* newWidget, SwitchMode mode) { if (m_curWidget) { m_curWidget->hide(); m_layout->removeWidget(m_curWidget); if (m_curMode == DeleteAfter) delete m_curWidget; } m_curMode = mode; m_curWidget = newWidget; m_layout->addWidget(m_curWidget); m_curWidget->show(); } MainWindow::MainWindow(QWidget *parent) : KParts::MainWindow(parent, 0), - m_workflow(0), m_sidebar(0), m_timeLine(0), m_previewer(0), m_publisher(0), m_browser(0), m_metaEditor(0), m_editWidget(0), m_editPage(0), m_model(0), m_oldTab(0), // we start from startPage docksCreated(false), m_part(0) { setXMLFile("plasmateui.rc"); createMenus(); m_startPage = new StartPage(this); connect(m_startPage, SIGNAL(projectSelected(QString, QString)), this, SLOT(loadProject(QString, QString))); m_central = new CentralContainer(this); setCentralWidget(m_central); m_central->switchTo(m_startPage); setDockOptions(QMainWindow::AllowNestedDocks); // why not? } MainWindow::~MainWindow() { // Saving layout position KConfig c; KConfigGroup configDock = c.group("DocksPosition"); configDock.writeEntry("MainWindowLayout", saveState(0)); + configDock.writeEntry("WorkflowLocation", QVariant(m_sidebar->location())); + configDock.writeEntry("TimeLineLocation", QVariant(m_timeLine->location())); c.sync(); // if the user closes the application with an editor open, should // save its contents saveEditorData(); delete m_part; m_part = 0; delete m_metaEditor; m_metaEditor = 0; - if (m_workflow) { + if (m_sidebar) { //delete m_startPage; - //configDock.writeEntry("WorkflowLocation", QVariant(m_workflow->location())); - delete m_workflow; + delete m_sidebar; } if (m_previewer) { configDock.writeEntry("PreviewerHeight", m_previewerWidget->height()); configDock.writeEntry("PreviewerWidth", m_previewerWidget->width()); c.sync(); delete m_previewer; delete m_previewerWidget; } if (m_browser) { // save current page for restoration next time // TODO: Maybe it makes more sense to save this per-project? KConfigGroup cg = KGlobal::config()->group("General"); cg.writeEntry("lastBrowserPage", m_browser->currentPage().toEncoded()); KGlobal::config()->sync(); delete m_browser; } if (m_publisher) { delete m_publisher; } if (m_timeLine) { - configDock.writeEntry("TimeLineLocation", QVariant(m_timeLine->location())); delete m_timeLine; } if (m_editPage) { delete m_editPage; delete m_editWidget; } } void MainWindow::createMenus() { KStandardAction::quit(this, SLOT(quit()), actionCollection()); KAction *refresh = KStandardAction::redisplay(this, SLOT(saveAndRefresh()), actionCollection()); refresh->setShortcut(tr("Ctrl+F5")); refresh->setText("Refresh Previewer"); menuBar()->addMenu(helpMenu()); setupGUI(); } void MainWindow::createDockWidgets() { KConfig c; KConfigGroup configDock = c.group("DocksPosition"); ///////////////////////////////////////////////////////////////////////// - m_workflow = new QDockWidget(i18n("Workflow"), this); - m_workflow->setObjectName("workflow"); - m_sidebar = new Sidebar(m_workflow); + Qt::DockWidgetArea location = (Qt::DockWidgetArea) configDock.readEntry("WorkflowLocation", + QVariant(Qt::TopDockWidgetArea)).toInt(); + m_sidebar = new Sidebar(this, + location); + m_sidebar->setObjectName("workflow"); + addDockWidget(location, m_sidebar); m_sidebar->addItem(KIcon("go-home"), i18n("Start page")); m_sidebar->addItem(KIcon("accessories-text-editor"), i18n("Edit")); m_sidebar->addItem(KIcon("document-save"),i18n("New SavePoint")); m_sidebar->addItem(KIcon("krfb"), i18n("Publish")); m_sidebar->addItem(KIcon("help-contents"), i18n("Documentation")); m_sidebar->addItem(KIcon("user-desktop"), i18n("Preview")); connect(m_sidebar, SIGNAL(currentIndexClicked(const QModelIndex &)), this, SLOT(changeTab(const QModelIndex &))); - m_workflow->setWidget(m_sidebar); - addDockWidget(Qt::LeftDockWidgetArea, m_workflow); - - m_workflow->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding); - m_sidebar->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding); ///////////////////////////////////////////////////////////////////////// m_editPage = new EditPage(); m_editPage->setModel(m_model); m_editWidget = new QDockWidget(i18n("Files"), this); m_editWidget->setObjectName("edit tree"); m_editWidget->setWidget(m_editPage); addDockWidget(Qt::RightDockWidgetArea, m_editWidget); connect(m_editPage, SIGNAL(loadEditor(KService::List, KUrl)), this, SLOT(loadRequiredEditor(const KService::List, KUrl))); connect(m_editPage, SIGNAL(loadMetaDataEditor(KUrl)), this, SLOT(loadMetaDataEditor(KUrl))); m_editPage->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); m_editWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); ///////////////////////////////////////////////////////////////////////// - Qt::DockWidgetArea location = (Qt::DockWidgetArea) configDock.readEntry("TimeLineLocation", - QVariant(Qt::BottomDockWidgetArea)).toInt(); + location = (Qt::DockWidgetArea) configDock.readEntry("TimeLineLocation", + QVariant(Qt::BottomDockWidgetArea)).toInt(); m_timeLine = new TimeLine(this, m_model->package(), location); m_timeLine->setObjectName("timeline"); addDockWidget(location, m_timeLine); ///////////////////////////////////////////////////////////////////////// m_previewerWidget = new QDockWidget(i18n("Previewer"), this); - m_previewerWidget->setObjectName("workflow"); + m_previewerWidget->setObjectName("preview"); m_previewer = new Previewer(this); m_previewerWidget->setWidget(m_previewer); addDockWidget(Qt::LeftDockWidgetArea, m_previewerWidget); m_previewerWidget->updateGeometry(); m_previewer->updateGeometry(); m_previewer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_previewerWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - splitDockWidget(m_workflow, m_editWidget, Qt::Horizontal); + //splitDockWidget(m_workflow, m_editWidget, Qt::Horizontal); splitDockWidget(m_editWidget, m_previewerWidget, Qt::Vertical); // Restoring the previous layout restoreState(configDock.readEntry("MainWindowLayout",QByteArray()), 0); connect(this, SIGNAL(newSavePointClicked()), m_timeLine, SLOT(newSavePoint())); // Restore browser widget if there is something to restore KConfigGroup cg = KGlobal::config()->group("General"); QString lastPage = cg.readEntry("lastBrowserPage"); if (lastPage != QString::null) { // restore! m_browser = new DocBrowser(this); m_browser->load(lastPage); } docksCreated = true; int w = size().width() < sizeHint().width() ? sizeHint().width() : size().width(); int h = size().height() < sizeHint().height() ? sizeHint().height() : size().height(); resize(w, h); } void MainWindow::quit() { qApp->closeAllWindows(); // deleteLater(); } void MainWindow::changeTab(const QModelIndex &item) { // should save data in any open editors when changing tabs saveEditorData(); - int tab = item.row(); + int tab = (m_sidebar->isVertical()) ? item.row(): item.column(); m_startPage->resetStatus(); if(tab == SavePoint) { emit newSavePointClicked(); m_sidebar->setCurrentIndex(m_oldTab); tab = m_oldTab; } switch (tab) { case StartPageTab: { m_central->switchTo(m_startPage); } break; case EditTab: { // see if there is a previously active editor to restore if (m_metaEditor) { m_central->switchTo(m_metaEditor); } else if (m_part) { m_central->switchTo(m_part->widget()); m_part->widget()->setFocus(Qt::OtherFocusReason); } else { QLabel *l = new QLabel(i18n("Select a file to edit."), this); m_central->switchTo(l, CentralContainer::DeleteAfter); } } break; case PublishTab: { if (!m_publisher) m_publisher = new Publisher(this, m_model->package()); m_central->switchTo(m_publisher); } break; case DocsTab: { if (!m_browser) m_browser = new DocBrowser(this); m_central->switchTo(m_browser); } break; case PreviewTab: { Previewer *tabPreviewer = new Previewer(this); tabPreviewer->addApplet(m_model->package()); m_central->switchTo(tabPreviewer, CentralContainer::DeleteAfter); } } m_oldTab = tab; } void MainWindow::saveEditorData() { if (qobject_cast(m_part)) { static_cast(m_part)->save(); } if (m_metaEditor) { m_metaEditor->writeFile(); } } void MainWindow::saveAndRefresh() { saveEditorData(); emit refreshRequested(); } void MainWindow::loadRequiredEditor(const KService::List offers, KUrl target) { // save any previous editor content saveEditorData(); if (offers.isEmpty()) { kDebug() << "No offers for editor, can not load."; return; } QVariantList args; QString error; // we should show this via debug if we fail KParts::ReadOnlyPart *part = dynamic_cast( offers.at(0)->createInstance( this, args, &error)); QWidget *mainWidget = 0; if (!m_part || !part->inherits(m_part->metaObject()->className())) { delete m_part; // reuse if we can m_part = part; KTextEditor::Document *editorPart = qobject_cast(m_part); if (editorPart) { KTextEditor::View *view = qobject_cast(editorPart->widget()); setupTextEditor(editorPart, view); mainWidget = view; } else { mainWidget = m_part->widget(); } } else { delete part; mainWidget = m_part->widget(); } if (!m_part) { kDebug() << "Failed to load editor:" << error; } m_central->switchTo(mainWidget); // open the target for editting/viewing if (!target.equals(m_part->url())) m_part->openUrl(target); mainWidget->setMinimumWidth(300); //Add the part's GUI //createGUI(m_part); // We keep only one editor object alive at a time - // so we know who to activate when the edit tab is reselected delete m_metaEditor; m_metaEditor = 0; m_sidebar->setCurrentIndex(EditTab); m_oldTab = EditTab; } void MainWindow::setupTextEditor(KTextEditor::Document *editorPart, KTextEditor::View *view) { //FIXME: we should be setting the highlight based on the type of document //editorPart->setHighlightingMode("JavaScript"); if (view) { view->setContextMenu(view->defaultContextMenu()); KTextEditor::ConfigInterface *config = qobject_cast(view); if (config) { kDebug() << "setting various config values..."; config->setConfigValue("line-numbers", true); config->setConfigValue("dynamic-word-wrap", true); } // set a nicer default indent mode KTextEditor::CommandInterface *command = qobject_cast(editorPart->editor()); if (command) { QString ret; command->queryCommand("set-indent-mode")->exec(view, "set-indent-mode normal", ret); } } KTextEditor::ConfigInterface *config = dynamic_cast(editorPart); if (config) { config->setConfigValue("backup-on-save-prefix", "."); } } void MainWindow::loadMetaDataEditor(KUrl target) { // save any previous editor content saveEditorData(); if (!m_metaEditor) m_metaEditor = new MetaDataEditor(this); m_metaEditor->setFilename(target.path()); m_metaEditor->readFile(); m_central->switchTo(m_metaEditor); m_sidebar->setCurrentIndex(EditTab); m_oldTab = EditTab; } void MainWindow::loadProject(const QString &name, const QString &type) { kDebug() << "Loading project named" << name << "..."; delete m_model; // Saving NewProject preferences KConfigGroup preferences = KGlobal::config()->group("NewProjectDefaultPreferences"); preferences.writeEntry("Username", m_startPage->userName()); preferences.writeEntry("Email", m_startPage->userEmail()); preferences.writeEntry("radioButtonJsChecked", m_startPage->selectedJsRadioButton()); preferences.writeEntry("radioButtonPyChecked", m_startPage->selectedPyRadioButton()); preferences.writeEntry("radioButtonRbChecked", m_startPage->selectedRbRadioButton()); preferences.sync(); QString packagePath = KStandardDirs::locateLocal("appdata", name + '/'); QString actualType = type; if (actualType.isEmpty()) { QDir dir(packagePath); if (dir.exists("metadata.desktop")) { Plasma::PackageMetadata metadata(packagePath + "metadata.desktop"); actualType = metadata.serviceType(); } } // Add it to the recent files first. m_model = new PackageModel(this); m_model->setPackageType(actualType); m_model->setPackage(packagePath); QStringList recentFiles; KConfigGroup cg = KGlobal::config()->group("General"); recentFiles = recentProjects(); if (recentFiles.contains(name)) { recentFiles.removeAt(recentFiles.indexOf(name)); } if (!name.isEmpty()) { recentFiles.prepend(name); } else return; kDebug() << "Writing the following m_sidebar of recent files to the config:" << recentFiles; cg.writeEntry("recentFiles", recentFiles); KGlobal::config()->sync(); // Load the needed widgets, switch to page 1 (edit)... if(!docksCreated) createDockWidgets(); else { // loading a new project! // workaround to completely clear previewer delete m_previewer; m_previewer = new Previewer(this); m_previewerWidget->setWidget(m_previewer); // point editor tree to new model m_editPage->setModel(m_model); // delete old publisher delete m_publisher; m_publisher = 0; } QLabel *l = new QLabel(i18n("Select a file to edit."), this); m_central->switchTo(l); m_oldTab = EditTab; m_sidebar->setCurrentIndex(m_oldTab); m_timeLine->setWorkingDir(KUrl(packagePath)); m_timeLine->loadTimeLine(KUrl(packagePath)); // load project in previewer m_previewer->addApplet(packagePath); // Now, setup some useful properties such as the project name in the title bar // and setting the current working directory. Plasma::PackageMetadata metadata(packagePath + "metadata.desktop"); setCaption("[Project:" + metadata.name() + ']'); kDebug() << "Content prefix: " << m_model->contentsPrefix() ; QDir::setCurrent(m_model->package() + m_model->contentsPrefix()); } QStringList MainWindow::recentProjects() // Q: TODO Limit to 5? // A: Before limiting, we need to provide an "Export" feature so // the developer can save his projects and import it later for review. { KConfigGroup cg = KGlobal::config()->group("General"); QStringList l = cg.readEntry("recentFiles", QStringList()); // kDebug() << l.toStringList(); return l; } diff --git a/mainwindow.h b/mainwindow.h index 956b75b..c9751dd 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -1,124 +1,123 @@ /* Copyright (c) 2009 Riccardo Iaconelli 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. */ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include class QModelIndex; namespace Ui { } class QDockWidget; class QStringList; class EditPage; class PackageModel; class StartPage; class Sidebar; class TimeLine; class MetaDataEditor; // our own previewer class Previewer; class DocBrowser; class Publisher; namespace KTextEditor { class Document; class View; } // namespace KTextEditor class MainWindow : public KParts::MainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); ~MainWindow(); QStringList recentProjects(); public Q_SLOTS: void quit(); void changeTab(const QModelIndex &); void loadProject(const QString &name, const QString &type); void loadRequiredEditor(const KService::List offers, KUrl target); void loadMetaDataEditor(KUrl target); void saveEditorData(); void saveAndRefresh(); signals: void newSavePointClicked(); void refreshRequested(); private: // QMainWindow takes control of and DELETES the previous centralWidget // whenever a new one is set - this is bad because we want to preserve // the state of the previous centralWidget for when it becomes active again. // This class is a workaround - we set an instance as the permanent // centralWidget, and use it to do graceful, non-destructive widget-switching. class CentralContainer : public QWidget { public: enum SwitchMode { Preserve, DeleteAfter }; CentralContainer(QWidget* parent); void switchTo(QWidget* newWidget, SwitchMode mode = Preserve); private: SwitchMode m_curMode; QLayout *m_layout; QWidget *m_curWidget; }; enum WorkflowTabs { StartPageTab = 0, EditTab, SavePoint, PublishTab, DocsTab, PreviewTab }; void createMenus(); void createDockWidgets(); void setupTextEditor(KTextEditor::Document *editorPart, KTextEditor::View *view); StartPage *m_startPage; - QDockWidget *m_workflow; Sidebar *m_sidebar; TimeLine *m_timeLine; QDockWidget *m_previewerWidget; Previewer *m_previewer; MetaDataEditor *m_metaEditor; Publisher *m_publisher; DocBrowser *m_browser; QDockWidget *m_editWidget; EditPage *m_editPage; PackageModel *m_model; int m_oldTab; bool docksCreated; CentralContainer *m_central; KParts::ReadOnlyPart *m_part; }; #endif // MAINWINDOW_H diff --git a/savesystem/tabledelegate.cpp b/savesystem/tabledelegate.cpp index ecf18a6..5cf2a80 100644 --- a/savesystem/tabledelegate.cpp +++ b/savesystem/tabledelegate.cpp @@ -1,91 +1,92 @@ #include #include #include #include #include "tabledelegate.h" static const int ITEM_MARGIN_LEFT = 5; static const int ITEM_MARGIN_TOP = 5; static const int ITEM_MARGIN_RIGHT = 5; static const int ITEM_MARGIN_BOTTOM = 5; static const int ITEM_PADDING = 5; TableDelegate::TableDelegate() { } void TableDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QBrush backBrush; QColor foreColor; bool disabled = false; bool hover = false; if (!(option.state & QStyle::State_Enabled)) { backBrush = option.palette.brush(QPalette::Disabled, QPalette::Base); foreColor = option.palette.color(QPalette::Disabled, QPalette::Text); disabled = true; // Since the TimeLine doesnt allow selectable items, because you dont actually "are" on a given savepoint, // we dont actually need this chek. /*} else if (option.state & (QStyle::State_HasFocus | QStyle::State_Selected)) { backBrush = option.palette.brush(QPalette::Highlight); foreColor = option.palette.color(QPalette::HighlightedText);*/ } else if (option.state & QStyle::State_MouseOver) { backBrush = option.palette.color(QPalette::Highlight).darker(); foreColor = option.palette.color(QPalette::Text); hover = true; } else { /*if ( option.state & QStyle::State_Enabled )*/ backBrush = option.palette.brush(QPalette::Base); foreColor = option.palette.color(QPalette::Text); } QStyle *style = QApplication::style(); QStyleOptionViewItemV4 opt(option); // KStyle provides an "hover highlight" effect for free; // but we want that for non-KStyle-based styles too if (!style->inherits("KStyle") && hover) { Qt::BrushStyle bs = opt.backgroundBrush.style(); if (bs > Qt::NoBrush && bs < Qt::TexturePattern) opt.backgroundBrush = opt.backgroundBrush.color().light(115); else opt.backgroundBrush = backBrush; } painter->save(); style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, 0); painter->restore(); QIcon icon = index.data(Qt::DecorationRole).value< QIcon >(); if (!icon.isNull()) { QPoint iconpos( (option.rect.width() - option.decorationSize.width()) / 2, ITEM_MARGIN_TOP ); iconpos += option.rect.topLeft(); QIcon::Mode iconmode = disabled ? QIcon::Disabled : QIcon::Normal; painter->drawPixmap(iconpos, icon.pixmap(option.decorationSize, iconmode)); } QString text = index.data(Qt::DisplayRole).toString(); QRect fontBoundaries = QFontMetrics(option.font).boundingRect(text); + fontBoundaries.setWidth(fontBoundaries.width() + ITEM_PADDING); QPoint textPos( ITEM_MARGIN_LEFT + (option.rect.width() - ITEM_MARGIN_LEFT - ITEM_MARGIN_RIGHT - fontBoundaries.width()) / 2, ITEM_MARGIN_TOP + option.decorationSize.height() + ITEM_PADDING ); fontBoundaries.translate(-fontBoundaries.topLeft()); fontBoundaries.translate(textPos); fontBoundaries.translate(option.rect.topLeft()); painter->setPen(foreColor); painter->drawText(fontBoundaries, Qt::AlignCenter, text); } QSize TableDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { QSize baseSize(option.decorationSize.width(), option.decorationSize.height()); QRect fontBoundaries = QFontMetrics(option.font).boundingRect(index.data(Qt::DisplayRole).toString()); baseSize.setWidth(qMax(fontBoundaries.width(), baseSize.width())); baseSize.setHeight(baseSize.height() + fontBoundaries.height() + 2*ITEM_PADDING); return baseSize += QSize(ITEM_MARGIN_LEFT + ITEM_MARGIN_RIGHT, ITEM_MARGIN_TOP + ITEM_MARGIN_BOTTOM); } diff --git a/sidebar.cpp b/sidebar.cpp index 629ff54..7b7be7a 100644 --- a/sidebar.cpp +++ b/sidebar.cpp @@ -1,177 +1,162 @@ -/*************************************************************************** - * Copyright (C) 2007 by Pino Toscano * - * * - * 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. * - ***************************************************************************/ - - - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -// #include "settings.h" +/**************************************************************************** + * Copyright (C) 2007 by Diego [Po]lentino Casella * + * * + * 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. * + ****************************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include + +//#include -#include "sidebaritem.cpp" -#include "sidebardelegate.h" -#include "sidebarlistwidget.h" -#include "sidebarprivatestorage.h" #include "sidebar.h" +#include "sidebartablewidget.h" +#include "sidebardelegate.h" +#include "sidebaritem.cpp" - -Sidebar::Sidebar(QWidget *parent) - : QWidget(parent), d(new SidebarPrivateStorage) +Sidebar::Sidebar(QWidget *parent, Qt::DockWidgetArea location) + :QDockWidget(i18n("Workflow")) { - QHBoxLayout *mainlay = new QHBoxLayout(this); - mainlay->setMargin(0); - mainlay->setSpacing(0); - - d->list = new SidebarListWidget(this); - mainlay->addWidget(d->list); - d->list->setMouseTracking(true); - d->list->viewport()->setAttribute(Qt::WA_Hover); - d->sideDelegate = new SidebarDelegate(d->list); -// d->sideDelegate->setShowText( Okular::Settings::sidebarShowText() ); - d->list->setItemDelegate(d->sideDelegate); - d->list->setUniformItemSizes(true); - d->list->setSelectionMode(QAbstractItemView::SingleSelection); - int iconsize = 32;// Okular::Settings::sidebarIconSize(); - d->list->setIconSize(QSize(iconsize, iconsize)); - d->list->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - d->list->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - d->list->setContextMenuPolicy(Qt::CustomContextMenu); - d->list->viewport()->setAutoFillBackground(false); - - d->splitter = new QSplitter(this); - mainlay->addWidget(d->splitter); - d->splitter->setOpaqueResize(true); - d->splitter->setChildrenCollapsible(false); - - d->sideContainer = new QWidget(d->splitter); - d->sideContainer->setMinimumWidth(90); - d->sideContainer->setMaximumWidth(600); - d->vlay = new QVBoxLayout(d->sideContainer); - d->vlay->setMargin(0); - - d->sideTitle = new QLabel(d->sideContainer); - d->vlay->addWidget(d->sideTitle); - QFont tf = d->sideTitle->font(); - tf.setBold(true); - d->sideTitle->setFont(tf); - d->sideTitle->setMargin(3); - d->sideTitle->setIndent(3); - - d->stack = new QStackedWidget(d->sideContainer); - d->vlay->addWidget(d->stack); - d->sideContainer->hide(); - - connect(d->list, SIGNAL(clicked(const QModelIndex &)), + Q_UNUSED(parent) + + setFeatures(QDockWidget::AllDockWidgetFeatures); + m_table = new SidebarTableWidget(location); + m_table->setParent(this); + setWidget(m_table); + + m_delegate = new SidebarDelegate(); + m_table->setItemDelegate(m_delegate); + + connect(m_table, SIGNAL(clicked(const QModelIndex &)), this, SIGNAL(currentIndexClicked(const QModelIndex &))); + connect(this, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), + m_table,SLOT(updateLayout(Qt::DockWidgetArea))); + } Sidebar::~Sidebar() { - delete d; + //delete d; } -int Sidebar::addItem(const QIcon &icon, const QString &text) +Qt::DockWidgetArea Sidebar::location() { - SidebarItem *newitem = new SidebarItem(icon, text); - d->list->addItem(newitem); - d->pages.append(newitem); - // updating the minimum height of the icon view, so all are visible with no scrolling - d->adjustListSize(false, true); - return d->pages.count() - 1; + return m_table->location(); } -void Sidebar::setItemEnabled(int index, bool enabled) +void Sidebar::resizeEvent(QResizeEvent * event) { - if (index < 0 || index >= d->pages.count()) - return; - - Qt::ItemFlags f = d->pages.at(index)->flags(); - if (enabled) { - f |= Qt::ItemIsEnabled; - f |= Qt::ItemIsSelectable; + /* + I've reimplemented this event handler because, when resizing the main widget to a size + smaller than the dockwidget, a bothersome effects appears. According with the orientation, + it appears a scrollbar INSIDE the m_table widget, which hovers partially the icons when + the dock is vertical, and hovers completely the text when it is horizontal. + So I've implemented this simple workaround, in order to expand the dockwidget when a + scrollbar is shown. + I know that resizing a child widget inside a parent resizeEvent() is dangerous at 98%, + by the way this trick is very simple and well structured, so it wont cause issues I hope =) + */ + + QSize newSize = event->size(); + //qDebug() << "New size: " << newSize; + //qDebug() << "m_table size:" << m_table->size(); + //qDebug() << "m_table total lenght" << m_table->totalLenght(); + + bool vertical = ((m_table->location() == Qt::RightDockWidgetArea) || + (m_table->location() == Qt::LeftDockWidgetArea)); + + if(vertical) { + if(m_table->totalLenght() > newSize.height()) { + m_table->setFixedWidth(m_table->columnWidth(0) + m_table->scrollbarSize(vertical).width()); + return; + } else { + if(m_table->columnWidth(0) < newSize.width()) { + m_table->setFixedWidth(m_table->columnWidth(0)); + return; + } + } } else { - f &= ~Qt::ItemIsEnabled; - f &= ~Qt::ItemIsSelectable; - } - d->pages.at(index)->setFlags(f); - - if (!enabled && index == currentIndex()) - // find an enabled item, and select that one - for (int i = 0; i < d->pages.count(); ++i) - if (d->pages.at(i)->flags() & Qt::ItemIsEnabled) { - setCurrentIndex(i); - break; + if(m_table->totalLenght() > newSize.width()) { + m_table->setFixedHeight(m_table->rowHeight(0) + m_table->scrollbarSize(vertical).height()); + return; + } else { + if(m_table->rowHeight(0) < newSize.height()) { + m_table->setFixedHeight(m_table->rowHeight(0)); + return; } + } + } +} + +void Sidebar::addItem(const QIcon &icon, const QString &text) +{ + SidebarItem *newItem = new SidebarItem(icon, text); + m_table->addItem(newItem); +} + +bool Sidebar::isVertical() +{ + return ((m_table->location() == Qt::LeftDockWidgetArea)||(m_table->location() == Qt::RightDockWidgetArea)); } bool Sidebar::isItemEnabled(int index) const { - if (index < 0 || index >= d->pages.count()) + /*if (index < 0 || index >= d->pages.count()) return false; Qt::ItemFlags f = d->pages.at(index)->flags(); - return (f & Qt::ItemIsEnabled) == Qt::ItemIsEnabled; + return (f & Qt::ItemIsEnabled) == Qt::ItemIsEnabled;*/ + return true; } void Sidebar::setCurrentIndex(int index) { - if (index < 0 || index >= d->pages.count() || !isItemEnabled(index)) - return; - - QModelIndex modelindex = d->list->model()->index(index, 0); - d->list->setCurrentIndex(modelindex); - d->list->selectionModel()->select(modelindex, QItemSelectionModel::ClearAndSelect); + /*if (index < 0 || index >= d->pages.count() || !isItemEnabled(index)) + return;*/ + bool vertical = ((m_table->location() == Qt::LeftDockWidgetArea)|| + (m_table->location() == Qt::RightDockWidgetArea)); + + QModelIndex modelindex = m_table->model()->index(vertical? 0: index, + vertical? index: 0); + m_table->setCurrentIndex(modelindex); + m_table->selectionModel()->select(modelindex, QItemSelectionModel::ClearAndSelect); } int Sidebar::currentIndex() const { - return d->list->currentRow(); + return m_table->currentRow(); } void Sidebar::setSidebarVisibility(bool visible) { - if (visible != d->list->isHidden()) + if (visible != m_table->isHidden()) return; - static bool sideWasVisible = !d->sideContainer->isHidden(); + static bool sideWasVisible = !isHidden(); - d->list->setHidden(!visible); + m_table->setHidden(!visible); if (visible) { - d->sideContainer->setHidden(!sideWasVisible); + setHidden(!sideWasVisible); sideWasVisible = true; } else { - sideWasVisible = !d->sideContainer->isHidden(); - d->sideContainer->setHidden(true); + sideWasVisible = !isHidden(); + setHidden(true); } } bool Sidebar::isSidebarVisible() const { - return !d->sideContainer->isHidden(); + return !isHidden(); } #include "sidebar.moc" diff --git a/sidebar.h b/sidebar.h index 466cdee..b707661 100644 --- a/sidebar.h +++ b/sidebar.h @@ -1,46 +1,53 @@ /*************************************************************************** * Copyright (C) 2007 by Pino Toscano * * * * 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. * ***************************************************************************/ #ifndef _SIDEBAR_H_ #define _SIDEBAR_H_ -#include +#include class QIcon; +class SidebarTableWidget; +class SidebarDelegate; -#include "sidebarprivatestorage.h" - -class Sidebar : public QWidget +class Sidebar : public QDockWidget { Q_OBJECT public: - Sidebar(QWidget *parent = 0); + Sidebar(QWidget *parent = 0, + Qt::DockWidgetArea location = Qt::TopDockWidgetArea); ~Sidebar(); - int addItem(const QIcon &icon, const QString &text); + Qt::DockWidgetArea location(); + void addItem(const QIcon &icon, const QString &text); - void setItemEnabled(int index, bool enabled); bool isItemEnabled(int index) const; void setCurrentIndex(int index); int currentIndex() const; void setSidebarVisibility(bool visible); bool isSidebarVisible() const; + bool isVertical(); + signals: void currentIndexClicked(const QModelIndex &item); +protected: + void resizeEvent(QResizeEvent * event); + private: void saveSplitterSize() const; - SidebarPrivateStorage *d; + SidebarTableWidget *m_table; + SidebarDelegate *m_delegate; }; #endif diff --git a/sidebardelegate.cpp b/sidebardelegate.cpp index 730c182..25cfbd8 100644 --- a/sidebardelegate.cpp +++ b/sidebardelegate.cpp @@ -1,119 +1,120 @@ /*************************************************************************** * Copyright (C) 2007 by Pino Toscano * * * * 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. * ***************************************************************************/ // Stolen from okular :-) #include #include #include #include #include #include #include "sidebardelegate.h" /* A simple delegate to paint the icon of each item */ static const int ITEM_MARGIN_LEFT = 5; static const int ITEM_MARGIN_TOP = 5; static const int ITEM_MARGIN_RIGHT = 5; static const int ITEM_MARGIN_BOTTOM = 5; static const int ITEM_PADDING = 5; SidebarDelegate::SidebarDelegate(QObject *parent) : QAbstractItemDelegate(parent), m_showText(true) { } SidebarDelegate::~SidebarDelegate() { } void SidebarDelegate::setShowText(bool show) { m_showText = show; } bool SidebarDelegate::isTextShown() const { return m_showText; } void SidebarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QBrush backBrush; QColor foreColor; bool disabled = false; bool hover = false; if (!(option.state & QStyle::State_Enabled)) { backBrush = option.palette.brush(QPalette::Disabled, QPalette::Base); foreColor = option.palette.color(QPalette::Disabled, QPalette::Text); disabled = true; } else if (option.state & (QStyle::State_HasFocus | QStyle::State_Selected)) { backBrush = option.palette.brush(QPalette::Highlight); foreColor = option.palette.color(QPalette::HighlightedText); } else if (option.state & QStyle::State_MouseOver) { backBrush = option.palette.color(QPalette::Highlight).light(115); foreColor = option.palette.color(QPalette::HighlightedText); hover = true; } else { /*if ( option.state & QStyle::State_Enabled )*/ backBrush = option.palette.brush(QPalette::Base); foreColor = option.palette.color(QPalette::Text); } QStyle *style = QApplication::style(); QStyleOptionViewItemV4 opt(option); // KStyle provides an "hover highlight" effect for free; // but we want that for non-KStyle-based styles too if (!style->inherits("KStyle") && hover) { Qt::BrushStyle bs = opt.backgroundBrush.style(); if (bs > Qt::NoBrush && bs < Qt::TexturePattern) opt.backgroundBrush = opt.backgroundBrush.color().light(115); else opt.backgroundBrush = backBrush; } painter->save(); style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, 0); painter->restore(); QIcon icon = index.data(Qt::DecorationRole).value< QIcon >(); if (!icon.isNull()) { QPoint iconpos( (option.rect.width() - option.decorationSize.width()) / 2, ITEM_MARGIN_TOP ); iconpos += option.rect.topLeft(); QIcon::Mode iconmode = disabled ? QIcon::Disabled : QIcon::Normal; painter->drawPixmap(iconpos, icon.pixmap(option.decorationSize, iconmode)); } if (m_showText) { QString text = index.data(Qt::DisplayRole).toString(); QRect fontBoundaries = QFontMetrics(option.font).boundingRect(text); + fontBoundaries.setWidth(fontBoundaries.width() + ITEM_PADDING); QPoint textPos( ITEM_MARGIN_LEFT + (option.rect.width() - ITEM_MARGIN_LEFT - ITEM_MARGIN_RIGHT - fontBoundaries.width()) / 2, ITEM_MARGIN_TOP + option.decorationSize.height() + ITEM_PADDING ); fontBoundaries.translate(-fontBoundaries.topLeft()); fontBoundaries.translate(textPos); fontBoundaries.translate(option.rect.topLeft()); painter->setPen(foreColor); painter->drawText(fontBoundaries, Qt::AlignCenter, text); } } QSize SidebarDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { QSize baseSize(option.decorationSize.width(), option.decorationSize.height()); if (m_showText) { QRect fontBoundaries = QFontMetrics(option.font).boundingRect(index.data(Qt::DisplayRole).toString()); baseSize.setWidth(qMax(fontBoundaries.width(), baseSize.width())); baseSize.setHeight(baseSize.height() + fontBoundaries.height() + ITEM_PADDING); } return baseSize + QSize(ITEM_MARGIN_LEFT + ITEM_MARGIN_RIGHT, ITEM_MARGIN_TOP + ITEM_MARGIN_BOTTOM); } diff --git a/sidebaritem.cpp b/sidebaritem.cpp index 79ba63d..832f682 100644 --- a/sidebaritem.cpp +++ b/sidebaritem.cpp @@ -1,25 +1,25 @@ -#include +#include //#include "sidebaritem.h" #ifndef SIDEBARITEM_H #define SIDEBARITEM_H -static const int SidebarItemType = QListWidgetItem::UserType + 1; +static const int SidebarItemType = QTableWidgetItem::UserType + 1; /* List item representing a sidebar entry. */ -class SidebarItem : public QListWidgetItem +class SidebarItem : public QTableWidgetItem { public: SidebarItem(const QIcon &icon, const QString &text) - : QListWidgetItem(0, SidebarItemType) { + : QTableWidgetItem(0, SidebarItemType) { setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); setIcon(icon); setText(text); setToolTip(text); } }; #endif // SIDEBARITEM_H diff --git a/sidebarlistwidget.cpp b/sidebarlistwidget.cpp deleted file mode 100644 index 95255ce..0000000 --- a/sidebarlistwidget.cpp +++ /dev/null @@ -1,111 +0,0 @@ - -#include -#include -#include -#include -#include - -#include "sidebarlistwidget.h" - -SidebarListWidget::SidebarListWidget(QWidget *parent) - : QListWidget(parent) -{ -} - -SidebarListWidget::~SidebarListWidget() -{ -} - -void SidebarListWidget::mouseDoubleClickEvent(QMouseEvent *event) -{ - QModelIndex index = indexAt(event->pos()); - if (index.isValid() && !(index.flags() & Qt::ItemIsSelectable)) { - return; - } - - QListWidget::mouseDoubleClickEvent(event); -} - -void SidebarListWidget::mouseMoveEvent(QMouseEvent *event) -{ - QModelIndex index = indexAt(event->pos()); - if (index.isValid() && !(index.flags() & Qt::ItemIsSelectable)) { - return; - } - - QListWidget::mouseMoveEvent(event); -} - -void SidebarListWidget::mousePressEvent(QMouseEvent *event) -{ - QModelIndex index = indexAt(event->pos()); - if (index.isValid() && !(index.flags() & Qt::ItemIsSelectable)) { - return; - } - - QListWidget::mousePressEvent(event); -} - -void SidebarListWidget::mouseReleaseEvent(QMouseEvent *event) -{ - QModelIndex index = indexAt(event->pos()); - if (index.isValid() && !(index.flags() & Qt::ItemIsSelectable)) { - return; - } - - QListWidget::mouseReleaseEvent(event); -} - -QModelIndex SidebarListWidget::moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers) -{ - Q_UNUSED(modifiers) - QModelIndex oldindex = currentIndex(); - QModelIndex newindex = oldindex; - switch (cursorAction) { - case MoveUp: - case MovePrevious: { - int row = oldindex.row() - 1; - while (row > -1 && !(model()->index(row, 0).flags() & Qt::ItemIsSelectable)) --row; - if (row > -1) - newindex = model()->index(row, 0); - break; - } - case MoveDown: - case MoveNext: { - int row = oldindex.row() + 1; - int max = model()->rowCount(); - while (row < max && !(model()->index(row, 0).flags() & Qt::ItemIsSelectable)) ++row; - if (row < max) - newindex = model()->index(row, 0); - break; - } - case MoveHome: - case MovePageUp: { - int row = 0; - while (row < oldindex.row() && !(model()->index(row, 0).flags() & Qt::ItemIsSelectable)) ++row; - if (row < oldindex.row()) - newindex = model()->index(row, 0); - break; - } - case MoveEnd: - case MovePageDown: { - int row = model()->rowCount() - 1; - while (row > oldindex.row() && !(model()->index(row, 0).flags() & Qt::ItemIsSelectable)) --row; - if (row > oldindex.row()) - newindex = model()->index(row, 0); - break; - } - // no navigation possible for these - case MoveLeft: - case MoveRight: - break; - } - - // dirty hack to change item when the key cursor changes item - if (oldindex != newindex) { - emit itemClicked(itemFromIndex(newindex)); - } - - return newindex; -} - diff --git a/sidebarlistwidget.h b/sidebarlistwidget.h deleted file mode 100644 index 46e017f..0000000 --- a/sidebarlistwidget.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef SIDEBARLISTWIDGET_H -#define SIDEBARLISTWIDGET_H - -class SidebarListWidget : public QListWidget -{ -public: - SidebarListWidget(QWidget *parent = 0); - ~SidebarListWidget(); - -protected: - // from QListWidget - void mouseDoubleClickEvent(QMouseEvent *event); - void mouseMoveEvent(QMouseEvent *event); - void mousePressEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *event); - - QModelIndex moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers); -}; - -#endif // SIDEBARLISTWIDGET_H diff --git a/sidebarprivatestorage.cpp b/sidebarprivatestorage.cpp deleted file mode 100644 index fbcbeb1..0000000 --- a/sidebarprivatestorage.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include -#include -#include -#include -#include - - -#include "sidebaritem.cpp" -#include "sidebardelegate.h" -#include "sidebarlistwidget.h" -#include "sidebarprivatestorage.h" - - -SidebarPrivateStorage::SidebarPrivateStorage() - : sideWidget(0), bottomWidget(0), splitterSizesSet(false), - itemsHeight(0) -{ -} - -void SidebarPrivateStorage::adjustListSize(bool recalc, bool expand) -{ - QRect bottomElemRect( - QPoint(0, 0), - list->sizeHintForIndex(list->model()->index(list->count() - 1, 0)) - ); - if (recalc) { - int w = 0; - for (int i = 0; i < list->count(); ++i) { - QSize s = list->sizeHintForIndex(list->model()->index(i, 0)); - if (s.width() > w) - w = s.width(); - } - bottomElemRect.setWidth(w); - } - bottomElemRect.translate(0, bottomElemRect.height() *(list->count() - 1)); - itemsHeight = bottomElemRect.height() * list->count(); - list->setMinimumHeight(itemsHeight + list->frameWidth() * 2); - int curWidth = list->minimumWidth(); - int newWidth = expand - ? qMax(bottomElemRect.width() + list->frameWidth() * 2, curWidth) - : qMin(bottomElemRect.width() + list->frameWidth() * 2, curWidth); - list->setFixedWidth(newWidth); -} diff --git a/sidebarprivatestorage.h b/sidebarprivatestorage.h deleted file mode 100644 index 5a8e5e2..0000000 --- a/sidebarprivatestorage.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef SIDEBARPRIVATESTORAGE_H -#define SIDEBARPRIVATESTORAGE_H - -class SidebarItem; -class SidebarDelegate; -class SidebarListWidget; -class SidebarPrivateStorage; - - -class QSplitter; -class QStackedWidget; -class QStackedWidget; - -class SidebarPrivateStorage -{ -public: - SidebarPrivateStorage(); - - void adjustListSize(bool recalc, bool expand = true); - - SidebarListWidget *list; - QSplitter *splitter; - QStackedWidget *stack; - QWidget *sideContainer; - QLabel *sideTitle; - QVBoxLayout *vlay; - QWidget *sideWidget; - QWidget *bottomWidget; - QList< SidebarItem* > pages; - bool splitterSizesSet; - int itemsHeight; - SidebarDelegate *sideDelegate; - -}; - -#endif // SIDEBARPRIVATESTORAGE_H diff --git a/sidebartablewidget.cpp b/sidebartablewidget.cpp new file mode 100755 index 0000000..3f5ccaa --- /dev/null +++ b/sidebartablewidget.cpp @@ -0,0 +1,333 @@ +#include +#include +#include +#include +#include + +//#include + +#include "sidebartablewidget.h" +#include "sidebaritem.cpp" + +static const int ITEM_MARGIN_LEFT = 5; +static const int ITEM_MARGIN_TOP = 5; +static const int ITEM_MARGIN_RIGHT = 5; +static const int ITEM_MARGIN_BOTTOM = 5; +static const int ITEM_PADDING = 5; + + + +SidebarTableWidget::SidebarTableWidget(Qt::DockWidgetArea location, QWidget *parent) + : QTableWidget(0,0,parent), + m_horizontalSB(0), + m_verticalSB(0), + m_location(location), + m_maxCellDimension(0), + m_totalLenght(0) +{ + horizontalHeader()->setVisible(false); + verticalHeader()->setVisible(false); + setIconSize(QSize(32,32)); + setShowGrid(false); + setMouseTracking(true); + viewport()->setAutoFillBackground(false); + setSelectionMode(QAbstractItemView::SingleSelection); + + m_horizontalSB = horizontalScrollBar(); + m_verticalSB = verticalScrollBar(); + setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); +} + +SidebarTableWidget::~SidebarTableWidget() +{ +} + +Qt::DockWidgetArea SidebarTableWidget::location() +{ + return m_location; +} + +void SidebarTableWidget::updateLayout(Qt::DockWidgetArea location) +{ + bool wasVertical = true; + + // Ensure we REALLY need to update the layout + switch(location) { + case Qt::LeftDockWidgetArea: + if((m_location == Qt::LeftDockWidgetArea)|| + (m_location == Qt::RightDockWidgetArea)) { + return; + } + wasVertical = false; + break; + + case Qt::RightDockWidgetArea: + if((m_location == Qt::LeftDockWidgetArea)|| + (m_location == Qt::RightDockWidgetArea)) { + return; + } + wasVertical = false; + break; + + case Qt::TopDockWidgetArea: + if((m_location == Qt::TopDockWidgetArea)|| + (m_location == Qt::BottomDockWidgetArea)) { + return; + } + break; + + case Qt::BottomDockWidgetArea: + if((m_location == Qt::TopDockWidgetArea)|| + (m_location == Qt::BottomDockWidgetArea)) { + return; + } + break; + + default: + return; + } + // Before starting swapping, hide the table for a while to avoid flickering and reset + // minimum and maximum widget size; + hide(); + + // Store the current position + m_location = location; + + // Compute the number of required iterations + int iterations = (wasVertical ? rowCount() : columnCount()); + + if(wasVertical) { + setColumnCount(iterations); + } else { + setRowCount(iterations); + } + + m_maxCellDimension = 0; + m_totalLenght = 0; + + // Save position of the selected item, if exists + int position = 0; + QTableWidgetItem *it = currentItem(); + if(it) { + position = (wasVertical ? it->row() : it->column()); + } + + for(int i=0; isize() : m_horizontalSB->size()); +} + +void SidebarTableWidget::addItem(SidebarItem *item) +{ + // According with the orientation, expand the widget through the first column or row, + // then add the item. + setRowCount(((m_location == Qt::RightDockWidgetArea)||(m_location == Qt::LeftDockWidgetArea)) ? + rowCount()+1 : 1); + setColumnCount(((m_location == Qt::RightDockWidgetArea)||(m_location == Qt::LeftDockWidgetArea)) ? + 1 : columnCount()+1); + + setItem(((m_location == Qt::RightDockWidgetArea)||(m_location == Qt::LeftDockWidgetArea)) ? + rowCount()-1 : 0, + ((m_location == Qt::RightDockWidgetArea)||(m_location == Qt::LeftDockWidgetArea)) ? + 0 : columnCount()-1, + item); + + updateSize(item); +} + +int SidebarTableWidget::totalLenght() +{ + return m_totalLenght; +} + +void SidebarTableWidget::clear() +{ + bool vertical = ((m_location == Qt::RightDockWidgetArea)||(m_location == Qt::LeftDockWidgetArea)); + for(int i = 0; i < (vertical ? rowCount(): columnCount()); ++i ) { + takeItem(vertical ? i: 0, + vertical ? 0: i); + } + setRowCount(0); + setColumnCount(0); + + m_maxCellDimension = 0; + m_totalLenght = 0; +} + +/*void SidebarTableWidget::mouseReleaseEvent(QMouseEvent *event) +{ + QModelIndex index = indexAt(event->pos()); + if (!index.isValid()) + return; + if (event->button() == Qt::RightButton) { + emit itemClicked(itemFromIndex(index)); + } +}*/ + +void SidebarTableWidget::updateSize(SidebarItem *item) +{ + // Now compute the correct row and column size for the current item + QFontMetrics font(item->font()); + QSize rect(ITEM_MARGIN_LEFT + qMax(iconSize().width(), font.width(item->text() + 2*ITEM_PADDING)) + ITEM_MARGIN_RIGHT, + ITEM_MARGIN_TOP + iconSize().height() + ITEM_PADDING + + font.boundingRect(item->text()).height() + 2*ITEM_MARGIN_BOTTOM ); + + + //qDebug() << "SidebarTableWidget::updateSize = " << rect; + + if((m_location == Qt::RightDockWidgetArea) || (m_location == Qt::LeftDockWidgetArea)) { + setRowHeight(item->row(),rect.height()); + m_totalLenght += rect.height(); + + if(m_maxCellDimension < rect.width()) { + m_maxCellDimension = rect.width(); + setColumnWidth(1,m_maxCellDimension); + } + setMinimumHeight(0); + setMaximumHeight(16777215); + setColumnWidth(1,m_maxCellDimension); + setColumnWidth(0,m_maxCellDimension); + setMinimumWidth(m_maxCellDimension+5); + setMaximumWidth(m_maxCellDimension+5); + + } else { + setColumnWidth(item->column(),rect.width()); + m_totalLenght += rect.width(); + + if(m_maxCellDimension < rect.height()) { + m_maxCellDimension = rect.height(); + setRowHeight(1,m_maxCellDimension); + } + setMinimumWidth(0); + setMaximumWidth(16777215); + setRowHeight(1,m_maxCellDimension); + setRowHeight(0,m_maxCellDimension); + setMinimumHeight(m_maxCellDimension+5); + setMaximumHeight(m_maxCellDimension+5); + } +} + + +void SidebarTableWidget::mouseDoubleClickEvent(QMouseEvent *event) +{ + QModelIndex index = indexAt(event->pos()); + if (index.isValid() && !(index.flags() & Qt::ItemIsSelectable)) { + return; + } + + QTableWidget::mouseDoubleClickEvent(event); +} + +void SidebarTableWidget::mouseMoveEvent(QMouseEvent *event) +{ + QModelIndex index = indexAt(event->pos()); + if (index.isValid() && !(index.flags() & Qt::ItemIsSelectable)) { + return; + } + + QTableWidget::mouseMoveEvent(event); +} + +void SidebarTableWidget::mousePressEvent(QMouseEvent *event) +{ + QModelIndex index = indexAt(event->pos()); + if (index.isValid() && !(index.flags() & Qt::ItemIsSelectable)) { + return; + } + + QTableWidget::mousePressEvent(event); +} + +void SidebarTableWidget::mouseReleaseEvent(QMouseEvent *event) +{ + QModelIndex index = indexAt(event->pos()); + if (index.isValid() && !(index.flags() & Qt::ItemIsSelectable)) { + return; + } + + QTableWidget::mouseReleaseEvent(event); +} + +QModelIndex SidebarTableWidget::moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers) +{ + Q_UNUSED(modifiers) + QModelIndex oldindex = currentIndex(); + QModelIndex newindex = oldindex; + switch (cursorAction) { + case MoveUp: + case MovePrevious: { + int row = oldindex.row() - 1; + while (row > -1 && !(model()->index(row, 0).flags() & Qt::ItemIsSelectable)) --row; + if (row > -1) + newindex = model()->index(row, 0); + break; + } + case MoveDown: + case MoveNext: { + int row = oldindex.row() + 1; + int max = model()->rowCount(); + while (row < max && !(model()->index(row, 0).flags() & Qt::ItemIsSelectable)) ++row; + if (row < max) + newindex = model()->index(row, 0); + break; + } + case MoveHome: + case MovePageUp: { + int row = 0; + while (row < oldindex.row() && !(model()->index(row, 0).flags() & Qt::ItemIsSelectable)) ++row; + if (row < oldindex.row()) + newindex = model()->index(row, 0); + break; + } + case MoveEnd: + case MovePageDown: { + int row = model()->rowCount() - 1; + while (row > oldindex.row() && !(model()->index(row, 0).flags() & Qt::ItemIsSelectable)) --row; + if (row > oldindex.row()) + newindex = model()->index(row, 0); + break; + } + // no navigation possible for these + case MoveLeft: + case MoveRight: + break; + } + + // dirty hack to change item when the key cursor changes item + if (oldindex != newindex) { + emit itemClicked(itemFromIndex(newindex)); + } + + return newindex; +} + diff --git a/sidebartablewidget.h b/sidebartablewidget.h new file mode 100755 index 0000000..b65e7cb --- /dev/null +++ b/sidebartablewidget.h @@ -0,0 +1,48 @@ +#ifndef SIDEBARTABLEWIDGET_H +#define SIDEBARTABLEWIDGET_H + +#include +class SidebarItem; + +class SidebarTableWidget : public QTableWidget +{ + Q_OBJECT + +public: + SidebarTableWidget(Qt::DockWidgetArea location, QWidget *parent = 0); + ~SidebarTableWidget(); + + void addItem(SidebarItem *item); + void clear(); + QSize scrollbarSize(bool vertical); + Qt::DockWidgetArea location(); + int totalLenght(); + +public Q_SLOTS: + void updateLayout(Qt::DockWidgetArea location); + +protected: + private: + void updateSize(SidebarItem *item); + void mouseReleaseEvent(QMouseEvent *event); + + QScrollBar *m_horizontalSB; + QScrollBar *m_verticalSB; + Qt::DockWidgetArea m_location; + + // Max Cell Dimension: according with its position, could be a width or height + int m_maxCellDimension; + + // Total Length: stores the width/height of the entire row/column + int m_totalLenght; + + // from QTableWidget + void mouseDoubleClickEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mousePressEvent(QMouseEvent *event); + //void mouseReleaseEvent(QMouseEvent *event); + + QModelIndex moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers); +}; + +#endif // SIDEBARTABLEWIDGET_H