/*! \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 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 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 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/qtcreator_logo_32.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 LoggerMode::context() const { return QList(); } \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 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 */