Files
qt-creator/doc/pluginhowto/mode.qdoc
Felix Geyer ea9b7fb5e5 On unix: install the application icons according to the freedesktop spec.
This allows desktop environments to pick the right icon size when displaying
the Qt Creator menu entry.

Change-Id: I10f6b46fb99202571d081a5e6e4d680be7ca069f
Merge-request: 328
Reviewed-by: Daniel Molkentin <daniel.molkentin@nokia.com>
Reviewed-on: http://codereview.qt.nokia.com/64
2011-05-23 12:56:18 +02:00

538 lines
16 KiB
Plaintext

/*!
\page mode.html
\title 13. Adding a mode
When we are working in Qt Creator then we in one of the six modes below.
\list
\o Welcome
\o Edit
\o Debug
\o Project
\o Help
\o Output
\endlist
By selecting different modes in Qt creator we can quickly switch between different task spaces, such
as editing, browsing the Qt Creator manual, setting up the build environment, etc.
Different modes can be selected either by clicking on the mode selectors or through keyboard shortcuts.
The following figure shows the mode selectors in the Qt Creator.
\inlineimage qtc-modes-13.png
Now in this chapter we are concerned about learning to add a new mode and a "LoggerMode" mode selector will be availble in Qt Creator.
\section1 13.1 Core Classes and Interfaces
To support a new mode we need to
\list
\o Implement a plugin \bold {(ExtensionSystem::IPlugin } implementation) class that exposes the new mode.Chapter 2 in this
document provides a detailed description on creating plugins by implementing the ExtensionSystem::IPlugin interface.
\o Implement the \bold{(Core::IMode)} interface. This interface allows us to add a new mode in Qt creator
\endlist
\section2 Step 1. Core::IMode interface
This interface abstracts the creation of a mode, adding an icon to the mode selector, setting the mode priority,
setting a unique made name. The \bold {Core::IMode} interface is declared as follows in scr/plugins/coreplugin/imode.h
\code
namespace Core {
class CORE_EXPORT IMode : public IContext
{
Q_OBJECT
public:
IMode(QObject *parent = 0) : IContext(parent) {}
virtual ~IMode() {}
virtual QString name() const = 0;
virtual QIcon icon() const = 0;
virtual int priority() const = 0;
virtual const char *uniqueModeName() const = 0;
};
} // namespace Core
\endcode
Notice that Core::IMode inherits Core::IContext. Core::IContext is an interface through which
Qt Creator picks up the widget corresponding to the mode. The Core::IContext interface is declared
as follows.
\code
namespace Core
{
class CORE_EXPORT IContext : public QObject
{
Q_OBJECT
public:
IContext(QObject *parent = 0) : QObject(parent) {}
virtual ~IContext() {}
virtual QList<int> context() const = 0;
virtual QWidget *widget() = 0;
virtual QString contextHelpId() const { return QString(); }
};
}
\endcode
\section1 13.2 Adding a new mode
Lets add a mode to Qt Creator called "LoggerMode". LoggerMode allows the user (developer) to log the number of hours he/she
has worked on a project. The following steps explain how the new mode "LoggerMode" is added.
\section2 Step 1. Declaring the LoggerMode class
We first begin by declaring a class called LoggerMode that implements the Core::IMode interface.
The class definition is as follows.
\code
#include <coreplugin/imode.h>
struct LoggerModeData;
class LoggerMode : public Core::IMode
{
Q_OBJECT
public:
LoggerMode();
~LoggerMode();
QString name() const;
QIcon icon() const;
int priority() const;
QWidget *widget();
const char *uniqueModeName() const;
QList<int> context() const;
void activated();
QString contextHelpId() const { return QLatin1String("Qt Creator"); }
private:
LoggerModeData *d;
};
\endcode
\section2 Step 2. Implementing the LoggerMode class
Declaring the private variables of the LoggerMode class.
\code
struct LoggerModeData
{
QWidget *m_widget;
};
\endcode
The constructor creates a new blank widget just for now to get started with the mode.
The constructor and the destructor are implemented as follows
\code
LoggerMode::LoggerMode()
{
d = new LoggerModeData;
d->m_widget = new QWidget;
}
LoggerMode::~LoggerMode()
{
delete d->m_widget;
delete d;
}
\endcode
The \bold {name()} method returns a name for the new mode selector.
\code
QString LoggerMode::name() const
{
return tr("LoggerMode");
}
\endcode
The \bold {icon()} method returns a logo for the new mode selector.
\code
QIcon LoggerMode::icon() const
{
return QIcon(QLatin1String(":/core/images/logo/32/qtcreator.png"));
}
\endcode
The \bold {priority()} method is implemented to return a priority for the mode. Modes of higher
priority are shown above modes of lower priority. The highest priority in Qt Creator is currently
100 and is associated with the Welcome mode. We return 0 from LoggerMode, becasue we want this
mode to appear at the end.
\code
int LoggerMode::priority() const
{
return 0;
}
\endcode
Thw \bold {widget()} method returns a widget to the new mode.
\code
QWidget* LoggerMode::widget()
{
return d->m_widget;
}
\endcode
The \bold {uniqueModeName()} returns the name of the mode to the "LoggerMode" Class.
\code
const char* LoggerMode::uniqueModeName() const
{
return "LoggerMode" ;
}
\endcode
The \bold {context()} method returns an empty list of integers to tne "LoggerMode" class.
\code
QList<int> LoggerMode::context() const
{
return QList<int>();
}
\endcode
\section2 Step 3. Implementing the "LoggerMode" plugin
We implement the "LoggerMode" plugin very similar to the DoNothingPlugin class described in Chapter 2.
Here we only look at the implementation of the initialize() method.
\code
bool LoggerModePlugin::initialize(const QStringList& args, QString *errMsg)
{
Q_UNUSED(args);
Q_UNUSED(errMsg);
loggerMode = new LoggerMode;
addAutoReleasedObject(loggerMode);
return true;
}
\endcode
\section2 Step 4. Testing the plugin.
Upon compiling the plugin and restarting Qt Creator, we can notice the "LoggerMode" mode selector in the Qt creator.
\inlineimage qtc-loggermode-13.png
\section1 13.3 Adding Functionality to the "LoggerMode"
The actual function of the "LoggerMode" is to log data in a text file about a project, such as progress , hours worked,
description etc.
\section2 Step 1. Modifying the "LoggerMode" Class
To add the functionalities, the LoggerMode class is further modified.
The code block is given as follows.
\code
struct LoggerModeData;
class LoggerMode :public Core::IMode
{
Q_OBJECT
public:
LoggerMode();
~LoggerMode();
...
...
protected slots:
void addNewStackWidgetPage(const QString projectName);
void addItem();
private:
...
};
\endcode
The constructor of the \bold {LoggerMode} class is modified as follows.
\code
LoggerMode::LoggerMode()
{
d = new LoggerModeData;
d->m_widget = new QWidget;
//Current Projects Label and combobox widget are created.
d->currentProjectsLabel = new QLabel("Current projects :");
d->currentProjectsLabel->setFixedWidth(90);
d->currentProjectsCombobox = new QComboBox;
d->currentProjectsCombobox->setSizePolicy(QSizePolicy::Preferred,
QSizePolicy::Preferred);
//Add Projects Label and combobox widget are created.
d->addProjectLabel = new QLabel("Add Project :");
d->addProjectLabel->setAlignment(Qt::AlignRight);
d->addProjectComboBox = new QComboBox;
d->addProjectComboBox->setSizePolicy(QSizePolicy::Preferred,
QSizePolicy::Preferred);
d->addProjectComboBox->setEditable(true);
d->addToProjectButton = new QPushButton(tr("Add Project"));
d->addToProjectButton->setFixedWidth(80);
//Creating a horizontal Layout
QHBoxLayout *hLayout = new QHBoxLayout;
hLayout->addWidget(d->currentProjectsLabel);
hLayout->addWidget(d->currentProjectsCombobox);
hLayout->addWidget(d->addProjectLabel);
hLayout->addWidget(d->addProjectComboBox);
hLayout->addWidget(d->addToProjectButton);
//creating a stackedWidget
d->stackedWidget = new QStackedWidget;
//creating a vertical layout
QVBoxLayout* layout = new QVBoxLayout;
layout->addLayout(hLayout);
layout->addWidget(d->stackedWidget);
d->m_widget->setLayout(layout);
d->addProjectComboBox->addItem("Project 1");
d->addProjectComboBox->addItem("Project 2");
d->addProjectComboBox->addItem("Project 3");
connect(d->addToProjectButton,SIGNAL(clicked()),
this,SLOT(addItem()));
connect(d->currentProjectsCombobox, SIGNAL(currentIndexChanged(int)),
d->stackedWidget, SLOT(setCurrentIndex(int)));
}
\endcode
Implementation of the \bold{addNewStackWidgetPage()} slot of \bold {LoggerMode} class
\code
void LoggerMode::addNewStackWidgetPage(const QString projectName)
{
d->stackedWidget->addWidget(new LoggerModeWidget(projectName));
}
\endcode
Implementation of the \bold{addItem()} slot of \bold {LoggerMode} class
\code
void LoggerMode::addItem()
{
d->currentProjectsCombobox->addItem(d->addProjectComboBox->currentText());
addNewStackWidgetPage(d->currentProjectsCombobox->itemText(0));
}
\endcode
The effect of the above block of code can be seen in the following image.
\inlineimage qtc-loggerpage-13.png
\section2 Step 2. Declaration of the "LoggerModeWidget" class
Reffering to the above image, when ever we select a project from the \bold {Add Project} combobox and click
\bold {Add Project} button a new project is added to the \bold {Current projects} list and and a corresponding
\bold {LoggerModeWidget} is opened, for logging different informations about the project.
The declaration of the \bold {LoggerModeWidget} class is shown in the following code block.
\code
#include <QWidget>
struct LoggerModeWidgetData;
class LoggerModeWidget : public QWidget
{
Q_OBJECT
public:
LoggerModeWidget(const QString projectName, QWidget* parent = 0);
~LoggerModeWidget();
public slots:
void setProjectName(QString name);
protected slots:
bool saveToFile();
void startTimeLog();
void endTimeLog();
void updateTime();
private:
LoggerModeWidgetData* d;
};
\endcode
\section2 Step 3. Implementing the "LoggerModeWidget" class
Declaring the private member variables in the structure called \bold {LoggerModeWidgetData}
\code
struct LoggerModeWidgetData
{
QLabel *progressLabel;
QLabel *hoursWorkedLabel;
QLabel *dateLabel;
QLabel *descriptionLabel;
QCalendarWidget *calendar;
QComboBox *progressComboBox;
QLineEdit *hoursWorkedLineEdit;
QPushButton *startTimerButton;
QPushButton *stopTimerButton;
QPushButton *saveButton;
QTimer *timer;
QTextEdit *textEdit;
QString projectName;
int totalTime;
};
\endcode
Implementation of the constructor and destructor of the \bold {LoggerModeWidget} class
\code
LoggerModeWidget::LoggerModeWidget(const QString projectName, QWidget* parent)
:QWidget(parent)
{
d = new LoggerModeWidgetData;
d->projectName = projectName;
d->totalTime = 0;
QStringList percentList;
percentList <<"10%" <<"20%" <<"30%" <<"40%" <<"50%"
<<"60%" <<"70%" <<"80%" <<"90%" <<"100%" ;
d->progressLabel = new QLabel("Progress:");
d->hoursWorkedLabel = new QLabel("Hours Worked:");
d->dateLabel = new QLabel("Date:");
d->descriptionLabel = new QLabel("Description :");
d->hoursWorkedLineEdit = new QLineEdit;
d->hoursWorkedLineEdit->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
d->progressComboBox = new QComboBox;
d->progressComboBox->addItems(percentList);
d->progressComboBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
d->startTimerButton = new QPushButton(tr("Start Timer"));
d->startTimerButton->setFixedWidth(80);
d->stopTimerButton = new QPushButton(tr("Pause Timer"));
d->stopTimerButton->setFixedWidth(80);
d->stopTimerButton->setCheckable(true);
d->textEdit = new QTextEdit(this);
d->textEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
d->calendar = new QCalendarWidget;
d->saveButton = new QPushButton(tr("Save To File"));
d->saveButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
QGroupBox *timeLoggerBox = new QGroupBox(tr("Time Logger"));
QGridLayout *gLayout = new QGridLayout;
gLayout->addWidget(d->dateLabel, 0, 0, 1, 1);
gLayout->addWidget(d->calendar, 1, 0, 1, 3);
gLayout->addWidget(d->progressLabel, 2, 0, 1, 1);
gLayout->addWidget(d->progressComboBox, 2, 1, 1, 1);
gLayout->addWidget(d->hoursWorkedLabel, 3, 0, 1, 1);
gLayout->addWidget(d->hoursWorkedLineEdit, 3, 1, 1, 1);
gLayout->addWidget(d->startTimerButton, 4, 1, 1, 1);
gLayout->addWidget(d->stopTimerButton, 4, 2, 1, 1);
timeLoggerBox->setLayout(gLayout);
d->timer = new QTimer(this);
// connection of SIGNALS and SLOTS
connect(d->timer, SIGNAL(timeout()), this, SLOT(updateTime()));
connect(d->startTimerButton,SIGNAL(clicked()),this,SLOT(startTimeLog()));
connect(d->stopTimerButton,SIGNAL(clicked()),this,SLOT(endTimeLog()));
connect(d->saveButton, SIGNAL(clicked()), this, SLOT(saveToFile()));
QVBoxLayout *vLayout = new QVBoxLayout;
vLayout->addWidget(d->descriptionLabel);
vLayout->addWidget(d->textEdit);
QHBoxLayout * hLayout = new QHBoxLayout;
hLayout->addWidget(timeLoggerBox);
hLayout->addLayout(vLayout);
QHBoxLayout *bLayout = new QHBoxLayout;
bLayout->addStretch(1);
bLayout->addWidget(d->saveButton);
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->addLayout(hLayout);
mainLayout->addLayout(bLayout);
mainLayout->addStretch(1);
}
LoggerModeWidget::~LoggerModeWidget()
{
delete d;
}
\endcode
The \bold {saveToFile()} slot is used by the "SaveTofile" button to save the contents of the "LoggerModeWidget" to a
text file.
\code
bool LoggerModeWidget::saveToFile()
{
QString fileName = QFileDialog::getSaveFileName(this);
if (fileName.isEmpty())
return false;
QFile file(fileName);
if (!file.open(QFile::WriteOnly | QFile::Text)) {
QMessageBox::critical(this, tr("Application"),
tr("Unable to open file %1 for writing :\n%2.")
.arg(fileName)
.arg(file.errorString()));
return false;
}
QTextStream out(&file);
#ifndef QT_NO_CURSOR
QApplication::setOverrideCursor(Qt::WaitCursor);
#endif
out << "Project name : " << d->projectName << "\n";
out << "Date : " << d->calendar->selectedDate().toString() << "\n";
out << "Progress : " << d->progressComboBox->currentText() << "\n";
out << "Duration : " << d->hoursWorkedLineEdit->text() << "\n\n";
out << "Description : " << d->textEdit->toPlainText();
#ifndef QT_NO_CURSOR
QApplication::restoreOverrideCursor();
#endif
return true;
}
\endcode
The \bold {startTimeLog()} slot is used by the \bold {Start Timer} button to start the timer.
\code
void LoggerModeWidget::startTimeLog()
{
d->totalTime = 0;
d->timer->start(1000);
}
\endcode
The \bold {endTimeLog()} slot is used by the \bold (Pause Timer } button to pause and resume the timer.
\code
void LoggerModeWidget::endTimeLog()
{
if(d->stopTimerButton->isChecked())
{
d->stopTimerButton->setText("Continue Timer");
d->timer->stop();
}
else
{
d->stopTimerButton->setText("Pause Timer");
d->timer->start(1000);
}
}
\endcode
The \bold {updateTime()} slot is used to update the time.
\code
void LoggerModeWidget::updateTime()
{
d->totalTime++;
QTime time(0,0,0);
time = time.addSecs(d->totalTime);
d->hoursWorkedLineEdit->setText(time.toString());
}
\endcode
\section1 13.4 Testing the final LoggerMode plugin.
\section2 Step 1. A "LoggerMode" mode selector can be seen int the Qt Creator.
\inlineimage qtc-loggermode-13.png
\section2 Step 2. A LoggerMode widget opens with options to "Add Projects"
\inlineimage qtc-loggerpage-13.png
\section2 Step 3. The "Add Project" button adds a project to the "Current Project list and opens the the "LoggerModeWidget"
\inlineimage qtc-loggermodewidget-13.png
*/